expand.beh.html

Program{
	private void expandStaticTraversals()bypassing VisitorSpec via TraversalDef to-stop{ TraversalName, TraversalParms, StrategyGraph, PathDirective, StrategyVariable, CompoundStrategy }{
		(@ ClassGraph cg; @)
		before ClassGraph (@ cg = host; @)
		(@ ClassDef source; ClassName clname; @)
		before ClassDef (@ source = host; clname = host.get_classname(); @)
		(@ TraversalName name; @)
		before TraversalName (@ name = host; @)
		(@ TraversalParms parms; @)
		before TraversalParms (@ parms = host; @)
		(@ StrategyGraph sg; @)
		before StrategyExpression (@ sg = host.toGraph(clname); @)
		after TraversalDef (@
      Program.log.print("  Marking " + name + "...");
      Program.log.flush();
      if (!cg.markSubgraph(sg)) return;
      Program.log.println("  expanding...");
      TraversalMethodName mname = new TraversalMethodName(name);
      String args = parms.collectVisitorNames();
      boolean use_nodeset = sg.size() > 1;
      String start_call = "  public void " + name + parms + " {\n";
      if (use_nodeset) {
	start_call +="    java.util.BitSet startSet = new java.util.BitSet();\n";
	start_call += sg.startSetCode("    ", "startSet", clname);
      }
      start_call += "    " + mname + "(";
      if (use_nodeset) {
	start_call += "startSet";
	if (!args.equals("")) start_call += ", ";
      }
      start_call += args + ");\n  }\n";
      source.addMethod(start_call);

      Program.prog.makeTraversalMethods(mname, parms, args, use_nodeset);
    @)
	}
}

TraversalParms{
	String collectVisitorNames()=allVisitorNames{
		(@ boolean first = true; @)
		init (@ return_val = ""; @)
		before VisitorName (@
      if (first) first = false; else return_val += ", ";
      return_val += host;
    @)
	}
}

Program{
	void makeTraversalMethods(TraversalMethodName name, TraversalParms parms, String args, boolean use_nodeset)=allEdges{
		(@ TraversalParms revparms; String args_with_nodeset; @)
		before Program (@
      revparms = parms.reverse();
      args_with_nodeset = (use_nodeset ? "nodes, " : "") + args;
    @)
		(@ ClassDef def; ClassName source; boolean opt; String edge_calls; @)
		around ClassDef (@
      if (host.isInterface()) return;
      def = host;
      ClassDef parent = host.get_superclass_def();
      if (parent != null && !parent.is_in_trav()) parent = null;
      if (host.is_in_trav()) {
	/*
	  let v be the first visitor
	   outer:
	    If v has an around method for this class,
	      call/cc
	    else
	      call befores on v for this class & its parents
	      if v is last visitor,
		for each edge e,
		 inner:
		  call befores on v for e
		  if v is last visitor,
		    traverse e
		  else
		    call inner: with next visitor
		  call afters on v for e
	      else
		call outer: with next visitor
	      call afters on v for this class & its parents
	*/
	source = host.get_classname();
	Glob glob = new ClassGlob(source);
	// Make the before method caller.
	String bef_super_call = "";
	if (parent != null) {
	  bef_super_call = "    super." + name.beforeName() 
					+ "(" + args + ");\n";
	}
	host.addBeforeMethod(name, parms,
			     bef_super_call + parms.callBefores(glob, false));

	// Make the after method caller.
	String aft_super_call = "";
	if (parent != null) {
	  aft_super_call = "    super." + name.afterName()
					+ "(" + args + ");\n";
	}
	host.addAfterMethod(name, parms,
			    revparms.callAfters(glob, false) + aft_super_call);

	edge_calls = "";
	subtraversal.apply();
	String body = host.maybeAddAroundMethod(name, parms, glob, edge_calls,
			    parms.callArounds(glob, false, source, name,
					      args_with_nodeset),
						use_nodeset);
	if (host.isConstructionClass()) {
	  body = "    " + name.beforeName() + "(" + args +");\n"
	       + body
	       + "    " + name.afterName()  + "(" + args +");\n";
	}
	if (use_nodeset)
	  body = host.get_tg().intercopyEdgesCode("    ", "nodes") + body;
	host.addTraversalMethod(name, parms, body, use_nodeset);
      } else if (parent != null) {
	// The class isn't in the traversal, but its parent is; generate
	// an empty traversal method, so that the parent's method
	// doesn't get inherited.
	host.addTraversalMethod(name, parms, "", use_nodeset);
      }
    @)
		before OptionalPart (@ opt = true; @)
		before Part (@
      if (host.is_in_trav()) {
	ClassName classname = host.get_classname();
	PartName partname = host.get_partname();
	if (host.isDerived()) {
	  edge_calls += "    " + classname + " " + partname
		      + " = get_" + partname + "();\n";
	}
	if (opt) edge_calls += "    if (" + partname + " != null) {\n";
	Glob glob = new PartGlob(source, partname, classname);
	edge_calls += parms.callBefores(glob, opt);
	if (!host.isTerminal()) {
	  edge_calls += def.maybeAddAroundMethod(name, parms, glob,
			  host.callTraversalMethod(name, args, use_nodeset),
			  parms.callArounds(glob, opt, source, name,
					    args_with_nodeset),
						 use_nodeset);
	}
	edge_calls += revparms.callAfters(glob, opt);
	if (opt) edge_calls += "    }\n";
      }
    @)
		after OptionalPart (@ opt = false; @)
		before Superclass (@
      if (host.is_in_trav() &&
	  Program.prog.definesClass(host.get_classname())) {
	Glob glob = new SuperclassGlob(source, host.get_classname());
	edge_calls += parms.callBefores(glob, false)
		   +  def.maybeAddAroundMethod(name, parms, glob,
			    host.callTraversalMethod(name, args, use_nodeset),
			    parms.callArounds(glob, false, source, name,
					      args_with_nodeset),
					       use_nodeset)
		   +  revparms.callAfters(glob, false);
      }
    @)
	}
}

