core:
import edu.neu.ccs.demeter.dj.*;
import edu.neu.ccs.demeter.aplib.*;
import java.util.*;

import edu.neu.ccs.demeter.*;
add: class SemanticChecker {
  public constructor SemanticChecker() {{
    super();
  }}
  public static SemanticChecker parse(java.io.Reader in)
    throws ParseException
  {{ return new Parser(in)._SemanticChecker(); }}
  public static SemanticChecker parse(java.io.InputStream in)
    throws ParseException
  {{ return new Parser(in)._SemanticChecker(); }}
  public static SemanticChecker parse(String s) {{
    try { return parse(new java.io.StringReader(s)); }
    catch (ParseException e) {
      throw new RuntimeException(e.toString());
    }
  }}
{{
    // the runtime class graph
    ClassGraph runtimeCg;
    // the class graph defined by the input class dictionary
    edu.neu.ccs.demeter.aplib.cd.ClassGraph inputCg;
    // a pointer to the traversal XAspects component
    TraversalAspect ta;
  }}
  public void generate(ClassDictionaryAspect cda, TraversalAspect travA) {{
    // create the runtime class graph
    runtimeCg = new ClassGraph(true, false);

    // create the class graph for the input class dictionary
    inputCg = ClassGraph.fromString(cda.get_textcd().get_text().toString());
    inputCg.normalize();

    // assign the pointer to the provided traversal aspect component
    ta = travA;
  }}
  public void check() {{
    // make some Traversal XAspects specific checks
    // i.e., make sure that "nodes" and regular expression declarations
    // utilize other declarations that are defined
    check_trav_nodesAndRegExp();

    // check in all places for undefined classes
    // i.e., check used classes in class dictionary, strategy expressions,
    // and class list declarations
    checkForUndefinedClasses();

    // verify that strategies represent legal paths
    checkTraversalPaths();
  }}
  private void check_trav_nodesAndRegExp() {{
    // check that all used Strategy names in "nodes" node set decls are defined
    List usedNames = runtimeCg.gather(ta, "from TraversalAspect via StrategyName to" + Main.FIdent);
    List defNames = runtimeCg.gather(ta, "from TraversalAspect via StrategyDeclName to" + Main.FIdent);
    subset_test(usedNames, defNames);    

    // check that regular expressions reference defined node sets
    List defNodeSetDecls = runtimeCg.gather(ta, "from TraversalAspect via NodesetDeclName to" + Main.FIdent);
    List usedNodeSetDecls = runtimeCg.gather(ta, "from TraversalAspect via NodesetIdent to" + Main.FIdent);    
    subset_test(usedNodeSetDecls, defNodeSetDecls);
  }}
  private void checkForUndefinedClasses() {{
    // get a list of all used classes in input cd, and make sure each used class
    // is defined by the cd
    java.util.Collection c = inputCg.getNodes();
    checkDefinesClass(c.iterator());

    // check that all classes used in strategy expressions are defined
    List usedClassNames = runtimeCg.gather(ta, "from TraversalAspect via ClassName to" + Main.FIdent); 
    checkDefinesClass(usedClassNames.iterator());

    // check classes are all defined in class list node sets
    List usedClasses = runtimeCg.gather(ta, "from TraversalAspect via ClassListName to" + Main.FIdent);
    checkDefinesClass(usedClasses.iterator());
  }}
  private void subset_test(List used, List defined) {{
    ListIterator usedIterator = used.listIterator();
    while (usedIterator.hasNext()) {
      Ident next = (Ident) usedIterator.next();
      if (!defined.contains(next)) {
        System.out.println(next.toString() + " undefined.");
      }
    }
  }}
  private void checkTraversalPaths() {{
    List test = runtimeCg.gather(ta, "from TraversalAspect to Strategy");
    Strategy strat = (Strategy) test.get(0);

    // We have been unable to implement this portion as of yet.
    // It seems the best way would be to create a Traversal object
    // using the Strategy and parsed class graph, and catch the
    // possible exceptions (TraversalException, ParseException),
    // but we have been unable to do this due to incompatibilities
    // between our Strategy defined in our cd, the Traversal object
    // and our parsed class graph.

    /* The following code is provided as an example of this semantic
     * checking process, if the Strategies were stored in String format:
     *
     * try {
     *   // create a strategy from the string, 
     *   // syntax errors result in StrategyParseException
     *   Strategy strategy = new Strategy(srategyAsString);
     * 
     *   // compute traversal, bad path results in TraversalException
     *   Traversal.compute(strategy, inputCg);
     * } catch (StrategyParseException spe) {
     *     // invalid strategy syntax
     *     System.out.println("StrategyParseException: " + spe.getMessage());
     * } catch (TraversalException te) {
     *     // bad traversal path
     *    System.out.println("TraversalException: " + te.getMessage());
     * } catch (Exception e) {
     *	  System.out.println(e.getMessage());
     * }
     */
  
  }}
  private void checkDefinesClass(Iterator iter) {{
    while (iter.hasNext()) {
      Object next = iter.next();
      if (!inputCg.definesClass(next.toString())) {      
        System.out.println(next.toString() + " undefined.");
      }
    }  
  }}
{{  void universal_trv0_bef(UniversalVisitor _v_) {
    ((UniversalVisitor) _v_).before(this);
  }
}}
{{  void universal_trv0_aft(UniversalVisitor _v_) {
    ((UniversalVisitor) _v_).after(this);
  }
}}
{{  void universal_trv0(UniversalVisitor _v_) {
    universal_trv0_bef(_v_);
    universal_trv0_aft(_v_);
  }
}}
}