001: // Copyright (c) 2001, 2003 Per M.A. Bothner and Brainfood Inc.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.kawa.xml;
005:
006: import gnu.bytecode.*;
007: import gnu.mapping.*;
008: import gnu.expr.*;
009: import gnu.xml.*;
010: import gnu.lists.*;
011:
012: public abstract class NodeConstructor extends MethodProc implements
013: Inlineable {
014: public abstract void compileToNode(ApplyExp exp, Compilation comp,
015: ConsumerTarget target);
016:
017: public static XMLFilter pushNodeConsumer(Consumer out) {
018: if (out instanceof XMLFilter)
019: return (XMLFilter) out;
020: else
021: return new XMLFilter(new NodeTree());
022: }
023:
024: public static void popNodeConsumer(Consumer saved, Consumer current) {
025: if (saved != current)
026: saved
027: .writeObject(current instanceof XMLFilter ? (Object) KNode
028: .make((NodeTree) ((XMLFilter) current).out)
029: : (Object) current);
030: }
031:
032: public static XMLFilter pushNodeContext(CallContext ctx) {
033: Consumer out = ctx.consumer;
034: if (out instanceof XMLFilter)
035: return (XMLFilter) out;
036: else {
037: XMLFilter filter = new XMLFilter(new NodeTree());
038: ctx.consumer = filter;
039: return filter;
040: }
041: }
042:
043: public static void popNodeContext(Consumer saved, CallContext ctx) {
044: Object current = ctx.consumer;
045: if (saved != current) {
046: if (current instanceof XMLFilter)
047: current = KNode
048: .make((NodeTree) ((XMLFilter) current).out);
049: saved.writeObject(current);
050: ctx.consumer = saved;
051: }
052: }
053:
054: public static void compileChild(Expression arg, Compilation comp,
055: ConsumerTarget target) {
056: if (arg instanceof ApplyExp) {
057: ApplyExp app = (ApplyExp) arg;
058: Expression func = app.getFunction();
059: if (func instanceof QuoteExp) {
060: Object proc = ((QuoteExp) func).getValue();
061: if (proc instanceof NodeConstructor) {
062: ((NodeConstructor) proc).compileToNode(app, comp,
063: target);
064: return;
065: }
066: }
067: }
068: arg.compileWithPosition(comp, target);
069: }
070:
071: /** Compile an expression using a fresh NodeTree.
072: * Compare with ConsumerTarget.compileUsingConsumer, but creates a NodeTree.
073: */
074: public static void compileUsingNodeTree(Expression exp,
075: Compilation comp, Target target) {
076: Method makeMethod = typeNodeConstructor.getDeclaredMethod(
077: "makeNode", 0);
078: Method makeKNodeMethod = typeNodeConstructor.getDeclaredMethod(
079: "finishNode", 1);
080: ConsumerTarget.compileUsingConsumer(exp, comp, target,
081: makeMethod, makeKNodeMethod);
082: }
083:
084: public static XMLFilter makeNode() {
085: return new XMLFilter(new NodeTree());
086: }
087:
088: public static KNode finishNode(XMLFilter filter) {
089: return KNode.make((NodeTree) filter.out);
090: }
091:
092: public void compile(ApplyExp exp, Compilation comp, Target target) {
093: if (target instanceof IgnoreTarget)
094: ApplyExp.compile(exp, comp, target);
095: else if (!(target instanceof ConsumerTarget))
096: compileUsingNodeTree(exp, comp, target);
097: else {
098: ConsumerTarget ctarget = (ConsumerTarget) target;
099: Variable cvar = ctarget.getConsumerVariable();
100: Type ctype = cvar.getType();
101: if (ctype.isSubtype(typeXMLFilter))
102: compileToNode(exp, comp, ctarget);
103: else {
104: Expression[] args = exp.getArgs();
105: int nargs = args.length;
106: CodeAttr code = comp.getCode();
107: Scope scope = code.pushScope();
108: Variable saved = scope.addVariable(code,
109: Compilation.typeConsumer, null);
110: code.emitLoad(cvar);
111: code.emitStore(saved);
112: if (ctarget.isContextTarget()) {
113: comp.loadCallContext();
114: code.emitInvokeStatic(pushNodeContextMethod);
115: } else {
116: code.emitLoad(cvar);
117: code.emitInvokeStatic(pushNodeConsumerMethod);
118: }
119: code.emitStore(cvar);
120: code.emitTryStart(true, Type.void_type);
121: Type saveType = cvar.getType();
122: // For slightly improved code generation. We can potentially use
123: // the faster invokevirtual rather than invokeinterface.
124: cvar.setType(typeXMLFilter);
125: compileToNode(exp, comp, ctarget);
126: cvar.setType(saveType);
127: code.emitTryEnd();
128: code.emitFinallyStart();
129: code.emitLoad(saved);
130: if (ctarget.isContextTarget()) {
131: comp.loadCallContext();
132: code.emitInvokeStatic(popNodeContextMethod);
133: } else {
134: code.emitLoad(cvar);
135: code.emitInvokeStatic(popNodeConsumerMethod);
136: }
137: code.emitLoad(saved);
138: code.emitStore(cvar);
139: code.emitFinallyEnd();
140: code.emitTryCatchEnd();
141: code.popScope();
142: }
143: }
144: }
145:
146: public Type getReturnType(Expression[] args) {
147: return Compilation.typeObject;
148: }
149:
150: static final ClassType typeXMLFilter = ClassType
151: .make("gnu.xml.XMLFilter");
152: static final ClassType typeKNode = ClassType
153: .make("gnu.kawa.xml.KNode");
154: static final ClassType typeNodeConstructor = ClassType
155: .make("gnu.kawa.xml.NodeConstructor");
156: static final Method pushNodeContextMethod = typeNodeConstructor
157: .getDeclaredMethod("pushNodeContext", 1);
158: static final Method popNodeContextMethod = typeNodeConstructor
159: .getDeclaredMethod("popNodeContext", 2);
160: static final Method pushNodeConsumerMethod = typeNodeConstructor
161: .getDeclaredMethod("pushNodeConsumer", 1);
162: static final Method popNodeConsumerMethod = typeNodeConstructor
163: .getDeclaredMethod("popNodeConsumer", 2);
164: }
|