TraversalMethodName{
	(@
    static int trav = 0;
    TraversalMethodName(TraversalName name) { 
      methodname = MethodName.parse(name + "_trv" + (trav++));
    }
  @)
	protected String withSuffix(String suffix)(@
      return methodname + "_" + suffix;
  @)
	String beforeName()(@ return withSuffix("bef"); @)
	String afterName()(@ return withSuffix("aft"); @)
	String aroundName(Glob glob, ClassName clname)(@
    return withSuffix("aro_" + clname + glob.methodSuffix());
  @)
}

ClassDef{
	private String traversalMethodSignature(String name, TraversalParms parms, boolean use_nodeset)(@
    String signature = "  void " + name + "(";
    if (use_nodeset) signature += "java.util.BitSet nodes";
    Visitor_Commalist vis = parms.get_visitors();
    if (vis != null) {
      if (use_nodeset) signature += ", ";
      signature += vis;
    }
    signature += ")";
    return signature;
  @)
	void addTraversalMethod(TraversalMethodName name, TraversalParms parms, String body, boolean use_nodeset)(@
    String sig = traversalMethodSignature(name.toString(), parms, use_nodeset);
    addMethod(sig, body);
  @)
	void addBeforeMethod(TraversalMethodName name, TraversalParms parms, String body)(@
    addMethod("  void " + name.beforeName() + parms, body);
  @)
	void addAfterMethod(TraversalMethodName name, TraversalParms parms, String body)(@
    addMethod("  void " + name.afterName() + parms, body);
  @)
	void addAroundMethod(TraversalMethodName name, TraversalParms parms, Glob glob, String body, boolean use_nodeset)(@
    ClassName clname = get_classname();
    String mname = name.aroundName(glob, clname);
    String sig = traversalMethodSignature(mname, parms, use_nodeset);
    addMethod(sig, body);
    String s = "";
    s +="  static java.lang.reflect.Method " + mname + ";\n"
      + "  static {\n"
      + "    try {\n"
      + "      " + mname + " =\n"
      + "        " + clname + ".class.getDeclaredMethod(\"" + mname + "\",\n"
      + "          new Class[] { ";
    Enumeration e = parms.elements();
    boolean first = true;
    if (use_nodeset) {
      s += "java.util.BitSet.class";
      first = false;
    }
    while (e.hasMoreElements()) {
      Visitor vis = (Visitor) e.nextElement();
      if (first) first = false; else s += ", ";
      s += vis.get_classname() + ".class";
    }
    s += " });\n";
    s += "    } catch (NoSuchMethodException e) {\n";
    s += "      throw new RuntimeException(e.toString());\n";
    s += "    }\n";
    s += "  }\n";
    addMethod(s);
  @)
	String maybeAddAroundMethod(TraversalMethodName name, TraversalParms parms, Glob glob, String edge_call, String around_call, boolean use_nodeset)(@
    if (around_call.equals("")) return edge_call;
    // What if more than one method??
    addAroundMethod(name, parms, glob, edge_call, use_nodeset);
    return around_call;
  @)
}

Part{
	(@
    String callTraversalMethod(TraversalMethodName name, String args,
			       boolean use_nodeset) {
      if (!use_nodeset)
	return "    " + get_partname() + "." + name + "(" + args + ");\n";
      String call = 
	  "    { java.util.BitSet newnodes = new java.util.BitSet();\n";
      call += get_tg().maskCode("      ", "nodes", "newnodes");
      call += "      if (!newnodes.equals(new java.util.BitSet()))\n";
      call += "        " + get_partname() + "." + name + "(newnodes";
      if (!args.equals("")) call += ", " + args;
      call += "); }\n";
      return call;
    }
  @)
}

Superclass{
	(@
    String callTraversalMethod(TraversalMethodName name, String args,
			       boolean use_nodeset) {
      if (!use_nodeset)
	return "    super." + name + "(" + args + ");\n";
      String call =
	      "    { java.util.BitSet newnodes = new java.util.BitSet();\n";
      call += get_tg().maskCode("      ", "nodes", "newnodes");
      call += "      if (!newnodes.equals(new java.util.BitSet()))\n";
      call += "        super." + name + "(newnodes";
      if (!args.equals("")) call += ", " + args;
      call += "); }\n";
      return call;
    }
  @)
}