001: // Copyright (c) 2001, 2003, 2004 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.lists.*;
007: import gnu.mapping.*;
008: import gnu.bytecode.*;
009: import gnu.expr.*;
010: import gnu.xml.*;
011:
012: public class MakeElement extends NodeConstructor {
013: public static final MakeElement makeElement = new MakeElement();
014:
015: public int numArgs() {
016: return tag == null ? 0xFFFFF001 : 0xFFFFF000;
017: }
018:
019: /** Optional tag. If non-null, the element tag is this value,
020: * rather than the first parameter. */
021: public Object tag;
022:
023: public int copyNamespacesMode = XMLFilter.COPY_NAMESPACES_PRESERVE;
024:
025: private boolean handlingKeywordParameters;
026:
027: /** Should {@code KEYWORD: EXPRESSION} be mapped to an
028: * attribute constructor? */
029: public boolean isHandlingKeywordParameters() {
030: return handlingKeywordParameters;
031: }
032:
033: public void setHandlingKeywordParameters(boolean value) {
034: handlingKeywordParameters = value;
035: }
036:
037: NamespaceBinding namespaceNodes;
038:
039: public NamespaceBinding getNamespaceNodes() {
040: return namespaceNodes;
041: }
042:
043: public void setNamespaceNodes(NamespaceBinding bindings) {
044: namespaceNodes = bindings;
045: }
046:
047: public static Symbol getTagName(ApplyExp exp) {
048: Expression[] args = exp.getArgs();
049: if (args.length > 0) {
050: Expression arg0 = args[0];
051: if (arg0 instanceof QuoteExp) {
052: Object val = ((QuoteExp) arg0).getValue();
053: if (val instanceof Symbol)
054: return (Symbol) val;
055: }
056: }
057: return null;
058: }
059:
060: public static void startElement(Consumer out, Object qname,
061: int copyNamespacesMode, NamespaceBinding namespaceNodes) {
062: XName type;
063: if (qname instanceof Symbol)
064: type = new XName((Symbol) qname, namespaceNodes);
065: else
066: type = new XName(Symbol.make("", qname.toString(), ""),
067: namespaceNodes);
068: if (out instanceof XMLFilter)
069: ((XMLFilter) out).copyNamespacesMode = copyNamespacesMode;
070: out.startElement(type);
071: }
072:
073: public static void startElement(Consumer out, Object qname,
074: int copyNamespacesMode) {
075: Symbol type;
076: if (qname instanceof Symbol)
077: type = (Symbol) qname;
078: else
079: type = Symbol.make("", qname.toString(), "");
080: if (out instanceof XMLFilter)
081: ((XMLFilter) out).copyNamespacesMode = copyNamespacesMode;
082: out.startElement(type);
083: }
084:
085: public static void endElement(Consumer out, Object type/*FIXME:unused*/) {
086: out.endElement();
087: }
088:
089: public void apply(CallContext ctx) {
090: Consumer saved = ctx.consumer;
091: Consumer out = pushNodeContext(ctx);
092: try {
093: Object type = tag != null ? tag : ctx.getNextArg();
094: if (namespaceNodes != null)
095: startElement(out, type, copyNamespacesMode,
096: namespaceNodes);
097: else
098: startElement(out, type, copyNamespacesMode);
099: Object endMarker = Special.dfault;
100: for (;;) {
101: Object arg = ctx.getNextArg(endMarker);
102: if (arg == endMarker)
103: break;
104: if (arg instanceof Consumable)
105: ((Consumable) arg).consume(out);
106: else
107: ctx.writeValue(arg);
108: // Handling Keyword values is actually done by the Consumer.
109: if (isHandlingKeywordParameters())
110: out.endAttribute();
111: }
112: endElement(out, type);
113: } finally {
114: popNodeContext(saved, ctx);
115: }
116: }
117:
118: public void compileToNode(ApplyExp exp, Compilation comp,
119: ConsumerTarget target) {
120: Variable consumer = target.getConsumerVariable();
121: Expression[] args = exp.getArgs();
122: int nargs = args.length;
123: CodeAttr code = comp.getCode();
124: code.emitLoad(consumer);
125: code.emitDup();
126: int i;
127: if (tag == null) {
128: args[0].compile(comp, Target.pushObject);
129: i = 1;
130: } else {
131: comp.compileConstant(tag, Target.pushObject);
132: i = 0;
133: }
134: code.emitDup(1, 1); // dup_x1
135: // Stack: consumer, tagtype, consumer, tagtype
136: code.emitPushInt(copyNamespacesMode);
137: if (namespaceNodes != null) {
138: comp.compileConstant(namespaceNodes, Target.pushObject);
139: code.emitInvokeStatic(startElementMethod4);
140: } else
141: code.emitInvokeStatic(startElementMethod3);
142: for (; i < nargs; i++) {
143: compileChild(args[i], comp, target);
144: if (isHandlingKeywordParameters()) {
145: code.emitLoad(consumer);
146: code
147: .emitInvokeInterface(MakeAttribute.endAttributeMethod);
148: }
149: }
150: code.emitInvokeStatic(endElementMethod);
151: }
152:
153: public Type getReturnType(Expression[] args) {
154: return Compilation.typeObject;
155: }
156:
157: static final ClassType typeMakeElement = ClassType
158: .make("gnu.kawa.xml.MakeElement");
159: static final Method startElementMethod3 = typeMakeElement
160: .getDeclaredMethod("startElement", 3);
161: static final Method startElementMethod4 = typeMakeElement
162: .getDeclaredMethod("startElement", 4);
163: static final Method endElementMethod = typeMakeElement
164: .getDeclaredMethod("endElement", 2);
165: }
|