local scope vars indexed by number
[org.ibex.core.git] / src / org / ibex / js / JS.java
index 2d5c9aa..d602da3 100644 (file)
@@ -8,43 +8,35 @@ import java.util.*;
 /** The minimum set of functionality required for objects which are manipulated by JavaScript */
 public abstract class JS { 
     public static final JS METHOD = new JS() { };
-    public final JS unclone() { return _unclone(); }
-    public final JS jsclone() throws JSExn { return new Clone(this); }
 
     public JS.Enumeration keys() throws JSExn { throw new JSExn("you can't enumerate the keys of this object (class=" + getClass().getName() +")"); }
     public JS get(JS key) throws JSExn { return null; }
     public void put(JS key, JS val) throws JSExn { throw new JSExn("" + key + " is read only (class=" + getClass().getName() +")"); }
     
-    public InputStream getInputStream() throws IOException {
-        throw new IOException("this object doesn't have a stream associated with it " + getClass().getName() + ")");
-    }
-        
-    public final boolean hasTrap(JS key) { return getTrap(key) != null; }
-    
     public JS callMethod(JS method, JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
         throw new JSExn("method not found (" + JS.debugToString(method) + ")");
     }
-    
     public JS call(JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
         throw new JSExn("you cannot call this object (class=" + this.getClass().getName() +")");
     }
+    public InputStream getInputStream() throws IOException {
+        throw new IOException("this object doesn't have a stream associated with it " + getClass().getName() + ")");
+    }
     
+    public final JS unclone() { return _unclone(); }
+    public final JS jsclone() throws JSExn { return new Clone(this); }
+    public final boolean hasTrap(JS key) { return getTrap(key) != null; }
     public final boolean equals(Object o) { return this == o || ((o instanceof JS) && jsequals((JS)o)); }
+    // Discourage people from using toString()
+    public final String toString() { return "JS Object [class=" + getClass().getName() + "]"; }
     
-    public final String toString() {
-        // Discourage people from using toString()
-        String s = "JS Object [class=" + getClass().getName() + "]";
-        String ext = extendedToString();
-        return ext == null ? s : s + " " + ext;
-    }
-    
-    // These are only used internally by org.ibex.js
+    // Package private methods
     Trap getTrap(JS key) { return null; }
     void putTrap(JS key, Trap value) throws JSExn { throw new JSExn("traps cannot be placed on this object (class=" + this.getClass().getName() +")"); }
     String coerceToString() throws JSExn { throw new JSExn("can't coerce to a string (class=" + getClass().getName() +")"); }
     boolean jsequals(JS o) { return this == o; }
-    String extendedToString() { return null; }
-    
+    JS _unclone() { return this; }
+        
     public static class O extends JS implements Cloneable {
         private Hash entries;
         
@@ -64,29 +56,29 @@ public abstract class JS {
         }    
     }
     
-    JS _unclone() { return this; }
-    
     public interface Cloneable { }
-    
-    public static class Clone extends JS.O {
+        
+    public static class Clone extends O {
         protected final JS clonee;
-        JS _unclone() { return clonee.unclone(); }
-        public JS getClonee() { return clonee; }
         public Clone(JS clonee) throws JSExn {
             if(!(clonee instanceof Cloneable)) throw new JSExn("" + clonee.getClass().getName() + " isn't cloneable");
             this.clonee = clonee;
         }
-        public boolean jsequals(JS o) { return unclone().jsequals(o.unclone()); }
+        JS _unclone() { return clonee.unclone(); }
+        boolean jsequals(JS o) { return clonee.jsequals(o); }
+        
         public Enumeration keys() throws JSExn { return clonee.keys(); }
-        public JS get(JS key) throws JSExn { return clonee.getAndTriggerTraps(key); }
-        public void put(JS key, JS val) throws JSExn { clonee.putAndTriggerTraps(key, val); }
-        public JS callMethod(JS method, JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
-            return clonee.callMethod(method, a0, a1, a2, rest, nargs);
+        public final JS get(JS key) throws JSExn { return clonee.get(key); }
+        public final void put(JS key, JS val) throws JSExn { clonee.put(key,val); }
+        public final JS callMethod(JS method, JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
+            return clonee.callMethod(method,a0,a1,a2,rest,nargs); 
         }
         public JS call(JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
             return clonee.call(a0, a1, a2, rest, nargs);
         }
         public InputStream getInputStream() throws IOException { return clonee.getInputStream(); }
+        // FIXME: This shouldn't be necessary (its for Ibex.Blessing)
+        public JS getClonee() { return clonee; }
     }
     
     public static abstract class Enumeration extends JS {
@@ -110,6 +102,7 @@ public abstract class JS {
             return super.get(key);
         }
     }
+
     public static class EmptyEnumeration extends Enumeration {
         public EmptyEnumeration(Enumeration parent) { super(parent); }
         protected boolean _hasMoreElements() { return false; }
@@ -217,9 +210,6 @@ public abstract class JS {
         return false;
     }
     
-    public static JS newArray() { return new JSArray(); }
-    public static JS newRegexp(JS pat, JS flags) throws JSExn { return new JSRegexp(pat,flags); }
-
     // Instance Methods ////////////////////////////////////////////////////////////////////
  
     public final static JS NaN = new JSNumber.D(Double.NaN);
@@ -274,39 +264,43 @@ public abstract class JS {
     private static Enumeration EMPTY_ENUMERATION = new EmptyEnumeration(null);
     
     public static JS fromReader(String sourceName, int firstLine, Reader sourceCode) throws IOException {
-        return JSFunction._fromReader(sourceName, firstLine, sourceCode);
+        return Parser.fromReader(sourceName, firstLine, sourceCode);
     }
 
-    // HACK: caller can't know if the argument is a JSFunction or not...
-    public static JS cloneWithNewParentScope(JS j, JSScope s) {
-        return ((JSFunction)j)._cloneWithNewParentScope(s);
+    public static JS cloneWithNewGlobalScope(JS js, JS s) {
+        if(js instanceof JSFunction)
+            return ((JSFunction)js)._cloneWithNewParentScope(new JSScope.Top(s));
+        else
+            return js;
     }
 
 
     // Trap support //////////////////////////////////////////////////////////////////////////////
 
     /** performs a put, triggering traps if present; traps are run in an unpauseable interpreter */
-    public void putAndTriggerTraps(JS key, JS value) throws JSExn {
+    public final void putAndTriggerTraps(JS key, JS value) throws JSExn {
         Trap t = getTrap(key);
+        if(JS.isString(key) && JS.toString(key).equals("action")) System.err.println("got put to action! + " + t);
         if(t == null || (t = t.writeTrap()) == null) put(key,value);
         else new Interpreter(t,value,false).resume();
     }
 
     /** performs a get, triggering traps if present; traps are run in an unpauseable interpreter */
-    public JS getAndTriggerTraps(JS key) throws JSExn {
+    public final JS getAndTriggerTraps(JS key) throws JSExn {
         Trap t = getTrap(key);
         if (t == null || (t = t.readTrap()) == null) return get(key);
         else return new Interpreter(t,null,false).resume();
     }
     
-    public JS justTriggerTraps(JS key, JS value) throws JSExn {
+    public final JS justTriggerTraps(JS key, JS value) throws JSExn {
         Trap t = getTrap(key);
         if(t == null || (t = t.writeTrap()) == null) return value;
         else return new Interpreter(t,value,true).resume();
     }
 
     /** adds a trap, avoiding duplicates */
-    final void addTrap(JS key, JSFunction f) throws JSExn {
+    // FIXME: This shouldn't be public, it is needed for a hack in Template.java
+    public void addTrap(JS key, JSFunction f) throws JSExn {
         if (f.numFormalArgs > 1) throw new JSExn("traps must take either one argument (write) or no arguments (read)");
         boolean isRead = f.numFormalArgs == 0;
         for(Trap t = getTrap(key); t != null; t = t.next) if (t.f == f) return;
@@ -314,7 +308,8 @@ public abstract class JS {
     }
 
     /** deletes a trap, if present */
-    final void delTrap(JS key, JSFunction f) throws JSExn {
+    // FIXME: This shouldn't be public, it is needed for a hack in Template.java
+    public void delTrap(JS key, JSFunction f) throws JSExn {
         Trap t = (Trap)getTrap(key);
         if (t == null) return;
         if (t.f == f) { putTrap(t.target, t.next); return; }