Package org.antlr.v4.codegen

Source Code of org.antlr.v4.codegen.OutputModelWalker

/*
* [The "BSD license"]
*  Copyright (c) 2012 Terence Parr
*  Copyright (c) 2012 Sam Harwell
*  All rights reserved.
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*
*  1. Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*  2. Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*  3. The name of the author may not be used to endorse or promote products
*     derived from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
*  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
*  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
*  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
*  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
*  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
*  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
*  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.antlr.v4.codegen;

import org.antlr.v4.Tool;
import org.antlr.v4.codegen.model.ModelElement;
import org.antlr.v4.codegen.model.OutputModelObject;
import org.antlr.v4.tool.ErrorType;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
import org.stringtemplate.v4.compiler.FormalArgument;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

/** Convert an output model tree to template hierarchy by walking
*  the output model. Each output model object has a corresponding template
*  of the same name.  An output model object can have nested objects.
*  We identify those nested objects by the list of arguments in the template
*  definition. For example, here is the definition of the parser template:
*
*  Parser(parser, scopes, funcs) ::= <<...>>
*
*  The first template argument is always the output model object from which
*  this walker will create the template. Any other arguments identify
*  the field names within the output model object of nested model objects.
*  So, in this case, template Parser is saying that output model object
*  Parser has two fields the walker should chase called a scopes and funcs.
*
*  This simple mechanism means we don't have to include code in every
*  output model object that says how to create the corresponding template.
*/
public class OutputModelWalker {
  Tool tool;
  STGroup templates;

  public OutputModelWalker(Tool tool,
               STGroup templates)
  {
    this.tool = tool;
    this.templates = templates;
  }

  public ST walk(OutputModelObject omo) {
    // CREATE TEMPLATE FOR THIS OUTPUT OBJECT
    Class<? extends OutputModelObject> cl = omo.getClass();
    String templateName = cl.getSimpleName();
    if ( templateName == null ) {
      tool.errMgr.toolError(ErrorType.NO_MODEL_TO_TEMPLATE_MAPPING, cl.getSimpleName());
      return new ST("["+templateName+" invalid]");
    }
    ST st = templates.getInstanceOf(templateName);
    if ( st == null ) {
      tool.errMgr.toolError(ErrorType.CODE_GEN_TEMPLATES_INCOMPLETE, templateName);
      return new ST("["+templateName+" invalid]");
    }
    if ( st.impl.formalArguments == null ) {
      tool.errMgr.toolError(ErrorType.CODE_TEMPLATE_ARG_ISSUE, templateName, "<none>");
      return st;
    }

    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();
    String modelArgName = arg_it.next(); // ordered so this is first arg
    st.add(modelArgName, omo);

    // COMPUTE STs FOR EACH NESTED MODEL OBJECT MARKED WITH @ModelElement AND MAKE ST ATTRIBUTE
    Set<String> usedFieldNames = new HashSet<String>();
    Field fields[] = cl.getFields();
    for (Field fi : fields) {
      ModelElement annotation = fi.getAnnotation(ModelElement.class);
      if (annotation == null) {
        continue;
      }

      String fieldName = fi.getName();

      if (!usedFieldNames.add(fieldName)) {
        tool.errMgr.toolError(ErrorType.INTERNAL_ERROR, "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 ) {
          tool.errMgr.toolError(ErrorType.INTERNAL_ERROR, "not recognized nested model element: "+fieldName);
        }
      }
      catch (IllegalAccessException iae) {
        tool.errMgr.toolError(ErrorType.CODE_TEMPLATE_ARG_ISSUE, templateName, fieldName);
      }
    }
    //st.impl.dump();
    return st;
  }

}
TOP

Related Classes of org.antlr.v4.codegen.OutputModelWalker

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.