updated org.ibex.xt for new JS
[org.ibex.xt.git] / src / org / ibex / xt / Template.java
index 9e3e066..b585033 100644 (file)
@@ -14,7 +14,7 @@ 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) {
+    static Template newTemplate(Servlet.ServletScope servletscope, Scope scope, String str) {
         try {
             File f = new File(str);
             if (!f.exists()) f = new File(str + ".xt");
@@ -23,11 +23,11 @@ public class Template extends Node.Stream.Filter implements Node.Stream.Functor
         } catch (Exception e) { throw new RuntimeException(e); }
     }
 
-    static JSScope copyNodeToScope(Node n, JSScope scope) {
+    static Scope copyNodeToScope(Node n, Scope 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]);
+                scope.put(JSU.S(n.attrs[i*2]), JSU.S(n.attrs[i*2+1]));
             }
             return scope;
         } catch (Exception e) { throw new RuntimeException(e); }
@@ -35,18 +35,18 @@ public class Template extends Node.Stream.Filter implements Node.Stream.Functor
 
     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; }
+        private Scope scope;
+        public JSRewriter(Node.Stream in, Scope 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) {
+    public static Node transform(Node n, Scope 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) {
+    private static Object eval(String s, Scope scope) {
         if (s == null) return null;
         StringBuffer ret = new StringBuffer();
         for(boolean first = true; s.indexOf("${") != -1; first = false) {
@@ -64,22 +64,22 @@ public class Template extends Node.Stream.Filter implements Node.Stream.Functor
         return ret.toString();
     }
 
-    public static Object exec(String s, JSScope scope) {
+    public static Object exec(String s, Scope scope) {
         try {
-            return JS.eval(JS.cloneWithNewParentScope(JS.fromReader("input", 0, new StringReader(s)), scope));
+            return JSU.cloneWithNewGlobalScope(JSU.fromReader("input", 0, new StringReader(s)), scope).call(null,null);
         } catch (Exception e) {
             e.printStackTrace();
             throw new RuntimeException(e);
         }
     }
 
-    private JSScope scope;
+    private Scope 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) {
+    public Template(Servlet.ServletScope servletscope, JS scope, Reader template) {
         super(new Node.Stream.FromXML(template));
-        this.scope = scope;
+        this.scope = new Scope(scope);
         this.servletscope = servletscope;
     }
     public boolean _read(Node n) { boolean ret = __read(n); if (ret) transform(n, scope); return ret; }
@@ -94,13 +94,13 @@ public class Template extends Node.Stream.Filter implements Node.Stream.Functor
         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)),
+            return graft(newTemplate(servletscope, copyNodeToScope(transform(n, scope), new Scope(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);
+                return graft((Node.Stream.Functor)("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":
@@ -120,11 +120,19 @@ public class Template extends Node.Stream.Filter implements Node.Stream.Functor
     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) {
+        private Scope scope;
+        public ForEach(Node n, Scope 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); }
+            try {
+                JSArray a = ((JSArray)exec("return (" + n.attr("in").toString() + ");", this.scope = s));
+                while(true) {
+                    JS o = a.call(JSU.S("pop"), new JS[] { });
+                    if (o == null) break;
+                    array.push(o);
+                }
+            } catch (JSExn e) {
+                throw new RuntimeException(e);
+            }
         }
         public Node.Stream wrap(Node.Stream kids) {
             Vec nodes = new Vec();
@@ -136,8 +144,8 @@ public class Template extends Node.Stream.Filter implements Node.Stream.Functor
         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); }
+            Scope scope2 = new Scope(scope);
+            try { scope2.declare("x"); scope2.put(JSU.S("x"), (JS)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) {
@@ -148,6 +156,24 @@ public class Template extends Node.Stream.Filter implements Node.Stream.Functor
         }
     }
 
+    public static class Scope extends JS.Immutable {
+        private final JS parent;
+        private final Hash declared = new Hash();
+        public Scope(JS parent) { this.parent = parent; }
+        public JS get(JS key) throws JSExn {
+            if (declared.get(key)!=null) return super.get(key);
+            return parent.get(key);
+        }
+        public void put(JS key, JS val) throws JSExn {
+            if (declared.get(key)!=null) super.put(key, val);
+            else parent.put(key, val);
+        }
+        public void declare(JS key) { declared.put(key, Boolean.TRUE); }
+        public void declare(String key) { declare(JSU.S(key)); }
+        public void undeclare(JS key) { declared.remove(key); }
+        public void undeclare(String key) { undeclare(JSU.S(key)); }
+    }
+
     private class DropTag implements Node.Stream.Functor {
         public Node.Stream wrap(Node.Stream kids) {
             return kids;
@@ -159,8 +185,8 @@ public class Template extends Node.Stream.Filter implements Node.Stream.Functor
         } }
 
     private class JsTag implements Node.Stream.Functor {
-        JSScope scope;
-        public JsTag(JSScope scope) { this.scope = scope; }
+        Scope scope;
+        public JsTag(Scope scope) { this.scope = scope; }
         public Node.Stream wrap(final Node.Stream s) {
             return new Node.Stream() {
                     protected boolean _read(Node n) {