// wrapper.beh -- Wrapper handling. // $Id: wrapper.beh,v 1.5 2000/10/13 22:02:54 dougo Exp $ // Generating calls to wrappers: TraversalParms { String callBefores(Glob glob, String indent) (@ return callWrappers(WrapperKind.before, glob, indent, ""); @) String callArounds(Glob glob, String indent, ClassName clname, TraversalMethodName mname, String args) (@ return callWrappers(WrapperKind.around, glob, indent, Around.makeContinuation(clname, mname, glob, args)); @) String callAfters(Glob glob, String indent) (@ return callWrappers(WrapperKind.after, glob, indent, ""); @) String callWrappers(WrapperKind kind, Glob glob, String indent, String cont) = allVisitorNames { init (@ return_val = ""; @) (@ ClassName visclname; @) 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 { ClassDef where = def.getWrapperDefiner(kind, glob); if (where != null) { return_val += indent + "((" + where.get_classname() + ") " + host + ")." + kind + glob.methodSuffix() + "(" + cont + glob.methodArgs() + ");\n"; } } @) } } ClassDef { // Johan: This is where we make it possible to inherit wrappers from // super visitors. We could (should) do this when setting up the // wrapper dicts, but that would require processing classdefs in a // certain order to get it right. due to when this is performed, // that is tricky. So we do it now, and accept the performance // penalty. ClassDef getWrapperDefiner(WrapperKind kind, Glob glob) {{ if (hasWrapper(kind,glob)) return this; else { // if this class doesn't have it ask the parent ClassDef d = get_superclass_def(); return d == null ? null : d.getWrapperDefiner(kind,glob); } // we might be tempted to buffer the parent information in this // wrapperdict, but if the classmethods is still shared between // classes, not a good idea. (I'm not 100% on when that is copied). }} private 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 { /** Build tables of visitors & wrappers to optimize wrapper lookup. */ 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"; @) } } // Generating code for wrappers: HostSpec { void generateWrapperCode(WrapperKind kind, Text code, boolean is_aspect) 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() + ") " + (is_aspect ? Text.begin : "{") + code + (is_aspect ? Text.end : "}")); @) } } // Around method stuff. 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 + " {\n" // 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 + "} .")); @) }