extra comments
[org.ibex.xt-crawshaw.git] / src / java / org / ibex / xt / Template.java
index c30ece6..6afe1b2 100644 (file)
@@ -14,6 +14,9 @@ import java.util.*;
 import org.ibex.util.*;
 import org.ibex.js.*;
 
+// FIXME: replace scope().get("") with containsKey() check on attributes,
+//        thereby neatly sidestepping any higher up user defined variables
+//        (especially when combined with undeclare()
 public class Template extends JSLeaf.Element {
     public static Template parse(String path, Template.Scope s) throws FileNotFoundException, IOException {
         Reader xmlreader = new BufferedReader(new InputStreamReader(new FileInputStream(path)));
@@ -40,10 +43,7 @@ public class Template extends JSLeaf.Element {
             //#end
 
         } else if (uri.startsWith("http://xt.ibex.org/")) {
-            //#switch(uri.substring(19))
-            case "io": System.out.println("ibex.xt.io not yet implemented"); // TODO
-            //#end
-            //throw new JSLeaf.Exn("Unknown XT library: "+uri);
+            throw new JSLeaf.Exn("Unknown XT library: "+uri);
 
         } else if (uri.startsWith("local:")) {
             // merge a new template into this tree
@@ -62,15 +62,16 @@ public class Template extends JSLeaf.Element {
                 e.getChildren().clear();
             }
 
-            Tree.Element merged = new JSLeaf.Merge(t, e);
+            // merge the attributes of the template and its representative
+            t.setAttributes(new JSLeaf.MergeAttr(e.getAttributes(), t.getAttributes()));
 
             // remap the parent of the original element
             if (e.getParent() != null) {
                 List ch = e.getParent().getChildren();
-                ch.set(ch.indexOf(e), merged);
+                ch.set(ch.indexOf(e), t);
             }
 
-            return wrap(merged, s);
+            return wrap(t, s);
         }
 
         e = new Template.AttributeEval(e);
@@ -107,11 +108,14 @@ public class Template extends JSLeaf.Element {
     /** Processes ${...} blocks in attributes, loads applicable
      *  attributes into the JS scope and processes global attributes. */
     public static class AttributeEval extends JSLeaf.Element implements Tree.Attributes {
+        // TODO: hide global attributes from out() function. waiting on util.XMLHelper
         protected Tree.Attributes a;
 
-        public AttributeEval(Tree.Element wrapped) { super(wrapped); a = wrapped.getAttributes(); }
-
-        public Tree.Attributes getAttributes() { return this; }
+        public AttributeEval(Tree.Element wrapped) {
+            super(wrapped);
+            a = wrapped.getAttributes();
+            wrapped.setAttributes(this);
+        }
 
         public int getIndex(String q) { return a.getIndex(q); }
         public int getIndex(String u, String k) { return a.getIndex(u, k); }
@@ -134,7 +138,7 @@ public class Template extends JSLeaf.Element {
                     case "declare":
                         Object d = eval(a.getVal(i));
                         if (!(d instanceof String)) throw new JSLeaf.Exn(
-                            "attribute "+getPrefix()+":declare can only contain a "+
+                            "attribute '"+getPrefix()+":declare' can only contain a "+
                             "space seperated list of variable names to declare.");
                         StringTokenizer st = new StringTokenizer((String)d, " ");
                         while (st.hasMoreTokens()) scope().declare(st.nextToken());
@@ -221,16 +225,36 @@ public class Template extends JSLeaf.Element {
 
     // TODO: finish
     public static final class Transaction extends JSLeaf.Element {
-        private final Template.Scope scope; // FIXME: HACK. unstatisise all tags, or do this to all
-        public Transaction(Tree.Element e, Template.Scope s) { super(e); scope = s;} // TODO: check kids
+        private Template.Scope scope;
+        public Transaction(Tree.Element e, Template.Scope s) { super(e); scope = s; }
 
         public void out(Writer w) throws IOException {
-            // TODO: <xt:use />
-            List c = getChildren();
             StringWriter sw = new StringWriter();
+            List c = getChildren();
             for (int i=0; i < c.size(); i++) ((Tree.Leaf)c.get(i)).out(sw);
-            JS t = JS.fromReader("input", 0, new StringReader(sw.toString()));
-            t = JS.cloneWithNewParentScope(t, new JSScope(null));
+            StringReader sr = new StringReader(sw.toString());
+
+            JS t;
+            try { t = JS.cloneWithNewParentScope(
+                        JS.fromReader("input", 0, sr), new JSScope(null)); }
+            catch (IOException e) { throw new JSLeaf.Exn(e.getMessage()); }
+
+            try {
+                JSScope scope = JS.getParentScope(t);
+
+                Object u = scope().get("use"); if (u != null) scope().undeclare("use");
+                if (u != null) {
+                    if (!(u instanceof String)) throw new JSLeaf.Exn(
+                         "<"+getPrefix()+":transaction> requires 'use' attribute "+
+                         "to be a valid space-seperated list of variables");
+                    StringTokenizer st = new StringTokenizer((String)u);
+                    while (st.hasMoreTokens()) {
+                        String k = st.nextToken();
+                        scope.put(k, scope().get(k));
+                    }
+                }
+            } catch (JSExn e) { throw new JSLeaf.Exn(e); }
+
             scope.transaction(t);
         }
     }
@@ -238,7 +262,6 @@ public class Template extends JSLeaf.Element {
     public static final class Text extends JSLeaf {
         public Text(Tree.Leaf w) { super(w); }
         public void out(Writer w) throws IOException {
-            // FIXME: make eval() take a writer
             StringWriter sw = new StringWriter();
             super.out(sw);
             w.write((String)eval(sw.toString()));