wrapper.beh.html

TraversalParms{
	String callBefores(Glob glob, boolean indent)(@
    return callWrappers(WrapperKind.before, glob, indent, "");
  @)
	String callArounds(Glob glob, boolean indent, ClassName clname, TraversalMethodName mname, String args)(@
    return callWrappers(WrapperKind.around, glob, indent,
			Around.makeContinuation(clname, mname, glob, args));
  @)
	String callAfters(Glob glob, boolean indent)(@
    return callWrappers(WrapperKind.after, glob, indent, "");
  @)
	String callWrappers(WrapperKind kind, Glob glob, boolean indent, String cont)allVisitorNames(WrapperCallGenerator);
}

WrapperCallGenerator{
	init (@ return_val = ""; @)
	before Visitor (@ visclname = host.get_classname(); @)
	before VisitorName (@
    ClassDef def = Program.prog.findClassDef(visclname);
    if (def == null) {
      System.err.println("Error: no such visitor class \"" + visclname + "\"");
    } else if (def.hasWrapper(kind, glob)) {
      return_val += (indent ? "      " : "    ")
		 +  host + "." + kind + glob.methodSuffix()
		 +  "(" + cont + glob.methodArgs() + ");\n";
    }
  @)
}

ClassDef{
	(@
    boolean hasWrapper(WrapperKind kind, Glob glob) {
      Hashtable wrapperdict = get_wrapperdict();
      if (wrapperdict == null) return false;
      HostSet hostset = (HostSet) wrapperdict.get(kind);
      if (hostset == null) return false;
      return hostset.contains(glob);
    }
    Hashtable get_wrapperdict() {
      return classmethods.get_wrapperdict();
    }
  @)
}

Program{
	void buildVisitorTables()bypassing VisitorSpec via Wrapper to Glob{
		(@ Hashtable wrapperdict; @)
		before ClassMethods (@ wrapperdict = null; @)
		(@ HostSet hostset; @)
		before Wrapper (@
    WrapperKind kind = host.get_kind();
    // wrapperdict is a table of tables, one per wrapper kind.
    if (wrapperdict == null) wrapperdict = new Hashtable();
    // hostset is a set of hosts that have a wrapper of this kind.
    hostset = (HostSet) wrapperdict.get(kind);
    if (hostset == null) {
      hostset = new HostSet();
      wrapperdict.put(kind, hostset);
    }
  @)
		before Glob (@ hostset.add(host); @)
		after ClassMethods (@ host.set_wrapperdict(wrapperdict); @)
	}
}

HostSet{
	void add(Glob host)(@
    if (host.isExact())
      addExactHost(host);
    else if (host.isPartNameGlob())
      addPartName(host.get_partname());
    else
      addGlob(host);
  @)
	void addExactHost(Glob host)(@
    if (exactHosts == null) exactHosts = new Hashtable();
    exactHosts.put(host, host);
  @)
	void addPartName(PartName name)(@
    if (partnames == null) partnames = new Hashtable();
    partnames.put(name, name);
  @)
	void addGlob(Glob glob)(@
    if (globs == null) globs = new GlobSet();
    globs.addElement(glob);
  @)
	boolean contains(Glob glob)(@
    if (exactHosts != null && exactHosts.get(glob) != null) return true;
    if (partnames != null && glob instanceof PartGlob &&
	partnames.get(glob.get_partname()) != null) return true;
    if (globs != null && globs.match(glob)) return true;
    return false;
  @)
}

WrapperKind{
	(@
    final static Before before = new Before();
    final static Around around = new Around();
    final static After after = new After();
  @)
}

Glob{
	String methodSuffix()to{ ClassGlob, PartName, SubclassGlob, SuperclassGlob }{
		before ClassGlob (@ return_val = ""; @)
		before PartGlob (@ return_val = "_"; @)
		before PartName (@ return_val += host; @)
		before SubclassGlob (@ return_val = "_sub"; @)
		before SuperclassGlob (@ return_val = "_sup"; @)
	}
	String methodParms()to{ ClassName, AnyClass, AnyPart }{
		init (@ return_val = ""; @)
		before ClassName (@ return_val += host; @)
		before AnyClass (@ return_val += "Object"; @)
		after ClassGlob (@ return_val += " host"; @)
		after SourceGlob (@ return_val += " source, "; @)
		before AnyPart (@ return_val += "String edge, "; @)
		after DestGlob (@ return_val += " dest"; @)
	}
	String methodArgs()to{ ClassGlob, PartName, SubclassGlob, SuperclassGlob }{
		before ClassGlob (@ return_val = "this"; @)
		before PartGlob (@ return_val = "this, "; @)
		before PartName (@ return_val += host; @)
		before{ SubclassGlob, SuperclassGlob }(@ return_val = "this, this"; @)
	}
}

HostSpec{
	void generateWrapperCode(WrapperKind kind, Text code)to{ ClassNameExact, AnyClass, PartNameExact, AnyPart }{
		before Glob (@
      Program.out.print("  public void " + kind + host.methodSuffix() + "(");
      if (kind instanceof Around)
	Program.out.print(Around.absname + " subtraversal, ");
      Program.out.println(host.methodParms() + ") {" + code + "}");
    @)
	}
}

Around{
	(@ static final ClassName classname = ClassName.parse("__Subtraversal"); @)
	(@ static final ClassName absname = ClassName.parse("AroundContinuation"); @)
	static String makeContinuation(ClassName clname, TraversalMethodName name, Glob glob, String args)(@
    return "new " + Around.classname
	    + "(" + name.aroundName(glob, clname) + ", this, "
		  + "new Object[] { " + args + " }), ";
  @)
}

Program{
	private void addSubtraversalClass()(@
    addClassDef(ClassDef.parse(
  "*notparsed* " + Around.classname + " = *extends* " + Around.absname + " {"
				   // get rid of this after converting TAO
+ Text.begin
+ "  java.lang.reflect.Method method;\n"
+ "  Object object;\n"
+ "  Object args[];\n"
+ "  "+Around.classname+"(java.lang.reflect.Method m, Object o, Object a[])\n"
+ "    { method = m; object = o; args = a; }\n"
+ "  public void apply() {\n"
+ "    try {\n"
+ "      method.invoke(object, args);\n"
+ "    } catch (IllegalAccessException e) {\n"
+ "      throw new RuntimeException(\"Internal error: \" + e);\n"
+ "    } catch (IllegalArgumentException e) {\n"
+ "      throw new RuntimeException(\"Internal error: \" + e);\n"
+ "    } catch (java.lang.reflect.InvocationTargetException e) {\n"
+ "      Throwable t = e.getTargetException();\n"
+ "      java.io.StringWriter w = new java.io.StringWriter();\n"
+ "      t.printStackTrace(new java.io.PrintWriter(w));\n"
/* An attempt at extracting useful information from the stack trace,
 * without being redundant.  Didn't work too well.
+ "      String s = w.toString();\n"
+ "      int i = s.indexOf(\"\\n\");\n"
+ "      s = s.substring(0, s.indexOf(\"\\n\", i+1));\n"
+ "      throw new RuntimeException(\""+Around.classname+" got exception:\"\n"
+ "                                 + \"\\n\" + t + \"\\n\" + s);\n"
 */
+ "      throw new RuntimeException(\""+Around.classname+" got exception:\"\n"
+ "                                 + \"\\n\" + t + \"\\n\" + w);\n"
+ "    }\n"
+ "  }\n"
+ Text.end
+ "} ."));
  @)
}