+++ /dev/null
-package org.ibex.xml;
-import org.ibex.js.*;
-import org.ibex.util.*;
-import org.ibex.io.*;
-import java.io.*;
-import java.net.*;
-import java.util.*;
-
-public class JSRewriter extends XML.Node.Stream {
-
- private XML.Node.Stream in;
- private JSScope scope;
-
- public JSRewriter(XML.Node.Stream in) { this.in = in; this.scope = new JSScope(null); }
- public JSRewriter(XML.Node.Stream in, JSScope scope) { this.in = in; this.scope = scope; }
-
- public boolean _next(int level, XML.Node n) {
- if (!in.next(level, n)) return false;
- if (n.cdata != null) n.cdata = eval(n.cdata);
- else for(int i=1; i<n.numattrs; i+=2) n.attrs[i] = eval(n.attrs[i]);
- return true;
- }
-
- private String eval(String s) {
- if (s == null) return null;
- StringBuffer ret = new StringBuffer();
- while(s.indexOf("$[") != -1) {
- ret.append(s.substring(0, s.indexOf("$[")));
- s = s.substring(s.indexOf("$[")+2);
- String s2 = "return (" + s.substring(0, s.indexOf(']')) + ");\n";
- System.err.println("evaluating " + s2);
- try {
- JS js = JS.cloneWithNewParentScope(JS.fromReader("input", 0, new StringReader(s2)), scope);
- Object r = js.call(null, null, null, null, 0);
- System.err.println("output was " + r);
- ret.append(r == null ? "null" : r.toString());
- } catch (Exception e) {
- e.printStackTrace();
- ret.append(e.toString());
- }
- s = s.substring(s.indexOf(']') + 1);
- }
- ret.append(s);
- return ret.toString();
- }
-}
-
-
--- /dev/null
+package org.ibex.xt;
+import org.ibex.js.*;
+import org.ibex.util.*;
+import org.ibex.io.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+public class Node {
+
+ public String name = null;
+ public String cdata = null;
+ public int numattrs = 0;
+ public String[] attrs = null;
+ public String uri = null;
+ private int delta = 0;
+
+ public Node() { }
+ public Node(Node n) { copyFrom(n); }
+ public final void clear() { name = null; cdata = null; numattrs = 0; delta = 0; uri = null; }
+ public final void copyFrom(Node n) {
+ name=n.name; cdata=n.cdata; numattrs=n.numattrs; delta=n.delta; uri=n.uri;
+ if (n.attrs == null) { attrs = null; return; }
+ attrs = new String[n.attrs.length]; System.arraycopy(n.attrs, 0, attrs, 0, attrs.length); }
+ public final String attr(String key) {
+ for(int i=0; i<numattrs; i++) if (key.equals(attrs[i*2])) return attrs[i*2+1]; return null; }
+
+ public static abstract class Stream {
+ public static final Stream NULL = new Stream() { public boolean _read(Node n) { return false; } };
+ public static interface Functor { public Node.Stream wrap(Node.Stream in); }
+ public static class ConstantFunctor implements Functor {
+ private final Node.Stream stream;
+ public ConstantFunctor(Node.Stream stream) { this.stream = stream; }
+ public Node.Stream wrap(Node.Stream in) { return stream; }
+ }
+ public static abstract class Filter extends Stream {
+ Stream upstream;
+ Filter() { }
+ public Filter(Stream upstream) { this.upstream = upstream; }
+ public boolean upstreamRead(Node n) { upstream = upstream.simplify(); return upstream.read(n); }
+ public void wrapUpstream(Functor f) { upstream = f.wrap(upstream); }
+ public Filter graft(Functor f, Node n) {
+ upstream = new Graft((upstream instanceof Peekable) ? (Peekable)upstream : new Peekable(upstream), n, f);
+ return this;
+ }
+ }
+
+ public Stream simplify() { return this; }
+ protected abstract boolean _read(Node n);
+ public final boolean read(Node n) { n.clear(); if (!_read(n)) { n.clear(); return false; } return true; }
+
+ public static class Peekable extends Filter {
+ public Peekable(Stream s) { super(s); }
+ private Node pending = null;
+ public boolean peek(Node n) {
+ if (pending == null) {
+ Node n2 = new Node();
+ if (!upstreamRead(n2)) return false;
+ pending = n2;
+ }
+ n.copyFrom(pending);
+ return true;
+ }
+ public boolean _read(Node n) {
+ if (pending != null) { n.copyFrom(pending); pending = null; return true; }
+ return upstreamRead(n);
+ }
+ }
+
+ private static class Graft extends Filter {
+ private Stream inner2;
+ private Peekable a;
+ int total = 0;
+ int net = 0;
+ boolean simple = false;
+ private Node pending = new Node();
+ public Graft(final Peekable a, final Node n, final Functor f) {
+ this.a = a;
+ upstream = inner2 = new Stream() {
+ public boolean _read(Node n) {
+ if (!Graft.this.a.peek(n)) return false;
+ if (net + n.delta <= 0) return false;
+ Graft.this.a.read(n);
+ net += n.delta;
+ return true;
+ } };
+ wrapUpstream(f);
+ if (__read(pending)) pending.delta = n.delta;
+ total = n.delta;
+ }
+ public boolean _read(Node n) {
+ if (pending != null) { n.copyFrom(pending); pending = null; return true; }
+ boolean ret = __read(n);
+ if (ret) total += n.delta;
+ return ret;
+ }
+ public boolean __read(Node n) {
+ if (simple) return a.read(n);
+ if (upstreamRead(n)) return true;
+ while(inner2.read(n));
+ if (!a.read(n)) return false;
+ n.delta += net - total;
+ simple = true;
+ return true;
+ }
+ }
+
+ public static class FromXML extends Node.Stream {
+ private final XML.Pull xml;
+ private XML.Element parent = null;
+ private XML.Element e;
+ private int currentdelta = 0;
+ public FromXML(Reader r) { this.xml = new XML.Pull(r); }
+ protected boolean _read(Node n) { try {
+ Object ret = xml.read();
+ if (ret == null) return false;
+ if (ret instanceof String) {
+ n.cdata = (String)ret;
+ n.delta = xml.level - currentdelta;
+ currentdelta = xml.level;
+ return true;
+ }
+ XML.Element e = (XML.Element)ret;
+ n.name = e.getLocalName();
+ n.uri = e.getUri();
+ n.numattrs = e.getAttrLen();
+ n.delta = e.level - currentdelta;
+ currentdelta = e.level;
+ if (n.attrs == null || n.attrs.length < n.numattrs*2) n.attrs = new String[n.numattrs*4];
+ for(int i=0; i<n.numattrs; i++) { n.attrs[i*2] = e.getAttrKey(i); n.attrs[i*2+1] = e.getAttrVal(i); }
+ return true;
+ } catch (Exception e) { throw new RuntimeException(e); } }
+ }
+
+ public void toXML(Writer writer) throws IOException { Node n = new Node(); if (read(n)) toXML(writer, n); }
+ private Node toXML(Writer w, Node n) throws IOException {
+ final String name = n.name;
+ if (n.cdata != null) {
+ w.write(n.cdata);
+ if (!read(n)) n = null;
+ } else {
+ w.write("<");
+ w.write(name);
+ for(int i=0; i < n.numattrs * 2; i+=2) {
+ w.write(" ");
+ w.write(n.attrs[i]);
+ w.write("=\"");
+ w.write(n.attrs[i+1]);
+ w.write("\"");
+ }
+ if (!read(n)) n = null;
+ if (n == null || n.delta <= 0) {
+ w.write("/>");
+ } else {
+ w.write(">");
+ while(n != null && n.delta > 0) n = toXML(w, n);
+ w.write("</");
+ w.write(name);
+ w.write(">");
+ }
+ }
+ if (n != null) n.delta++;
+ return n;
+ }
+ }
+}
--- /dev/null
+package org.ibex.xt;
+import org.ibex.js.*;
+import org.ibex.util.*;
+import org.ibex.io.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+import com.thoughtworks.xstream.*;
+import org.prevayler.*;
+import org.prevayler.implementation.snapshot.*;
+
+public class Prevalence {
+
+ static final Hashtable prevaylers = new Hashtable();
+
+ public static void destroy(ServletContext cx, Prevayler prevayler) { try {
+ prevaylers.remove(cx);
+ prevayler.takeSnapshot();
+ prevayler.close();
+ } catch (Exception e) { e.printStackTrace(); } }
+
+ private static class SnapshotThread extends Thread {
+ ServletContext cx;
+ public SnapshotThread(ServletContext cx) { this.cx = cx; }
+ public void run() {
+ try {
+ Thread.sleep(10000);
+ Prevayler privatePrevayler = (Prevayler)prevaylers.get(cx);
+ if (privatePrevayler == null) return;
+ privatePrevayler.takeSnapshot();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public static Prevayler getPrevayler(ServletContext cx) {
+ try {
+ Prevayler prevayler;
+ synchronized(cx) {
+ prevayler = (Prevayler)prevaylers.get(cx);
+ if (prevayler == null) {
+ PrevaylerFactory pf = new PrevaylerFactory();
+ String base = cx.getRealPath("/") + "WEB-INF" + File.separatorChar + "prevalent";
+ System.err.println("prevayling to " + base);
+ pf.configurePrevalenceBase(base);
+ XStreamSnapshotManager manager = new XStreamSnapshotManager(new JS(), base, null) {
+ protected XStream createXStream() {
+ XStream xstream = new XStream();
+ xstream.alias("js", JS.class);
+ xstream.alias("jsdate", JSDate.class);
+ return xstream;
+ }
+ };
+ System.err.println("configuring with " + manager);
+ pf.configureSnapshotManager(manager);
+ //pf.configureClassLoader(JSTransaction.class.getClassLoader());
+ prevayler = pf.create();
+ prevaylers.put(cx, prevayler);
+ new SnapshotThread(cx).start();
+ }
+ }
+ return prevayler;
+ } catch (Exception e) { throw new RuntimeException(e); } }
+
+ public static class JSTransaction implements Transaction {
+ public static final long serialVersionUid = 0xfb2aa281;
+ private JS js;
+ public JSTransaction(JS js) { this.js = js; }
+ public void executeOn(Object o, Date now) {
+ try {
+ js.call(o, new JSDate(now.getTime()), null, null, 2);
+ } catch (Exception e) { throw new RuntimeException(e); }
+ }
+ }
+
+ public static class JSQuery implements Query {
+ public static final long serialVersionUid = 0xfb2aa282;
+ private JS js;
+ public JSQuery(JS js) { this.js = js; }
+ public Object query(Object o, Date now) {
+ try {
+ return js.call(o, new JSDate(now.getTime()), null, null, 2);
+ } catch (Exception e) { throw new RuntimeException(e); }
+ }
+ }
+}
-package org.ibex.xml;
+package org.ibex.xt;
import org.ibex.js.*;
import org.ibex.util.*;
import org.ibex.io.*;
import org.prevayler.*;
import org.prevayler.implementation.snapshot.*;
-
public class Servlet extends HttpServlet {
- private ServletResolver resolver = new ServletResolver();
- private class ServletResolver implements XML.Node.Stream.Resolver {
- public XML.Node.Stream.Functor resolve(String uri) {
- if (uri.indexOf(':') == -1) throw new RuntimeException("uri does not contain an method: " + uri);
- String method = uri.substring(0, uri.indexOf(':'));
- String rest = uri.substring(uri.indexOf(':'))+1;
- //case "xtree": return XTree.tag(rest);
- //#switch(method)
- case "webinf": return new Template(cx.getRealPath(rest));
- case "java": try { return (XML.Node.Stream.Functor)Class.forName(rest).newInstance(); }
- catch (Exception e) { throw new RuntimeException(e); }
- //#end
- throw new RuntimeException("unknown method " + method);
+ private ServletScope servletscope = null;
+ private String path;
+ private Prevayler prevayler;
+ private JS prevalent;
+ private ServletContext cx = null;
+
+ public void destroy() { try {
+ synchronized(this.getClass()) {
+ Prevayler privatePrevayler = prevayler;
+ if (prevayler == null) return;
+ prevayler = null;
+ Prevalence.destroy(cx, prevayler);
}
+ } catch (Exception e) { e.printStackTrace(); } }
+
+ public void init(ServletConfig sc) throws ServletException {
+ cx = sc.getServletContext();
+ prevayler = Prevalence.getPrevayler(cx);
}
+ public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { doGet(request, response); }
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
- JSScope scope = new ServletScope(request, response);
- String path = cx.getRealPath(((HttpServletRequest)request).getServletPath());
+ servletscope = new ServletScope(request, response, cx);
+ path = cx.getRealPath(((HttpServletRequest)request).getServletPath());
Reader xmlreader = new InputStreamReader(new FileInputStream(path));
- XML.Node.Stream s = new JSRewriter(XML.Node.Stream.in(xmlreader), scope);
- s.out(response.getWriter());
+ new Template(servletscope, new JSScope(servletscope), xmlreader).wrap(null).toXML(response.getWriter());
}
- public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { doGet(request, response); }
-
public class ServletScope extends JSScope {
HttpServletRequest request;
HttpServletResponse response;
- public ServletScope(ServletRequest request, ServletResponse response) {
+ ServletContext cx;
+ public String getRealPath(String s) { return cx.getRealPath(s); }
+ public ServletScope(ServletRequest request, ServletResponse response, ServletContext cx) {
super(null);
this.request = (HttpServletRequest)request;
this.response = (HttpServletResponse)response;
+ this.cx = cx;
}
private JS params = new JS() {
public Object get(Object key) { return request.getParameter(JS.toString(key)); }
//#switch(method)
case "prevalent.query":
try {
- return prevayler.execute(new JSQuery(JS.cloneWithNewParentScope((JS)a, null)));
+ return prevayler.execute(new Prevalence.JSQuery(JS.cloneWithNewParentScope((JS)a, null)));
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e); }
- case "prevalent.execute":
- try {
- prevayler.execute(new JSTransaction(JS.cloneWithNewParentScope((JS)a, null)));
- } catch (Exception e) {
- e.printStackTrace();
- throw new RuntimeException(e); }
-
case "session.invalidate": request.getSession(true).invalidate(); return null;
+ case "context.list":
+ String path = JS.toString(a);
+ if (path.indexOf("..") != -1) throw new JSExn("cannot use .. in paths");
+ File f = new File(cx.getRealPath("/") + File.separatorChar + path);
+ if (!f.isDirectory()) return null;
+ String[] contents = f.list();
+ JSArray ret = new JSArray(contents.length);
+ for(int i=0; i<contents.length; i++) ret.addElement(contents[i]);
+ return ret;
//#end
return null;
}
//#switch(key)
case "body":
case "arg": return null;
- case "prevalent": return getSub("prevalent");
- case "prevalent.query": return METHOD;
- case "prevalent.execute": return METHOD;
+ case "prevalent": return prevalent;
case "request": return getSub("request");
case "request.user": return request.getRemoteUser();
case "request.header": return requestHeader;
case "session.created": return new JSDate(request.getSession(true).getCreationTime());
case "session.accessed": return new JSDate(request.getSession(true).getLastAccessedTime());
case "session.invalidate": return METHOD;
+ case "page": return getSub("page");
+ case "page.lastmodified": return new JSDate(new File(path).lastModified());
+ case "context": return getSub("context");
+ case "context.list": return METHOD;
case "params": return params;
case "cookie": return cookies;
//#end
case "response.code": response.setStatus(JS.toInt(val));
case "response.redirect": response.sendRedirect(JS.toString(val));
case "response.contentType": response.setContentType(JS.toString(val));
+ case "prevalent":
+ try { prevayler.execute(new Prevalence.JSTransaction(JS.cloneWithNewParentScope((JS)val, null)));
+ } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); }
//#end
} catch (IOException e) {
throw new JSExn(e);
}
}
- // Prevalence //////////////////////////////////////////////////////////////////////////////
-
- static final Hashtable prevaylers = new Hashtable();
- private Prevayler prevayler;
- private JS prevalent;
- private ServletContext cx = null;
- public void destroy() {
- try {
- synchronized(this.getClass()) {
- Prevayler privatePrevayler = prevayler;
- if (prevayler == null) return;
- prevayler = null;
- prevaylers.remove(cx);
- prevayler.takeSnapshot();
- prevayler.close();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- private static class SnapshotThread extends Thread {
- ServletContext cx;
- public SnapshotThread(ServletContext cx) { this.cx = cx; }
- public void run() {
- try {
- Thread.sleep(10000);
- Prevayler privatePrevayler = (Prevayler)prevaylers.get(cx);
- if (privatePrevayler == null) return;
- privatePrevayler.takeSnapshot();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
-
- public void init(ServletConfig sc) throws ServletException {
- try {
- cx = sc.getServletContext();
- synchronized(cx) {
- prevayler = (Prevayler)prevaylers.get(cx);
- if (prevalent == null) {
- PrevaylerFactory pf = new PrevaylerFactory();
- String base = cx.getRealPath("/") + "WEB-INF" + File.separatorChar + "prevalent";
- System.err.println("prevayling to " + base);
- pf.configurePrevalenceBase(base);
- XStreamSnapshotManager manager = new XStreamSnapshotManager(new JS(), base, null) {
- protected XStream createXStream() {
- XStream xstream = new XStream();
- xstream.alias("js", JS.class);
- xstream.alias("jsdate", JSDate.class);
- return xstream;
- }
- };
- System.err.println("configuring with " + manager);
- pf.configureSnapshotManager(manager);
- //pf.configureClassLoader(JSTransaction.class.getClassLoader());
- prevayler = pf.create();
- prevaylers.put(cx, prevayler);
- new SnapshotThread(cx).start();
- }
- }
- prevalent = (JS)prevayler.prevalentSystem();
- } catch (Exception e) {
- throw new ServletException(e);
- }
- }
-
- public static class JSTransaction implements Transaction {
- private JS js;
- public JSTransaction(JS js) { this.js = js; }
- public void executeOn(Object o, Date now) {
- try {
- js.call(o, new JSDate(now.getTime()), null, null, 2);
- } catch (Exception e) { throw new RuntimeException(e); }
- }
- }
-
- public static class JSQuery implements Query {
- private JS js;
- public JSQuery(JS js) { this.js = js; }
- public Object query(Object o, Date now) {
- try {
- return js.call(o, new JSDate(now.getTime()), null, null, 2);
- } catch (Exception e) { throw new RuntimeException(e); }
- }
- }
-
}
--- /dev/null
+package org.ibex.xt;
+import org.ibex.js.*;
+import org.ibex.util.*;
+import org.ibex.io.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+public class Template extends Node.Stream.Filter implements Node.Stream.Functor {
+
+ static Template newTemplate(Servlet.ServletScope servletscope, JSScope scope, String str) {
+ try {
+ File f = new File(str);
+ if (!f.exists()) f = new File(str + ".xt");
+ if (!f.exists()) f = new File(str + ".xml");
+ return new Template(servletscope, scope, new InputStreamReader(new FileInputStream(f)));
+ } catch (Exception e) { throw new RuntimeException(e); }
+ }
+
+ static JSScope copyNodeToScope(Node n, JSScope scope) {
+ try {
+ for(int i=0; i<n.numattrs; i++) {
+ scope.declare(n.attrs[i*2]);
+ scope.put(n.attrs[i*2], n.attrs[i*2+1]);
+ }
+ return scope;
+ } catch (Exception e) { throw new RuntimeException(e); }
+ }
+
+ private class JSRewriter extends Node.Stream {
+ private Node.Stream in;
+ private JSScope scope;
+ public JSRewriter(Node.Stream in, JSScope scope) { this.in = in; this.scope = scope; }
+ protected boolean _read(Node n) { if (!in.read(n)) return false; transform(n, scope); return true; }
+ }
+
+ public static Node transform(Node n, JSScope scope) {
+ if (n.cdata != null) n.cdata = eval(n.cdata, scope).toString();
+ else for(int i=1; i<n.numattrs*2; i+=2) n.attrs[i] = eval(n.attrs[i], scope).toString();
+ return n;
+ }
+
+ private static Object eval(String s, JSScope scope) {
+ if (s == null) return null;
+ StringBuffer ret = new StringBuffer();
+ for(boolean first = true; s.indexOf("${") != -1; first = false) {
+ ret.append(s.substring(0, s.indexOf("${")));
+ String s2 = s.substring(s.indexOf("${")+2);
+ Object app = exec("return (" + s2.substring(0, s2.indexOf('}')) + ");\n", scope);
+ s = s.substring(s.indexOf('}') + 1);
+ //if (first && s.trim().length() == 0) return app;
+ if (!(app == null || app instanceof String || app instanceof Number || app instanceof Boolean))
+ throw new RuntimeException("javascripts within ${...} can only return strings, numbers, and booleans; not a " +
+ app.getClass().getName());
+ ret.append(app == null ? "null" : app.toString());
+ }
+ ret.append(s);
+ return ret.toString();
+ }
+
+ public static Object exec(String s, JSScope scope) {
+ try {
+ return JS.eval(JS.cloneWithNewParentScope(JS.fromReader("input", 0, new StringReader(s)), scope));
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ }
+ }
+
+ private JSScope scope;
+ private Servlet.ServletScope servletscope;
+ private Node.Stream children;
+ public Node.Stream wrap(Node.Stream children) { this.children = children; return this; }
+ public Template(Servlet.ServletScope servletscope, JSScope scope, Reader template) {
+ super(new Node.Stream.FromXML(template));
+ this.scope = scope;
+ this.servletscope = servletscope;
+ }
+ public boolean _read(Node n) { boolean ret = __read(n); if (ret) transform(n, scope); return ret; }
+ public boolean __read(final Node n) {
+ if (!upstreamRead(n)) return false;
+ if (n.cdata != null) return true;
+ final String uri = n.uri;
+ final String name = n.name;
+ if (uri.indexOf(':') == -1)
+ throw new RuntimeException("uri does not contain a colon: " + uri + " (tag name " + name + ")");
+ final String method = uri.substring(0, uri.indexOf(':'));
+ final String rest = uri.substring(uri.indexOf(':')+1);
+ if (uri.equals("http://www.w3.org/1999/xhtml")) { return true;
+ } else if (method.equals("webinf")) {
+ return graft(newTemplate(servletscope, copyNodeToScope(transform(n, scope), new JSScope(servletscope)),
+ servletscope.getRealPath("/") + "/WEB-INF/" + rest + name), n).upstreamRead(n);
+ } else if (uri.equals("http://xt.ibex.org/")) {
+ //#switch(name)
+ case "if":
+ transform(n, scope);
+ return graft("true".equals(n.attr("if")) ? new DropTag() : new DropAll(), n).upstreamRead(n);
+ case "js": return graft(new JsTag(scope), n).upstreamRead(n);
+ case "foreach": return graft(new ForEach(n, scope), n).upstreamRead(n);
+ case "children":
+ if (children == null) return true;
+ graft(new Node.Stream.ConstantFunctor(children), n);
+ children = null;
+ return upstreamRead(n);
+ //#end
+ return true;
+ } else if (method.equals("java")) {
+ try { return graft((Node.Stream.Functor)Class.forName(rest).newInstance(), n).upstreamRead(n); }
+ catch (Exception e) { throw new RuntimeException(e); }
+ }
+ throw new RuntimeException("Unknown namespace URI " + uri);
+ }
+
+ private class ForEach extends Node.Stream.Filter implements Node.Stream.Functor {
+ private Node[] nodes = null;
+ private Vec array = new Vec();
+ private JSScope scope;
+ public ForEach(Node n, JSScope s) {
+ super(Node.Stream.NULL);
+ Vec v = ((JSArray)exec("return (" + n.attr("in").toString() + ");", this.scope = s)).toVec();
+ while(true) { Object o = v.pop(); if (o == null) break; array.push(o); }
+ }
+ public Node.Stream wrap(Node.Stream kids) {
+ Vec nodes = new Vec();
+ Node n2 = new Node();
+ while(kids.read(n2)) nodes.addElement(new Node(n2));
+ nodes.copyInto(this.nodes = new Node[nodes.size()]);
+ return this;
+ }
+ protected boolean _read(Node n) {
+ if (upstreamRead(n)) return true;
+ if (array.size() == 0) return false;
+ JSScope scope2 = new JSScope(scope);
+ try { scope2.declare("x"); scope2.put("x", array.pop()); } catch (JSExn e) { throw new RuntimeException(e); }
+ return graft(new ConstantFunctor(new JSRewriter(new Node.Stream() {
+ private int i = 0;
+ protected boolean _read(Node n) {
+ if (i>=nodes.length) return false;
+ n.copyFrom(nodes[i++]);
+ return true;
+ } }, scope2)), n).upstreamRead(n);
+ }
+ }
+
+ private class DropTag implements Node.Stream.Functor {
+ public Node.Stream wrap(Node.Stream kids) {
+ return kids;
+ } }
+
+ private class DropAll implements Node.Stream.Functor {
+ public Node.Stream wrap(Node.Stream kids) {
+ return new Node.Stream() { public boolean _read(Node n) { return false; } };
+ } }
+
+ private class JsTag implements Node.Stream.Functor {
+ JSScope scope;
+ public JsTag(JSScope scope) { this.scope = scope; }
+ public Node.Stream wrap(final Node.Stream s) {
+ return new Node.Stream() {
+ protected boolean _read(Node n) {
+ boolean ret = s.read(n);
+ if (ret && n.cdata != null) {
+ System.err.println("exec("+n.cdata+")");
+ exec(n.cdata, scope);
+ return _read(n);
+ }
+ return ret;
+ }
+ };
+ }
+ }
+}