Search in sources :

Example 1 with ModelElement

use of us.parr.bookish.model.ModelElement in project bookish by parrt.

the class ModelConverter method walk.

public ST walk(OutputModelObject omo) {
    if (omo == null)
        return null;
    // CREATE TEMPLATE FOR THIS OUTPUT OBJECT
    Class<? extends OutputModelObject> cl = omo.getClass();
    String templateName = cl.getSimpleName();
    if (templateName == null) {
        System.err.println("no model to template mapping for " + cl.getSimpleName());
        return new ST("[" + templateName + " invalid]");
    }
    ST st = templates.getInstanceOf(templateName);
    if (st == null) {
        System.err.println("no model to template mapping for " + cl.getSimpleName());
        return new ST("[" + templateName + " invalid]");
    }
    if (st.impl.formalArguments == null) {
        System.err.println("no formal arguments for " + templateName);
        return st;
    }
    // LinkedHashMap
    Map<String, FormalArgument> formalArgs = st.impl.formalArguments;
    // PASS IN OUTPUT MODEL OBJECT TO TEMPLATE AS FIRST ARG
    Set<String> argNames = formalArgs.keySet();
    Iterator<String> arg_it = argNames.iterator();
    // ordered so this is first arg
    String modelArgName = arg_it.next();
    st.add(modelArgName, omo);
    Field[] allAnnotatedFields = getAllAnnotatedFields(cl);
    List<Field> modelFields = new ArrayList<>();
    for (Field fi : allAnnotatedFields) {
        ModelElement annotation = fi.getAnnotation(ModelElement.class);
        if (annotation != null) {
            modelFields.add(fi);
        }
    }
    // Make sure all @ModelElement fields are public (ST won't see otherwise)
    for (Field fi : allAnnotatedFields) {
        ModelElement annotation = fi.getAnnotation(ModelElement.class);
        if (annotation != null && !Modifier.isPublic(fi.getModifiers())) {
            System.err.println("non-public @ModelElement in " + templateName + ": " + fi.getName());
        }
    }
    // Ensure that @ModelElement fields match up with the parameters
    {
        List<String> fieldNames = map(modelFields, Field::getName);
        Set<String> t = new HashSet<>(argNames);
        t.remove(modelArgName);
        if (!t.equals(new HashSet<>(fieldNames))) {
            System.err.println("mismatch in template " + templateName + " between arguments and @ModelElement fields: " + t + "!=" + fieldNames);
        }
    }
    // COMPUTE STs FOR EACH NESTED MODEL OBJECT MARKED WITH @ModelElement AND MAKE ST ATTRIBUTE
    Set<String> usedFieldNames = new HashSet<>();
    for (Field fi : modelFields) {
        ModelElement annotation = fi.getAnnotation(ModelElement.class);
        if (annotation == null) {
            continue;
        }
        String fieldName = fi.getName();
        if (!usedFieldNames.add(fieldName)) {
            System.err.println("Model object " + omo.getClass().getSimpleName() + " has multiple fields named '" + fieldName + "'");
            continue;
        }
        // Just don't set @ModelElement fields w/o formal arg in target ST
        if (formalArgs.get(fieldName) == null)
            continue;
        try {
            Object o = fi.get(omo);
            if (o instanceof OutputModelObject) {
                // SINGLE MODEL OBJECT?
                OutputModelObject nestedOmo = (OutputModelObject) o;
                ST nestedST = walk(nestedOmo);
                // System.out.println("set ModelElement "+fieldName+"="+nestedST+" in "+templateName);
                st.add(fieldName, nestedST);
            } else if (o instanceof Collection || o instanceof OutputModelObject[]) {
                // LIST OF MODEL OBJECTS?
                if (o instanceof OutputModelObject[]) {
                    o = Arrays.asList((OutputModelObject[]) o);
                }
                Collection<?> nestedOmos = (Collection<?>) o;
                for (Object nestedOmo : nestedOmos) {
                    if (nestedOmo == null)
                        continue;
                    ST nestedST = walk((OutputModelObject) nestedOmo);
                    // System.out.println("set ModelElement "+fieldName+"="+nestedST+" in "+templateName);
                    st.add(fieldName, nestedST);
                }
            } else if (o instanceof Map) {
                Map<?, ?> nestedOmoMap = (Map<?, ?>) o;
                Map<Object, ST> m = new LinkedHashMap<Object, ST>();
                for (Map.Entry<?, ?> entry : nestedOmoMap.entrySet()) {
                    ST nestedST = walk((OutputModelObject) entry.getValue());
                    // System.out.println("set ModelElement "+fieldName+"="+nestedST+" in "+templateName);
                    m.put(entry.getKey(), nestedST);
                }
                st.add(fieldName, m);
            } else if (o != null) {
                System.err.println("type of " + fieldName + "'s model element isn't recognized: " + o.getClass().getSimpleName());
            }
        } catch (IllegalAccessException iae) {
            System.err.printf("code generation template <%s> has missing, misnamed, or incomplete arg list; missing <%s>\n", templateName, fieldName);
        }
    }
    // st.impl.dump();
    return st;
}
Also used : OutputModelObject(us.parr.bookish.model.OutputModelObject) Set(java.util.Set) HashSet(java.util.HashSet) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) FormalArgument(org.stringtemplate.v4.compiler.FormalArgument) Field(java.lang.reflect.Field) ModelElement(us.parr.bookish.model.ModelElement) ArrayList(java.util.ArrayList) List(java.util.List) HashSet(java.util.HashSet) ST(org.stringtemplate.v4.ST) Collection(java.util.Collection) OutputModelObject(us.parr.bookish.model.OutputModelObject) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map)

Aggregations

Field (java.lang.reflect.Field)1 ArrayList (java.util.ArrayList)1 Collection (java.util.Collection)1 HashSet (java.util.HashSet)1 LinkedHashMap (java.util.LinkedHashMap)1 List (java.util.List)1 Map (java.util.Map)1 Set (java.util.Set)1 ST (org.stringtemplate.v4.ST)1 FormalArgument (org.stringtemplate.v4.compiler.FormalArgument)1 ModelElement (us.parr.bookish.model.ModelElement)1 OutputModelObject (us.parr.bookish.model.OutputModelObject)1