";
+ linep [0] = 1;
+ }
+
+ string sourceURI = ScriptRuntime.makeUrlForGeneratedScript (false, filename, linep [0]);
+
+ IScriptable global = ScriptableObject.GetTopLevelScope (scope);
+
+ ErrorReporter reporter;
+ reporter = DefaultErrorReporter.ForEval (cx.ErrorReporter);
+
+ // Compile with explicit interpreter instance to force interpreter
+ // mode.
+ return cx.CompileFunction (global, source, new Interpreter (), reporter, sourceURI, 1, (object)null);
+ }
+
+ #region PrototypeIds
+ private const int Id_constructor = 1;
+ private const int Id_toString = 2;
+ private const int Id_toSource = 3;
+ private const int Id_apply = 4;
+ private const int Id_call = 5;
+ private const int MAX_PROTOTYPE_ID = 5;
+ #endregion
+
+ protected internal override int FindPrototypeId (string s)
+ {
+ int id;
+ #region Generated PrototypeId Switch
+ L0: {
+ id = 0;
+ string X = null;
+ int c;
+ L:
+ switch (s.Length) {
+ case 4:
+ X = "call";
+ id = Id_call;
+ break;
+ case 5:
+ X = "apply";
+ id = Id_apply;
+ break;
+ case 8:
+ c = s [3];
+ if (c == 'o') { X = "toSource"; id = Id_toSource; }
+ else if (c == 't') { X = "toString"; id = Id_toString; }
+ break;
+ case 11:
+ X = "constructor";
+ id = Id_constructor;
+ break;
+ }
+ if (X != null && X != s && !X.Equals (s))
+ id = 0;
+ }
+ EL0:
+
+ #endregion
+ return id;
+ }
+
+
+ private object prototypeProperty;
+ private bool isPrototypePropertyImmune;
+
+
+ }
+}
+
diff --git a/Code/EcmaScript.NET/Collections/ObjArray.cs b/src/EcmaScript.NET/Collections/ObjArray.cs
similarity index 94%
rename from Code/EcmaScript.NET/Collections/ObjArray.cs
rename to src/EcmaScript.NET/Collections/ObjArray.cs
index 6b94dea..b8d0057 100644
--- a/Code/EcmaScript.NET/Collections/ObjArray.cs
+++ b/src/EcmaScript.NET/Collections/ObjArray.cs
@@ -1,501 +1,501 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-using System.Runtime.InteropServices;
-
-namespace EcmaScript.NET.Collections
-{
-
- /// Implementation of resizable array with focus on minimizing memory usage by storing few initial array elements in object fields. Can also be used as a stack.
-
-
- public class ObjArray
- {
- virtual public bool Sealed
- {
- get
- {
- return zealed;
- }
-
- }
- virtual public bool Empty
- {
- get
- {
- return m_Size == 0;
- }
-
- }
- virtual public int Size
- {
- set
- {
- if (value < 0)
- throw new ArgumentException ();
- if (zealed)
- throw onSeledMutation ();
- int N = m_Size;
- if (value < N) {
- for (int i = value; i != N; ++i) {
- SetImpl (i, (object)null);
- }
- }
- else if (value > N) {
- if (value > FIELDS_STORE_SIZE) {
- ensureCapacity (value);
- }
- }
- m_Size = value;
- }
-
- }
-
- public ObjArray ()
- {
- }
-
- public void seal ()
- {
- zealed = true;
- }
-
- public int size ()
- {
- return m_Size;
- }
-
- public object Get (int index)
- {
- if (!(0 <= index && index < m_Size))
- throw onInvalidIndex (index, m_Size);
- return GetImpl (index);
- }
-
- public void Set (int index, object value)
- {
- if (!(0 <= index && index < m_Size))
- throw onInvalidIndex (index, m_Size);
- if (zealed)
- throw onSeledMutation ();
- SetImpl (index, value);
- }
-
- private object GetImpl (int index)
- {
- switch (index) {
-
- case 0:
- return f0;
-
- case 1:
- return f1;
-
- case 2:
- return f2;
-
- case 3:
- return f3;
-
- case 4:
- return f4;
- }
- return data [index - FIELDS_STORE_SIZE];
- }
-
- private void SetImpl (int index, object value)
- {
- switch (index) {
-
- case 0:
- f0 = value;
- break;
-
- case 1:
- f1 = value;
- break;
-
- case 2:
- f2 = value;
- break;
-
- case 3:
- f3 = value;
- break;
-
- case 4:
- f4 = value;
- break;
-
- default:
- data [index - FIELDS_STORE_SIZE] = value;
- break;
-
- }
- }
-
- public virtual int indexOf (object obj)
- {
- int N = m_Size;
- for (int i = 0; i != N; ++i) {
- object current = GetImpl (i);
- if (current == obj || (current != null && current.Equals (obj))) {
- return i;
- }
- }
- return -1;
- }
-
- public virtual int lastIndexOf (object obj)
- {
- for (int i = m_Size; i != 0; ) {
- --i;
- object current = GetImpl (i);
- if (current == obj || (current != null && current.Equals (obj))) {
- return i;
- }
- }
- return -1;
- }
-
- public object peek ()
- {
- int N = m_Size;
- if (N == 0)
- throw onEmptyStackTopRead ();
- return GetImpl (N - 1);
- }
-
- public object pop ()
- {
- if (zealed)
- throw onSeledMutation ();
- int N = m_Size;
- --N;
- object top;
- switch (N) {
-
- case -1:
- throw onEmptyStackTopRead ();
-
- case 0:
- top = f0;
- f0 = null;
- break;
-
- case 1:
- top = f1;
- f1 = null;
- break;
-
- case 2:
- top = f2;
- f2 = null;
- break;
-
- case 3:
- top = f3;
- f3 = null;
- break;
-
- case 4:
- top = f4;
- f4 = null;
- break;
-
- default:
- top = data [N - FIELDS_STORE_SIZE];
- data [N - FIELDS_STORE_SIZE] = null;
- break;
-
- }
- m_Size = N;
- return top;
- }
-
- public void push (object value)
- {
- add (value);
- }
-
- public void add (object value)
- {
- if (zealed)
- throw onSeledMutation ();
- int N = m_Size;
- if (N >= FIELDS_STORE_SIZE) {
- ensureCapacity (N + 1);
- }
- m_Size = N + 1;
- SetImpl (N, value);
- }
-
- public void add (int index, object value)
- {
- int N = m_Size;
- if (!(0 <= index && index <= N))
- throw onInvalidIndex (index, N + 1);
- if (zealed)
- throw onSeledMutation ();
- object tmp;
- switch (index) {
-
- case 0:
- if (N == 0) {
- f0 = value;
- break;
- }
- tmp = f0;
- f0 = value;
- value = tmp;
- goto case 1;
-
- case 1:
- if (N == 1) {
- f1 = value;
- break;
- }
- tmp = f1;
- f1 = value;
- value = tmp;
- goto case 2;
-
- case 2:
- if (N == 2) {
- f2 = value;
- break;
- }
- tmp = f2;
- f2 = value;
- value = tmp;
- goto case 3;
-
- case 3:
- if (N == 3) {
- f3 = value;
- break;
- }
- tmp = f3;
- f3 = value;
- value = tmp;
- goto case 4;
-
- case 4:
- if (N == 4) {
- f4 = value;
- break;
- }
- tmp = f4;
- f4 = value;
- value = tmp;
-
- index = FIELDS_STORE_SIZE;
- goto default;
-
- default:
- ensureCapacity (N + 1);
- if (index != N) {
- Array.Copy (data, index - FIELDS_STORE_SIZE, data, index - FIELDS_STORE_SIZE + 1, N - index);
- }
- data [index - FIELDS_STORE_SIZE] = value;
- break;
-
- }
- m_Size = N + 1;
- }
-
- public void remove (int index)
- {
- int N = m_Size;
- if (!(0 <= index && index < N))
- throw onInvalidIndex (index, N);
- if (zealed)
- throw onSeledMutation ();
- --N;
- switch (index) {
-
- case 0:
- if (N == 0) {
- f0 = null;
- break;
- }
- f0 = f1;
- goto case 1;
-
- case 1:
- if (N == 1) {
- f1 = null;
- break;
- }
- f1 = f2;
- goto case 2;
-
- case 2:
- if (N == 2) {
- f2 = null;
- break;
- }
- f2 = f3;
- goto case 3;
-
- case 3:
- if (N == 3) {
- f3 = null;
- break;
- }
- f3 = f4;
- goto case 4;
-
- case 4:
- if (N == 4) {
- f4 = null;
- break;
- }
- f4 = data [0];
-
- index = FIELDS_STORE_SIZE;
- goto default;
-
- default:
- if (index != N) {
- Array.Copy (data, index - FIELDS_STORE_SIZE + 1, data, index - FIELDS_STORE_SIZE, N - index);
- }
- data [N - FIELDS_STORE_SIZE] = null;
- break;
-
- }
- m_Size = N;
- }
-
- public void clear ()
- {
- if (zealed)
- throw onSeledMutation ();
- int N = m_Size;
- for (int i = 0; i != N; ++i) {
- SetImpl (i, (object)null);
- }
- m_Size = 0;
- }
-
- public object [] ToArray ()
- {
- object [] array = new object [m_Size];
- ToArray (array, 0);
- return array;
- }
-
- public void ToArray (object [] array)
- {
- ToArray (array, 0);
- }
-
- public void ToArray (object [] array, int offset)
- {
- int N = m_Size;
- switch (N) {
-
- default:
- Array.Copy (data, 0, array, offset + FIELDS_STORE_SIZE, N - FIELDS_STORE_SIZE);
- goto case 5;
-
-
- case 5:
- array [offset + 4] = f4;
- goto case 4;
-
- case 4:
- array [offset + 3] = f3;
- goto case 3;
-
- case 3:
- array [offset + 2] = f2;
- goto case 2;
-
- case 2:
- array [offset + 1] = f1;
- goto case 1;
-
- case 1:
- array [offset + 0] = f0;
- goto case 0;
-
- case 0:
- break;
- }
- }
-
- private void ensureCapacity (int minimalCapacity)
- {
- int required = minimalCapacity - FIELDS_STORE_SIZE;
- if (required <= 0)
- throw new ArgumentException ();
- if (data == null) {
- int alloc = FIELDS_STORE_SIZE * 2;
- if (alloc < required) {
- alloc = required;
- }
- data = new object [alloc];
- }
- else {
- int alloc = data.Length;
- if (alloc < required) {
- if (alloc <= FIELDS_STORE_SIZE) {
- alloc = FIELDS_STORE_SIZE * 2;
- }
- else {
- alloc *= 2;
- }
- if (alloc < required) {
- alloc = required;
- }
- object [] tmp = new object [alloc];
- if (m_Size > FIELDS_STORE_SIZE) {
- Array.Copy (data, 0, tmp, 0, m_Size - FIELDS_STORE_SIZE);
- }
- data = tmp;
- }
- }
- }
-
- private static ApplicationException onInvalidIndex (int index, int upperBound)
- {
- // \u2209 is "NOT ELEMENT OF"
- string msg = index + " \u2209 [0, " + upperBound + ')';
- throw new System.IndexOutOfRangeException (msg);
- }
-
- private static ApplicationException onEmptyStackTopRead ()
- {
- throw new ApplicationException ("Empty stack");
- }
-
- private static ApplicationException onSeledMutation ()
- {
- throw new ApplicationException ("Attempt to modify sealed array");
- }
-
-
- // Number of data elements
- private int m_Size;
-
- private bool zealed;
-
- private const int FIELDS_STORE_SIZE = 5;
-
- private object f0, f1, f2, f3, f4;
-
- private object [] data;
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace EcmaScript.NET.Collections
+{
+
+ /// Implementation of resizable array with focus on minimizing memory usage by storing few initial array elements in object fields. Can also be used as a stack.
+
+
+ public class ObjArray
+ {
+ virtual public bool Sealed
+ {
+ get
+ {
+ return zealed;
+ }
+
+ }
+ virtual public bool Empty
+ {
+ get
+ {
+ return m_Size == 0;
+ }
+
+ }
+ virtual public int Size
+ {
+ set
+ {
+ if (value < 0)
+ throw new ArgumentException ();
+ if (zealed)
+ throw onSeledMutation ();
+ int N = m_Size;
+ if (value < N) {
+ for (int i = value; i != N; ++i) {
+ SetImpl (i, (object)null);
+ }
+ }
+ else if (value > N) {
+ if (value > FIELDS_STORE_SIZE) {
+ ensureCapacity (value);
+ }
+ }
+ m_Size = value;
+ }
+
+ }
+
+ public ObjArray ()
+ {
+ }
+
+ public void seal ()
+ {
+ zealed = true;
+ }
+
+ public int size ()
+ {
+ return m_Size;
+ }
+
+ public object Get (int index)
+ {
+ if (!(0 <= index && index < m_Size))
+ throw onInvalidIndex (index, m_Size);
+ return GetImpl (index);
+ }
+
+ public void Set (int index, object value)
+ {
+ if (!(0 <= index && index < m_Size))
+ throw onInvalidIndex (index, m_Size);
+ if (zealed)
+ throw onSeledMutation ();
+ SetImpl (index, value);
+ }
+
+ private object GetImpl (int index)
+ {
+ switch (index) {
+
+ case 0:
+ return f0;
+
+ case 1:
+ return f1;
+
+ case 2:
+ return f2;
+
+ case 3:
+ return f3;
+
+ case 4:
+ return f4;
+ }
+ return data [index - FIELDS_STORE_SIZE];
+ }
+
+ private void SetImpl (int index, object value)
+ {
+ switch (index) {
+
+ case 0:
+ f0 = value;
+ break;
+
+ case 1:
+ f1 = value;
+ break;
+
+ case 2:
+ f2 = value;
+ break;
+
+ case 3:
+ f3 = value;
+ break;
+
+ case 4:
+ f4 = value;
+ break;
+
+ default:
+ data [index - FIELDS_STORE_SIZE] = value;
+ break;
+
+ }
+ }
+
+ public virtual int indexOf (object obj)
+ {
+ int N = m_Size;
+ for (int i = 0; i != N; ++i) {
+ object current = GetImpl (i);
+ if (current == obj || (current != null && current.Equals (obj))) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public virtual int lastIndexOf (object obj)
+ {
+ for (int i = m_Size; i != 0; ) {
+ --i;
+ object current = GetImpl (i);
+ if (current == obj || (current != null && current.Equals (obj))) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public object peek ()
+ {
+ int N = m_Size;
+ if (N == 0)
+ throw onEmptyStackTopRead ();
+ return GetImpl (N - 1);
+ }
+
+ public object pop ()
+ {
+ if (zealed)
+ throw onSeledMutation ();
+ int N = m_Size;
+ --N;
+ object top;
+ switch (N) {
+
+ case -1:
+ throw onEmptyStackTopRead ();
+
+ case 0:
+ top = f0;
+ f0 = null;
+ break;
+
+ case 1:
+ top = f1;
+ f1 = null;
+ break;
+
+ case 2:
+ top = f2;
+ f2 = null;
+ break;
+
+ case 3:
+ top = f3;
+ f3 = null;
+ break;
+
+ case 4:
+ top = f4;
+ f4 = null;
+ break;
+
+ default:
+ top = data [N - FIELDS_STORE_SIZE];
+ data [N - FIELDS_STORE_SIZE] = null;
+ break;
+
+ }
+ m_Size = N;
+ return top;
+ }
+
+ public void push (object value)
+ {
+ add (value);
+ }
+
+ public void add (object value)
+ {
+ if (zealed)
+ throw onSeledMutation ();
+ int N = m_Size;
+ if (N >= FIELDS_STORE_SIZE) {
+ ensureCapacity (N + 1);
+ }
+ m_Size = N + 1;
+ SetImpl (N, value);
+ }
+
+ public void add (int index, object value)
+ {
+ int N = m_Size;
+ if (!(0 <= index && index <= N))
+ throw onInvalidIndex (index, N + 1);
+ if (zealed)
+ throw onSeledMutation ();
+ object tmp;
+ switch (index) {
+
+ case 0:
+ if (N == 0) {
+ f0 = value;
+ break;
+ }
+ tmp = f0;
+ f0 = value;
+ value = tmp;
+ goto case 1;
+
+ case 1:
+ if (N == 1) {
+ f1 = value;
+ break;
+ }
+ tmp = f1;
+ f1 = value;
+ value = tmp;
+ goto case 2;
+
+ case 2:
+ if (N == 2) {
+ f2 = value;
+ break;
+ }
+ tmp = f2;
+ f2 = value;
+ value = tmp;
+ goto case 3;
+
+ case 3:
+ if (N == 3) {
+ f3 = value;
+ break;
+ }
+ tmp = f3;
+ f3 = value;
+ value = tmp;
+ goto case 4;
+
+ case 4:
+ if (N == 4) {
+ f4 = value;
+ break;
+ }
+ tmp = f4;
+ f4 = value;
+ value = tmp;
+
+ index = FIELDS_STORE_SIZE;
+ goto default;
+
+ default:
+ ensureCapacity (N + 1);
+ if (index != N) {
+ Array.Copy (data, index - FIELDS_STORE_SIZE, data, index - FIELDS_STORE_SIZE + 1, N - index);
+ }
+ data [index - FIELDS_STORE_SIZE] = value;
+ break;
+
+ }
+ m_Size = N + 1;
+ }
+
+ public void remove (int index)
+ {
+ int N = m_Size;
+ if (!(0 <= index && index < N))
+ throw onInvalidIndex (index, N);
+ if (zealed)
+ throw onSeledMutation ();
+ --N;
+ switch (index) {
+
+ case 0:
+ if (N == 0) {
+ f0 = null;
+ break;
+ }
+ f0 = f1;
+ goto case 1;
+
+ case 1:
+ if (N == 1) {
+ f1 = null;
+ break;
+ }
+ f1 = f2;
+ goto case 2;
+
+ case 2:
+ if (N == 2) {
+ f2 = null;
+ break;
+ }
+ f2 = f3;
+ goto case 3;
+
+ case 3:
+ if (N == 3) {
+ f3 = null;
+ break;
+ }
+ f3 = f4;
+ goto case 4;
+
+ case 4:
+ if (N == 4) {
+ f4 = null;
+ break;
+ }
+ f4 = data [0];
+
+ index = FIELDS_STORE_SIZE;
+ goto default;
+
+ default:
+ if (index != N) {
+ Array.Copy (data, index - FIELDS_STORE_SIZE + 1, data, index - FIELDS_STORE_SIZE, N - index);
+ }
+ data [N - FIELDS_STORE_SIZE] = null;
+ break;
+
+ }
+ m_Size = N;
+ }
+
+ public void clear ()
+ {
+ if (zealed)
+ throw onSeledMutation ();
+ int N = m_Size;
+ for (int i = 0; i != N; ++i) {
+ SetImpl (i, (object)null);
+ }
+ m_Size = 0;
+ }
+
+ public object [] ToArray ()
+ {
+ object [] array = new object [m_Size];
+ ToArray (array, 0);
+ return array;
+ }
+
+ public void ToArray (object [] array)
+ {
+ ToArray (array, 0);
+ }
+
+ public void ToArray (object [] array, int offset)
+ {
+ int N = m_Size;
+ switch (N) {
+
+ default:
+ Array.Copy (data, 0, array, offset + FIELDS_STORE_SIZE, N - FIELDS_STORE_SIZE);
+ goto case 5;
+
+
+ case 5:
+ array [offset + 4] = f4;
+ goto case 4;
+
+ case 4:
+ array [offset + 3] = f3;
+ goto case 3;
+
+ case 3:
+ array [offset + 2] = f2;
+ goto case 2;
+
+ case 2:
+ array [offset + 1] = f1;
+ goto case 1;
+
+ case 1:
+ array [offset + 0] = f0;
+ goto case 0;
+
+ case 0:
+ break;
+ }
+ }
+
+ private void ensureCapacity (int minimalCapacity)
+ {
+ int required = minimalCapacity - FIELDS_STORE_SIZE;
+ if (required <= 0)
+ throw new ArgumentException ();
+ if (data == null) {
+ int alloc = FIELDS_STORE_SIZE * 2;
+ if (alloc < required) {
+ alloc = required;
+ }
+ data = new object [alloc];
+ }
+ else {
+ int alloc = data.Length;
+ if (alloc < required) {
+ if (alloc <= FIELDS_STORE_SIZE) {
+ alloc = FIELDS_STORE_SIZE * 2;
+ }
+ else {
+ alloc *= 2;
+ }
+ if (alloc < required) {
+ alloc = required;
+ }
+ object [] tmp = new object [alloc];
+ if (m_Size > FIELDS_STORE_SIZE) {
+ Array.Copy (data, 0, tmp, 0, m_Size - FIELDS_STORE_SIZE);
+ }
+ data = tmp;
+ }
+ }
+ }
+
+ private static Exception onInvalidIndex (int index, int upperBound)
+ {
+ // \u2209 is "NOT ELEMENT OF"
+ string msg = index + " \u2209 [0, " + upperBound + ')';
+ throw new System.IndexOutOfRangeException (msg);
+ }
+
+ private static Exception onEmptyStackTopRead ()
+ {
+ throw new Exception ("Empty stack");
+ }
+
+ private static Exception onSeledMutation ()
+ {
+ throw new Exception ("Attempt to modify sealed array");
+ }
+
+
+ // Number of data elements
+ private int m_Size;
+
+ private bool zealed;
+
+ private const int FIELDS_STORE_SIZE = 5;
+
+ private object f0, f1, f2, f3, f4;
+
+ private object [] data;
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/Collections/ObjToIntMap.cs b/src/EcmaScript.NET/Collections/ObjToIntMap.cs
similarity index 97%
rename from Code/EcmaScript.NET/Collections/ObjToIntMap.cs
rename to src/EcmaScript.NET/Collections/ObjToIntMap.cs
index 7e3f60e..e42937f 100644
--- a/Code/EcmaScript.NET/Collections/ObjToIntMap.cs
+++ b/src/EcmaScript.NET/Collections/ObjToIntMap.cs
@@ -1,476 +1,476 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-using System.Runtime.InteropServices;
-
-
-namespace EcmaScript.NET.Collections
-{
-
- /// Map to associate objects to integers.
- /// The map does not synchronize any of its operation, so either use
- /// it from a single thread or do own synchronization or perform all mutation
- /// operations on one thread before passing the map to others
- ///
- ///
- public class ObjToIntMap
- {
- virtual public bool Empty
- {
- get
- {
- return keyCount == 0;
- }
-
- }
-
- // Map implementation via hashtable,
- // follows "The Art of Computer Programming" by Donald E. Knuth
-
- // ObjToIntMap is a copy cat of ObjToIntMap with API adjusted to object keys
-
- public class Iterator
- {
- virtual public object Key
- {
- get
- {
- object key = keys [cursor];
- if (key == UniqueTag.NullValue) {
- key = null;
- }
- return key;
- }
-
- }
- virtual public int Value
- {
- get
- {
- return values [cursor];
- }
-
- set
- {
- values [cursor] = value;
- }
-
- }
-
- internal Iterator (ObjToIntMap master)
- {
- this.master = master;
- }
-
- internal void Init (object [] keys, int [] values, int keyCount)
- {
- this.keys = keys;
- this.values = values;
- this.cursor = -1;
- this.remaining = keyCount;
- }
-
- public virtual void start ()
- {
- master.initIterator (this);
- next ();
- }
-
- public virtual bool done ()
- {
- return remaining < 0;
- }
-
- public virtual void next ()
- {
- if (remaining == -1)
- Context.CodeBug ();
- if (remaining == 0) {
- remaining = -1;
- cursor = -1;
- }
- else {
- for (++cursor; ; ++cursor) {
- object key = keys [cursor];
- if (key != null && key != ObjToIntMap.DELETED) {
- --remaining;
- break;
- }
- }
- }
- }
-
- internal ObjToIntMap master;
- private int cursor;
- private int remaining;
- private object [] keys;
- private int [] values;
- }
-
- public ObjToIntMap ()
- : this (4)
- {
- }
-
- public ObjToIntMap (int keyCountHint)
- {
- if (keyCountHint < 0)
- Context.CodeBug ();
- // Table grow when number of stored keys >= 3/4 of max capacity
- int minimalCapacity = keyCountHint * 4 / 3;
- int i;
- for (i = 2; (1 << i) < minimalCapacity; ++i) {
- }
- power = i;
- if (check && power < 2)
- Context.CodeBug ();
- }
-
- public virtual int size ()
- {
- return keyCount;
- }
-
- public virtual bool has (object key)
- {
- if (key == null) {
- key = UniqueTag.NullValue;
- }
- return 0 <= findIndex (key);
- }
-
- /// Get integer value assigned with key.
- /// key integer value or defaultValue if key is absent
- ///
- public virtual int Get (object key, int defaultValue)
- {
- if (key == null) {
- key = UniqueTag.NullValue;
- }
- int index = findIndex (key);
- if (0 <= index) {
- return values [index];
- }
- return defaultValue;
- }
-
- /// Get integer value assigned with key.
- /// key integer value
- ///
- /// RuntimeException if key does not exist
- public virtual int getExisting (object key)
- {
- if (key == null) {
- key = UniqueTag.NullValue;
- }
- int index = findIndex (key);
- if (0 <= index) {
- return values [index];
- }
- // Key must exist
- Context.CodeBug ();
- return 0;
- }
-
- public virtual void put (object key, int value)
- {
- if (key == null) {
- key = UniqueTag.NullValue;
- }
- int index = ensureIndex (key);
- values [index] = value;
- }
-
- /// If table already contains a key that equals to keyArg, return that key
- /// while setting its value to zero, otherwise add keyArg with 0 value to
- /// the table and return it.
- ///
- public virtual object intern (object keyArg)
- {
- bool nullKey = false;
- if (keyArg == null) {
- nullKey = true;
- keyArg = UniqueTag.NullValue;
- }
- int index = ensureIndex (keyArg);
- values [index] = 0;
- return (nullKey) ? null : keys [index];
- }
-
- public virtual void remove (object key)
- {
- if (key == null) {
- key = UniqueTag.NullValue;
- }
- int index = findIndex (key);
- if (0 <= index) {
- keys [index] = DELETED;
- --keyCount;
- }
- }
-
- public virtual void clear ()
- {
- int i = keys.Length;
- while (i != 0) {
- keys [--i] = null;
- }
- keyCount = 0;
- occupiedCount = 0;
- }
-
- public virtual Iterator newIterator ()
- {
- return new Iterator (this);
- }
-
- // The sole purpose of the method is to avoid accessing private fields
- // from the Iterator inner class to workaround JDK 1.1 compiler bug which
- // generates code triggering VerifierError on recent JVMs
- internal void initIterator (Iterator i)
- {
- i.Init (keys, values, keyCount);
- }
-
- /// Return array of present keys
- public virtual object [] getKeys ()
- {
- object [] array = new object [keyCount];
- getKeys (array, 0);
- return array;
- }
-
- public virtual void getKeys (object [] array, int offset)
- {
- int count = keyCount;
- for (int i = 0; count != 0; ++i) {
- object key = keys [i];
- if (key != null && key != DELETED) {
- if (key == UniqueTag.NullValue) {
- key = null;
- }
- array [offset] = key;
- ++offset;
- --count;
- }
- }
- }
-
- private static int tableLookupStep (int fraction, int mask, int power)
- {
- int shift = 32 - 2 * power;
- if (shift >= 0) {
- return ((int)(((uint)fraction >> shift)) & mask) | 1;
- }
- else {
- return (fraction & (int)((uint)mask >> -shift)) | 1;
- }
- }
-
- private int findIndex (object key)
- {
- if (keys != null) {
- int hash = key.GetHashCode ();
- int fraction = hash * A;
- int index = (int)((uint)fraction >> (32 - power));
- object test = keys [index];
- if (test != null) {
- int N = 1 << power;
- if (test == key || (values [N + index] == hash && test.Equals (key))) {
- return index;
- }
- // Search in table after first failed attempt
- int mask = N - 1;
- int step = tableLookupStep (fraction, mask, power);
- int n = 0;
- for (; ; ) {
- if (check) {
- if (n >= occupiedCount)
- Context.CodeBug ();
- ++n;
- }
- index = (index + step) & mask;
- test = keys [index];
- if (test == null) {
- break;
- }
- if (test == key || (values [N + index] == hash && test.Equals (key))) {
- return index;
- }
- }
- }
- }
- return -1;
- }
-
- // Insert key that is not present to table without deleted entries
- // and enough free space
- private int insertNewKey (object key, int hash)
- {
- if (check && occupiedCount != keyCount)
- Context.CodeBug ();
- if (check && keyCount == 1 << power)
- Context.CodeBug ();
- int fraction = hash * A;
- int index = (int)((uint)fraction >> (32 - power));
- int N = 1 << power;
- if (keys [index] != null) {
- int mask = N - 1;
- int step = tableLookupStep (fraction, mask, power);
- int firstIndex = index;
- do {
- if (check && keys [index] == DELETED)
- Context.CodeBug ();
- index = (index + step) & mask;
- if (check && firstIndex == index)
- Context.CodeBug ();
- }
- while (keys [index] != null);
- }
- keys [index] = key;
- values [N + index] = hash;
- ++occupiedCount;
- ++keyCount;
-
- return index;
- }
-
- private void rehashTable ()
- {
- if (keys == null) {
- if (check && keyCount != 0)
- Context.CodeBug ();
- if (check && occupiedCount != 0)
- Context.CodeBug ();
- int N = 1 << power;
- keys = new object [N];
- values = new int [2 * N];
- }
- else {
- // Check if removing deleted entries would free enough space
- if (keyCount * 2 >= occupiedCount) {
- // Need to grow: less then half of deleted entries
- ++power;
- }
- int N = 1 << power;
- object [] oldKeys = keys;
- int [] oldValues = values;
- int oldN = oldKeys.Length;
- keys = new object [N];
- values = new int [2 * N];
-
- int remaining = keyCount;
- occupiedCount = keyCount = 0;
- for (int i = 0; remaining != 0; ++i) {
- object key = oldKeys [i];
- if (key != null && key != DELETED) {
- int keyHash = oldValues [oldN + i];
- int index = insertNewKey (key, keyHash);
- values [index] = oldValues [i];
- --remaining;
- }
- }
- }
- }
-
- // Ensure key index creating one if necessary
- private int ensureIndex (object key)
- {
- int hash = key.GetHashCode ();
- int index = -1;
- int firstDeleted = -1;
- if (keys != null) {
- int fraction = hash * A;
- index = (int)((uint)fraction >> (32 - power));
- object test = keys [index];
- if (test != null) {
- int N = 1 << power;
- if (test == key || (values [N + index] == hash && test.Equals (key))) {
- return index;
- }
- if (test == DELETED) {
- firstDeleted = index;
- }
-
- // Search in table after first failed attempt
- int mask = N - 1;
- int step = tableLookupStep (fraction, mask, power);
- int n = 0;
- for (; ; ) {
- if (check) {
- if (n >= occupiedCount)
- Context.CodeBug ();
- ++n;
- }
- index = (index + step) & mask;
- test = keys [index];
- if (test == null) {
- break;
- }
- if (test == key || (values [N + index] == hash && test.Equals (key))) {
- return index;
- }
- if (test == DELETED && firstDeleted < 0) {
- firstDeleted = index;
- }
- }
- }
- }
- // Inserting of new key
- if (check && keys != null && keys [index] != null)
- Context.CodeBug ();
- if (firstDeleted >= 0) {
- index = firstDeleted;
- }
- else {
- // Need to consume empty entry: check occupation level
- if (keys == null || occupiedCount * 4 >= (1 << power) * 3) {
- // Too litle unused entries: rehash
- rehashTable ();
- return insertNewKey (key, hash);
- }
- ++occupiedCount;
- }
- keys [index] = key;
- values [(1 << power) + index] = hash;
- ++keyCount;
- return index;
- }
-
- // A == golden_ratio * (1 << 32) = ((sqrt(5) - 1) / 2) * (1 << 32)
- // See Knuth etc.
- private const int A = unchecked ((int)0x9e3779b9);
-
- private static readonly object DELETED = new object ();
-
- // Structure of kyes and values arrays (N == 1 << power):
- // keys[0 <= i < N]: key value or null or DELETED mark
- // values[0 <= i < N]: value of key at keys[i]
- // values[N <= i < 2*N]: hash code of key at keys[i-N]
-
-
- private object [] keys;
-
- private int [] values;
-
- private int power;
- private int keyCount;
-
- private int occupiedCount; // == keyCount + deleted_count
-
- // If true, enables consitency checks
- private static readonly bool check = false; // TODO: make me a preprocessor directive
-
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+using System.Runtime.InteropServices;
+
+
+namespace EcmaScript.NET.Collections
+{
+
+ /// Map to associate objects to integers.
+ /// The map does not synchronize any of its operation, so either use
+ /// it from a single thread or do own synchronization or perform all mutation
+ /// operations on one thread before passing the map to others
+ ///
+ ///
+ public class ObjToIntMap
+ {
+ virtual public bool Empty
+ {
+ get
+ {
+ return keyCount == 0;
+ }
+
+ }
+
+ // Map implementation via hashtable,
+ // follows "The Art of Computer Programming" by Donald E. Knuth
+
+ // ObjToIntMap is a copy cat of ObjToIntMap with API adjusted to object keys
+
+ public class Iterator
+ {
+ virtual public object Key
+ {
+ get
+ {
+ object key = keys [cursor];
+ if (key == UniqueTag.NullValue) {
+ key = null;
+ }
+ return key;
+ }
+
+ }
+ virtual public int Value
+ {
+ get
+ {
+ return values [cursor];
+ }
+
+ set
+ {
+ values [cursor] = value;
+ }
+
+ }
+
+ internal Iterator (ObjToIntMap master)
+ {
+ this.master = master;
+ }
+
+ internal void Init (object [] keys, int [] values, int keyCount)
+ {
+ this.keys = keys;
+ this.values = values;
+ this.cursor = -1;
+ this.remaining = keyCount;
+ }
+
+ public virtual void start ()
+ {
+ master.initIterator (this);
+ next ();
+ }
+
+ public virtual bool done ()
+ {
+ return remaining < 0;
+ }
+
+ public virtual void next ()
+ {
+ if (remaining == -1)
+ Context.CodeBug ();
+ if (remaining == 0) {
+ remaining = -1;
+ cursor = -1;
+ }
+ else {
+ for (++cursor; ; ++cursor) {
+ object key = keys [cursor];
+ if (key != null && key != ObjToIntMap.DELETED) {
+ --remaining;
+ break;
+ }
+ }
+ }
+ }
+
+ internal ObjToIntMap master;
+ private int cursor;
+ private int remaining;
+ private object [] keys;
+ private int [] values;
+ }
+
+ public ObjToIntMap ()
+ : this (4)
+ {
+ }
+
+ public ObjToIntMap (int keyCountHint)
+ {
+ if (keyCountHint < 0)
+ Context.CodeBug ();
+ // Table grow when number of stored keys >= 3/4 of max capacity
+ int minimalCapacity = keyCountHint * 4 / 3;
+ int i;
+ for (i = 2; (1 << i) < minimalCapacity; ++i) {
+ }
+ power = i;
+ if (check && power < 2)
+ Context.CodeBug ();
+ }
+
+ public virtual int size ()
+ {
+ return keyCount;
+ }
+
+ public virtual bool has (object key)
+ {
+ if (key == null) {
+ key = UniqueTag.NullValue;
+ }
+ return 0 <= findIndex (key);
+ }
+
+ /// Get integer value assigned with key.
+ /// key integer value or defaultValue if key is absent
+ ///
+ public virtual int Get (object key, int defaultValue)
+ {
+ if (key == null) {
+ key = UniqueTag.NullValue;
+ }
+ int index = findIndex (key);
+ if (0 <= index) {
+ return values [index];
+ }
+ return defaultValue;
+ }
+
+ /// Get integer value assigned with key.
+ /// key integer value
+ ///
+ /// RuntimeException if key does not exist
+ public virtual int getExisting (object key)
+ {
+ if (key == null) {
+ key = UniqueTag.NullValue;
+ }
+ int index = findIndex (key);
+ if (0 <= index) {
+ return values [index];
+ }
+ // Key must exist
+ Context.CodeBug ();
+ return 0;
+ }
+
+ public virtual void put (object key, int value)
+ {
+ if (key == null) {
+ key = UniqueTag.NullValue;
+ }
+ int index = ensureIndex (key);
+ values [index] = value;
+ }
+
+ /// If table already contains a key that equals to keyArg, return that key
+ /// while setting its value to zero, otherwise add keyArg with 0 value to
+ /// the table and return it.
+ ///
+ public virtual object intern (object keyArg)
+ {
+ bool nullKey = false;
+ if (keyArg == null) {
+ nullKey = true;
+ keyArg = UniqueTag.NullValue;
+ }
+ int index = ensureIndex (keyArg);
+ values [index] = 0;
+ return (nullKey) ? null : keys [index];
+ }
+
+ public virtual void remove (object key)
+ {
+ if (key == null) {
+ key = UniqueTag.NullValue;
+ }
+ int index = findIndex (key);
+ if (0 <= index) {
+ keys [index] = DELETED;
+ --keyCount;
+ }
+ }
+
+ public virtual void clear ()
+ {
+ int i = keys.Length;
+ while (i != 0) {
+ keys [--i] = null;
+ }
+ keyCount = 0;
+ occupiedCount = 0;
+ }
+
+ public virtual Iterator newIterator ()
+ {
+ return new Iterator (this);
+ }
+
+ // The sole purpose of the method is to avoid accessing private fields
+ // from the Iterator inner class to workaround JDK 1.1 compiler bug which
+ // generates code triggering VerifierError on recent JVMs
+ internal void initIterator (Iterator i)
+ {
+ i.Init (keys, values, keyCount);
+ }
+
+ /// Return array of present keys
+ public virtual object [] getKeys ()
+ {
+ object [] array = new object [keyCount];
+ getKeys (array, 0);
+ return array;
+ }
+
+ public virtual void getKeys (object [] array, int offset)
+ {
+ int count = keyCount;
+ for (int i = 0; count != 0; ++i) {
+ object key = keys [i];
+ if (key != null && key != DELETED) {
+ if (key == UniqueTag.NullValue) {
+ key = null;
+ }
+ array [offset] = key;
+ ++offset;
+ --count;
+ }
+ }
+ }
+
+ private static int tableLookupStep (int fraction, int mask, int power)
+ {
+ int shift = 32 - 2 * power;
+ if (shift >= 0) {
+ return ((int)(((uint)fraction >> shift)) & mask) | 1;
+ }
+ else {
+ return (fraction & (int)((uint)mask >> -shift)) | 1;
+ }
+ }
+
+ private int findIndex (object key)
+ {
+ if (keys != null) {
+ int hash = key.GetHashCode ();
+ int fraction = hash * A;
+ int index = (int)((uint)fraction >> (32 - power));
+ object test = keys [index];
+ if (test != null) {
+ int N = 1 << power;
+ if (test == key || (values [N + index] == hash && test.Equals (key))) {
+ return index;
+ }
+ // Search in table after first failed attempt
+ int mask = N - 1;
+ int step = tableLookupStep (fraction, mask, power);
+ int n = 0;
+ for (; ; ) {
+ if (check) {
+ if (n >= occupiedCount)
+ Context.CodeBug ();
+ ++n;
+ }
+ index = (index + step) & mask;
+ test = keys [index];
+ if (test == null) {
+ break;
+ }
+ if (test == key || (values [N + index] == hash && test.Equals (key))) {
+ return index;
+ }
+ }
+ }
+ }
+ return -1;
+ }
+
+ // Insert key that is not present to table without deleted entries
+ // and enough free space
+ private int insertNewKey (object key, int hash)
+ {
+ if (check && occupiedCount != keyCount)
+ Context.CodeBug ();
+ if (check && keyCount == 1 << power)
+ Context.CodeBug ();
+ int fraction = hash * A;
+ int index = (int)((uint)fraction >> (32 - power));
+ int N = 1 << power;
+ if (keys [index] != null) {
+ int mask = N - 1;
+ int step = tableLookupStep (fraction, mask, power);
+ int firstIndex = index;
+ do {
+ if (check && keys [index] == DELETED)
+ Context.CodeBug ();
+ index = (index + step) & mask;
+ if (check && firstIndex == index)
+ Context.CodeBug ();
+ }
+ while (keys [index] != null);
+ }
+ keys [index] = key;
+ values [N + index] = hash;
+ ++occupiedCount;
+ ++keyCount;
+
+ return index;
+ }
+
+ private void rehashTable ()
+ {
+ if (keys == null) {
+ if (check && keyCount != 0)
+ Context.CodeBug ();
+ if (check && occupiedCount != 0)
+ Context.CodeBug ();
+ int N = 1 << power;
+ keys = new object [N];
+ values = new int [2 * N];
+ }
+ else {
+ // Check if removing deleted entries would free enough space
+ if (keyCount * 2 >= occupiedCount) {
+ // Need to grow: less then half of deleted entries
+ ++power;
+ }
+ int N = 1 << power;
+ object [] oldKeys = keys;
+ int [] oldValues = values;
+ int oldN = oldKeys.Length;
+ keys = new object [N];
+ values = new int [2 * N];
+
+ int remaining = keyCount;
+ occupiedCount = keyCount = 0;
+ for (int i = 0; remaining != 0; ++i) {
+ object key = oldKeys [i];
+ if (key != null && key != DELETED) {
+ int keyHash = oldValues [oldN + i];
+ int index = insertNewKey (key, keyHash);
+ values [index] = oldValues [i];
+ --remaining;
+ }
+ }
+ }
+ }
+
+ // Ensure key index creating one if necessary
+ private int ensureIndex (object key)
+ {
+ int hash = key.GetHashCode ();
+ int index = -1;
+ int firstDeleted = -1;
+ if (keys != null) {
+ int fraction = hash * A;
+ index = (int)((uint)fraction >> (32 - power));
+ object test = keys [index];
+ if (test != null) {
+ int N = 1 << power;
+ if (test == key || (values [N + index] == hash && test.Equals (key))) {
+ return index;
+ }
+ if (test == DELETED) {
+ firstDeleted = index;
+ }
+
+ // Search in table after first failed attempt
+ int mask = N - 1;
+ int step = tableLookupStep (fraction, mask, power);
+ int n = 0;
+ for (; ; ) {
+ if (check) {
+ if (n >= occupiedCount)
+ Context.CodeBug ();
+ ++n;
+ }
+ index = (index + step) & mask;
+ test = keys [index];
+ if (test == null) {
+ break;
+ }
+ if (test == key || (values [N + index] == hash && test.Equals (key))) {
+ return index;
+ }
+ if (test == DELETED && firstDeleted < 0) {
+ firstDeleted = index;
+ }
+ }
+ }
+ }
+ // Inserting of new key
+ if (check && keys != null && keys [index] != null)
+ Context.CodeBug ();
+ if (firstDeleted >= 0) {
+ index = firstDeleted;
+ }
+ else {
+ // Need to consume empty entry: check occupation level
+ if (keys == null || occupiedCount * 4 >= (1 << power) * 3) {
+ // Too litle unused entries: rehash
+ rehashTable ();
+ return insertNewKey (key, hash);
+ }
+ ++occupiedCount;
+ }
+ keys [index] = key;
+ values [(1 << power) + index] = hash;
+ ++keyCount;
+ return index;
+ }
+
+ // A == golden_ratio * (1 << 32) = ((sqrt(5) - 1) / 2) * (1 << 32)
+ // See Knuth etc.
+ private const int A = unchecked ((int)0x9e3779b9);
+
+ private static readonly object DELETED = new object ();
+
+ // Structure of kyes and values arrays (N == 1 << power):
+ // keys[0 <= i < N]: key value or null or DELETED mark
+ // values[0 <= i < N]: value of key at keys[i]
+ // values[N <= i < 2*N]: hash code of key at keys[i-N]
+
+
+ private object [] keys;
+
+ private int [] values;
+
+ private int power;
+ private int keyCount;
+
+ private int occupiedCount; // == keyCount + deleted_count
+
+ // If true, enables consitency checks
+ private static readonly bool check = false; // TODO: make me a preprocessor directive
+
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/Collections/UintMap.cs b/src/EcmaScript.NET/Collections/UintMap.cs
similarity index 97%
rename from Code/EcmaScript.NET/Collections/UintMap.cs
rename to src/EcmaScript.NET/Collections/UintMap.cs
index 3f77b66..4f3360e 100644
--- a/Code/EcmaScript.NET/Collections/UintMap.cs
+++ b/src/EcmaScript.NET/Collections/UintMap.cs
@@ -1,428 +1,428 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-using System.Runtime.InteropServices;
-
-namespace EcmaScript.NET.Collections
-{
-
- /// Map to associate non-negative integers to objects or integers.
- /// The map does not synchronize any of its operation, so either use
- /// it from a single thread or do own synchronization or perform all mutation
- /// operations on one thread before passing the map to others.
- ///
- ///
-
- public class UintMap
- {
- virtual public bool Empty
- {
- get
- {
- return keyCount == 0;
- }
-
- }
- /// Return array of present keys
- virtual public int [] Keys
- {
- get
- {
- int [] keys = this.keys;
- int n = keyCount;
- int [] result = new int [n];
- for (int i = 0; n != 0; ++i) {
- int entry = keys [i];
- if (entry != EMPTY && entry != DELETED) {
- result [--n] = entry;
- }
- }
- return result;
- }
-
- }
-
- // Map implementation via hashtable,
- // follows "The Art of Computer Programming" by Donald E. Knuth
-
- public UintMap ()
- : this (4)
- {
- }
-
- public UintMap (int initialCapacity)
- {
- if (initialCapacity < 0)
- Context.CodeBug ();
- // Table grow when number of stored keys >= 3/4 of max capacity
- int minimalCapacity = initialCapacity * 4 / 3;
- int i;
- for (i = 2; (1 << i) < minimalCapacity; ++i) {
- }
- power = i;
- if (check && power < 2)
- Context.CodeBug ();
- }
-
- public virtual int size ()
- {
- return keyCount;
- }
-
- public virtual bool has (int key)
- {
- if (key < 0)
- Context.CodeBug ();
- return 0 <= findIndex (key);
- }
-
- /// Get object value assigned with key.
- /// key object value or null if key is absent
- ///
- public virtual object getObject (int key)
- {
- if (key < 0)
- Context.CodeBug ();
- if (values != null) {
- int index = findIndex (key);
- if (0 <= index) {
- return values [index];
- }
- }
- return null;
- }
-
- /// Get integer value assigned with key.
- /// key integer value or defaultValue if key is absent
- ///
- public virtual int getInt (int key, int defaultValue)
- {
- if (key < 0)
- Context.CodeBug ();
- int index = findIndex (key);
- if (0 <= index) {
- if (ivaluesShift != 0) {
- return keys [ivaluesShift + index];
- }
- return 0;
- }
- return defaultValue;
- }
-
- /// Get integer value assigned with key.
- /// key integer value or defaultValue if key does not exist or does
- /// not have int value
- ///
- /// RuntimeException if key does not exist
- public virtual int getExistingInt (int key)
- {
- if (key < 0)
- Context.CodeBug ();
- int index = findIndex (key);
- if (0 <= index) {
- if (ivaluesShift != 0) {
- return keys [ivaluesShift + index];
- }
- return 0;
- }
- // Key must exist
- Context.CodeBug ();
- return 0;
- }
-
- /// Set object value of the key.
- /// If key does not exist, also set its int value to 0.
- ///
- public virtual void put (int key, object value)
- {
- if (key < 0)
- Context.CodeBug ();
- int index = ensureIndex (key, false);
- if (values == null) {
- values = new object [1 << power];
- }
- values [index] = value;
- }
-
- /// Set int value of the key.
- /// If key does not exist, also set its object value to null.
- ///
- public virtual void put (int key, int value)
- {
- if (key < 0)
- Context.CodeBug ();
- int index = ensureIndex (key, true);
- if (ivaluesShift == 0) {
- int N = 1 << power;
- // keys.length can be N * 2 after clear which set ivaluesShift to 0
- if (keys.Length != N * 2) {
- int [] tmp = new int [N * 2];
- Array.Copy (keys, 0, tmp, 0, N);
- keys = tmp;
- }
- ivaluesShift = N;
- }
- keys [ivaluesShift + index] = value;
- }
-
- public virtual void remove (int key)
- {
- if (key < 0)
- Context.CodeBug ();
- int index = findIndex (key);
- if (0 <= index) {
- keys [index] = DELETED;
- --keyCount;
- // Allow to GC value and make sure that new key with the deleted
- // slot shall get proper default values
- if (values != null) {
- values [index] = null;
- }
- if (ivaluesShift != 0) {
- keys [ivaluesShift + index] = 0;
- }
- }
- }
-
- public virtual void clear ()
- {
- int N = 1 << power;
- if (keys != null) {
- for (int i = 0; i != N; ++i) {
- keys [i] = EMPTY;
- }
- if (values != null) {
- for (int i = 0; i != N; ++i) {
- values [i] = null;
- }
- }
- }
- ivaluesShift = 0;
- keyCount = 0;
- occupiedCount = 0;
- }
-
- private static int tableLookupStep (int fraction, int mask, int power)
- {
- int shift = 32 - 2 * power;
- if (shift >= 0) {
- return (((int)((uint)fraction >> shift)) & mask) | 1;
- }
- else {
- return (fraction & (int)((uint)mask >> -shift)) | 1;
- }
- }
-
- private int findIndex (int key)
- {
- int [] keys = this.keys;
- if (keys != null) {
- int fraction = key * A;
- int index = (int)((uint)fraction >> (32 - power));
- int entry = keys [index];
- if (entry == key) {
- return index;
- }
- if (entry != EMPTY) {
- // Search in table after first failed attempt
- int mask = (1 << power) - 1;
- int step = tableLookupStep (fraction, mask, power);
- int n = 0;
- do {
- if (check) {
- if (n >= occupiedCount)
- Context.CodeBug ();
- ++n;
- }
- index = (index + step) & mask;
- entry = keys [index];
- if (entry == key) {
- return index;
- }
- }
- while (entry != EMPTY);
- }
- }
- return -1;
- }
-
- // Insert key that is not present to table without deleted entries
- // and enough free space
- private int insertNewKey (int key)
- {
- if (check && occupiedCount != keyCount)
- Context.CodeBug ();
- if (check && keyCount == 1 << power)
- Context.CodeBug ();
- int [] keys = this.keys;
- int fraction = key * A;
- int index = (int)((uint)fraction >> (32 - power));
- if (keys [index] != EMPTY) {
- int mask = (1 << power) - 1;
- int step = tableLookupStep (fraction, mask, power);
- int firstIndex = index;
- do {
- if (check && keys [index] == DELETED)
- Context.CodeBug ();
- index = (index + step) & mask;
- if (check && firstIndex == index)
- Context.CodeBug ();
- }
- while (keys [index] != EMPTY);
- }
- keys [index] = key;
- ++occupiedCount;
- ++keyCount;
- return index;
- }
-
- private void rehashTable (bool ensureIntSpace)
- {
- if (keys != null) {
- // Check if removing deleted entries would free enough space
- if (keyCount * 2 >= occupiedCount) {
- // Need to grow: less then half of deleted entries
- ++power;
- }
- }
- int N = 1 << power;
- int [] old = keys;
- int oldShift = ivaluesShift;
- if (oldShift == 0 && !ensureIntSpace) {
- keys = new int [N];
- }
- else {
- ivaluesShift = N;
- keys = new int [N * 2];
- }
- for (int i = 0; i != N; ++i) {
- keys [i] = EMPTY;
- }
-
- object [] oldValues = values;
- if (oldValues != null) {
- values = new object [N];
- }
-
- int oldCount = keyCount;
- occupiedCount = 0;
- if (oldCount != 0) {
- keyCount = 0;
- for (int i = 0, remaining = oldCount; remaining != 0; ++i) {
- int key = old [i];
- if (key != EMPTY && key != DELETED) {
- int index = insertNewKey (key);
- if (oldValues != null) {
- values [index] = oldValues [i];
- }
- if (oldShift != 0) {
- keys [ivaluesShift + index] = old [oldShift + i];
- }
- --remaining;
- }
- }
- }
- }
-
- // Ensure key index creating one if necessary
- private int ensureIndex (int key, bool intType)
- {
- int index = -1;
- int firstDeleted = -1;
- int [] keys = this.keys;
- if (keys != null) {
- int fraction = key * A;
- index = (int)((uint)fraction >> (32 - power));
- int entry = keys [index];
- if (entry == key) {
- return index;
- }
- if (entry != EMPTY) {
- if (entry == DELETED) {
- firstDeleted = index;
- }
- // Search in table after first failed attempt
- int mask = (1 << power) - 1;
- int step = tableLookupStep (fraction, mask, power);
- int n = 0;
- do {
- if (check) {
- if (n >= occupiedCount)
- Context.CodeBug ();
- ++n;
- }
- index = (index + step) & mask;
- entry = keys [index];
- if (entry == key) {
- return index;
- }
- if (entry == DELETED && firstDeleted < 0) {
- firstDeleted = index;
- }
- }
- while (entry != EMPTY);
- }
- }
- // Inserting of new key
- if (check && keys != null && keys [index] != EMPTY)
- Context.CodeBug ();
- if (firstDeleted >= 0) {
- index = firstDeleted;
- }
- else {
- // Need to consume empty entry: check occupation level
- if (keys == null || occupiedCount * 4 >= (1 << power) * 3) {
- // Too litle unused entries: rehash
- rehashTable (intType);
- keys = this.keys;
- return insertNewKey (key);
- }
- ++occupiedCount;
- }
- keys [index] = key;
- ++keyCount;
- return index;
- }
- // A == golden_ratio * (1 << 32) = ((sqrt(5) - 1) / 2) * (1 << 32)
- // See Knuth etc.
- private const int A = unchecked ((int)0x9e3779b9);
-
- private const int EMPTY = -1;
- private const int DELETED = -2;
-
- // Structure of kyes and values arrays (N == 1 << power):
- // keys[0 <= i < N]: key value or EMPTY or DELETED mark
- // values[0 <= i < N]: value of key at keys[i]
- // keys[N <= i < 2N]: int values of keys at keys[i - N]
-
-
- private int [] keys;
-
- private object [] values;
-
- private int power;
- private int keyCount;
-
- private int occupiedCount; // == keyCount + deleted_count
-
- // If ivaluesShift != 0, keys[ivaluesShift + index] contains integer
- // values associated with keys
-
- private int ivaluesShift;
-
- // If true, enables consitency checks
- private static readonly bool check = false; // TODO: make me a preprocessor directive
-
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace EcmaScript.NET.Collections
+{
+
+ /// Map to associate non-negative integers to objects or integers.
+ /// The map does not synchronize any of its operation, so either use
+ /// it from a single thread or do own synchronization or perform all mutation
+ /// operations on one thread before passing the map to others.
+ ///
+ ///
+
+ public class UintMap
+ {
+ virtual public bool Empty
+ {
+ get
+ {
+ return keyCount == 0;
+ }
+
+ }
+ /// Return array of present keys
+ virtual public int [] Keys
+ {
+ get
+ {
+ int [] keys = this.keys;
+ int n = keyCount;
+ int [] result = new int [n];
+ for (int i = 0; n != 0; ++i) {
+ int entry = keys [i];
+ if (entry != EMPTY && entry != DELETED) {
+ result [--n] = entry;
+ }
+ }
+ return result;
+ }
+
+ }
+
+ // Map implementation via hashtable,
+ // follows "The Art of Computer Programming" by Donald E. Knuth
+
+ public UintMap ()
+ : this (4)
+ {
+ }
+
+ public UintMap (int initialCapacity)
+ {
+ if (initialCapacity < 0)
+ Context.CodeBug ();
+ // Table grow when number of stored keys >= 3/4 of max capacity
+ int minimalCapacity = initialCapacity * 4 / 3;
+ int i;
+ for (i = 2; (1 << i) < minimalCapacity; ++i) {
+ }
+ power = i;
+ if (check && power < 2)
+ Context.CodeBug ();
+ }
+
+ public virtual int size ()
+ {
+ return keyCount;
+ }
+
+ public virtual bool has (int key)
+ {
+ if (key < 0)
+ Context.CodeBug ();
+ return 0 <= findIndex (key);
+ }
+
+ /// Get object value assigned with key.
+ /// key object value or null if key is absent
+ ///
+ public virtual object getObject (int key)
+ {
+ if (key < 0)
+ Context.CodeBug ();
+ if (values != null) {
+ int index = findIndex (key);
+ if (0 <= index) {
+ return values [index];
+ }
+ }
+ return null;
+ }
+
+ /// Get integer value assigned with key.
+ /// key integer value or defaultValue if key is absent
+ ///
+ public virtual int getInt (int key, int defaultValue)
+ {
+ if (key < 0)
+ Context.CodeBug ();
+ int index = findIndex (key);
+ if (0 <= index) {
+ if (ivaluesShift != 0) {
+ return keys [ivaluesShift + index];
+ }
+ return 0;
+ }
+ return defaultValue;
+ }
+
+ /// Get integer value assigned with key.
+ /// key integer value or defaultValue if key does not exist or does
+ /// not have int value
+ ///
+ /// RuntimeException if key does not exist
+ public virtual int getExistingInt (int key)
+ {
+ if (key < 0)
+ Context.CodeBug ();
+ int index = findIndex (key);
+ if (0 <= index) {
+ if (ivaluesShift != 0) {
+ return keys [ivaluesShift + index];
+ }
+ return 0;
+ }
+ // Key must exist
+ Context.CodeBug ();
+ return 0;
+ }
+
+ /// Set object value of the key.
+ /// If key does not exist, also set its int value to 0.
+ ///
+ public virtual void put (int key, object value)
+ {
+ if (key < 0)
+ Context.CodeBug ();
+ int index = ensureIndex (key, false);
+ if (values == null) {
+ values = new object [1 << power];
+ }
+ values [index] = value;
+ }
+
+ /// Set int value of the key.
+ /// If key does not exist, also set its object value to null.
+ ///
+ public virtual void put (int key, int value)
+ {
+ if (key < 0)
+ Context.CodeBug ();
+ int index = ensureIndex (key, true);
+ if (ivaluesShift == 0) {
+ int N = 1 << power;
+ // keys.length can be N * 2 after clear which set ivaluesShift to 0
+ if (keys.Length != N * 2) {
+ int [] tmp = new int [N * 2];
+ Array.Copy (keys, 0, tmp, 0, N);
+ keys = tmp;
+ }
+ ivaluesShift = N;
+ }
+ keys [ivaluesShift + index] = value;
+ }
+
+ public virtual void remove (int key)
+ {
+ if (key < 0)
+ Context.CodeBug ();
+ int index = findIndex (key);
+ if (0 <= index) {
+ keys [index] = DELETED;
+ --keyCount;
+ // Allow to GC value and make sure that new key with the deleted
+ // slot shall get proper default values
+ if (values != null) {
+ values [index] = null;
+ }
+ if (ivaluesShift != 0) {
+ keys [ivaluesShift + index] = 0;
+ }
+ }
+ }
+
+ public virtual void clear ()
+ {
+ int N = 1 << power;
+ if (keys != null) {
+ for (int i = 0; i != N; ++i) {
+ keys [i] = EMPTY;
+ }
+ if (values != null) {
+ for (int i = 0; i != N; ++i) {
+ values [i] = null;
+ }
+ }
+ }
+ ivaluesShift = 0;
+ keyCount = 0;
+ occupiedCount = 0;
+ }
+
+ private static int tableLookupStep (int fraction, int mask, int power)
+ {
+ int shift = 32 - 2 * power;
+ if (shift >= 0) {
+ return (((int)((uint)fraction >> shift)) & mask) | 1;
+ }
+ else {
+ return (fraction & (int)((uint)mask >> -shift)) | 1;
+ }
+ }
+
+ private int findIndex (int key)
+ {
+ int [] keys = this.keys;
+ if (keys != null) {
+ int fraction = key * A;
+ int index = (int)((uint)fraction >> (32 - power));
+ int entry = keys [index];
+ if (entry == key) {
+ return index;
+ }
+ if (entry != EMPTY) {
+ // Search in table after first failed attempt
+ int mask = (1 << power) - 1;
+ int step = tableLookupStep (fraction, mask, power);
+ int n = 0;
+ do {
+ if (check) {
+ if (n >= occupiedCount)
+ Context.CodeBug ();
+ ++n;
+ }
+ index = (index + step) & mask;
+ entry = keys [index];
+ if (entry == key) {
+ return index;
+ }
+ }
+ while (entry != EMPTY);
+ }
+ }
+ return -1;
+ }
+
+ // Insert key that is not present to table without deleted entries
+ // and enough free space
+ private int insertNewKey (int key)
+ {
+ if (check && occupiedCount != keyCount)
+ Context.CodeBug ();
+ if (check && keyCount == 1 << power)
+ Context.CodeBug ();
+ int [] keys = this.keys;
+ int fraction = key * A;
+ int index = (int)((uint)fraction >> (32 - power));
+ if (keys [index] != EMPTY) {
+ int mask = (1 << power) - 1;
+ int step = tableLookupStep (fraction, mask, power);
+ int firstIndex = index;
+ do {
+ if (check && keys [index] == DELETED)
+ Context.CodeBug ();
+ index = (index + step) & mask;
+ if (check && firstIndex == index)
+ Context.CodeBug ();
+ }
+ while (keys [index] != EMPTY);
+ }
+ keys [index] = key;
+ ++occupiedCount;
+ ++keyCount;
+ return index;
+ }
+
+ private void rehashTable (bool ensureIntSpace)
+ {
+ if (keys != null) {
+ // Check if removing deleted entries would free enough space
+ if (keyCount * 2 >= occupiedCount) {
+ // Need to grow: less then half of deleted entries
+ ++power;
+ }
+ }
+ int N = 1 << power;
+ int [] old = keys;
+ int oldShift = ivaluesShift;
+ if (oldShift == 0 && !ensureIntSpace) {
+ keys = new int [N];
+ }
+ else {
+ ivaluesShift = N;
+ keys = new int [N * 2];
+ }
+ for (int i = 0; i != N; ++i) {
+ keys [i] = EMPTY;
+ }
+
+ object [] oldValues = values;
+ if (oldValues != null) {
+ values = new object [N];
+ }
+
+ int oldCount = keyCount;
+ occupiedCount = 0;
+ if (oldCount != 0) {
+ keyCount = 0;
+ for (int i = 0, remaining = oldCount; remaining != 0; ++i) {
+ int key = old [i];
+ if (key != EMPTY && key != DELETED) {
+ int index = insertNewKey (key);
+ if (oldValues != null) {
+ values [index] = oldValues [i];
+ }
+ if (oldShift != 0) {
+ keys [ivaluesShift + index] = old [oldShift + i];
+ }
+ --remaining;
+ }
+ }
+ }
+ }
+
+ // Ensure key index creating one if necessary
+ private int ensureIndex (int key, bool intType)
+ {
+ int index = -1;
+ int firstDeleted = -1;
+ int [] keys = this.keys;
+ if (keys != null) {
+ int fraction = key * A;
+ index = (int)((uint)fraction >> (32 - power));
+ int entry = keys [index];
+ if (entry == key) {
+ return index;
+ }
+ if (entry != EMPTY) {
+ if (entry == DELETED) {
+ firstDeleted = index;
+ }
+ // Search in table after first failed attempt
+ int mask = (1 << power) - 1;
+ int step = tableLookupStep (fraction, mask, power);
+ int n = 0;
+ do {
+ if (check) {
+ if (n >= occupiedCount)
+ Context.CodeBug ();
+ ++n;
+ }
+ index = (index + step) & mask;
+ entry = keys [index];
+ if (entry == key) {
+ return index;
+ }
+ if (entry == DELETED && firstDeleted < 0) {
+ firstDeleted = index;
+ }
+ }
+ while (entry != EMPTY);
+ }
+ }
+ // Inserting of new key
+ if (check && keys != null && keys [index] != EMPTY)
+ Context.CodeBug ();
+ if (firstDeleted >= 0) {
+ index = firstDeleted;
+ }
+ else {
+ // Need to consume empty entry: check occupation level
+ if (keys == null || occupiedCount * 4 >= (1 << power) * 3) {
+ // Too litle unused entries: rehash
+ rehashTable (intType);
+ keys = this.keys;
+ return insertNewKey (key);
+ }
+ ++occupiedCount;
+ }
+ keys [index] = key;
+ ++keyCount;
+ return index;
+ }
+ // A == golden_ratio * (1 << 32) = ((sqrt(5) - 1) / 2) * (1 << 32)
+ // See Knuth etc.
+ private const int A = unchecked ((int)0x9e3779b9);
+
+ private const int EMPTY = -1;
+ private const int DELETED = -2;
+
+ // Structure of kyes and values arrays (N == 1 << power):
+ // keys[0 <= i < N]: key value or EMPTY or DELETED mark
+ // values[0 <= i < N]: value of key at keys[i]
+ // keys[N <= i < 2N]: int values of keys at keys[i - N]
+
+
+ private int [] keys;
+
+ private object [] values;
+
+ private int power;
+ private int keyCount;
+
+ private int occupiedCount; // == keyCount + deleted_count
+
+ // If ivaluesShift != 0, keys[ivaluesShift + index] contains integer
+ // values associated with keys
+
+ private int ivaluesShift;
+
+ // If true, enables consitency checks
+ private static readonly bool check = false; // TODO: make me a preprocessor directive
+
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/CompilerEnvirons.cs b/src/EcmaScript.NET/CompilerEnvirons.cs
similarity index 96%
rename from Code/EcmaScript.NET/CompilerEnvirons.cs
rename to src/EcmaScript.NET/CompilerEnvirons.cs
index 4894638..9e376ff 100644
--- a/Code/EcmaScript.NET/CompilerEnvirons.cs
+++ b/src/EcmaScript.NET/CompilerEnvirons.cs
@@ -1,166 +1,166 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-using System.Collections;
-
-namespace EcmaScript.NET
-{
-
- public class CompilerEnvirons
- {
- virtual public bool UseDynamicScope
- {
- get
- {
- return useDynamicScope;
- }
-
- }
- public CompilerEnvirons ()
- {
- errorReporter = DefaultErrorReporter.instance;
- languageVersion = Context.Versions.Default;
- generateDebugInfo = true;
- useDynamicScope = false;
- reservedKeywordAsIdentifier = false;
- allowMemberExprAsFunctionName = false;
- xmlAvailable = true;
- optimizationLevel = 0;
- generatingSource = true;
- }
-
- public virtual void initFromContext (Context cx)
- {
- setErrorReporter (cx.ErrorReporter);
- this.languageVersion = cx.Version;
- useDynamicScope = cx.compileFunctionsWithDynamicScopeFlag;
- generateDebugInfo = (!cx.GeneratingDebugChanged || cx.GeneratingDebug);
- reservedKeywordAsIdentifier = cx.HasFeature (Context.Features.ReservedKeywordAsIdentifier);
- allowMemberExprAsFunctionName = cx.HasFeature (Context.Features.MemberExprAsFunctionName);
- xmlAvailable = cx.HasFeature (Context.Features.E4x);
- getterAndSetterSupport = cx.HasFeature (Context.Features.GetterAndSetter);
-
- optimizationLevel = cx.OptimizationLevel;
-
- generatingSource = cx.GeneratingSource;
- activationNames = cx.activationNames;
- }
-
- public ErrorReporter getErrorReporter ()
- {
- return errorReporter;
- }
-
- public virtual void setErrorReporter (ErrorReporter errorReporter)
- {
- if (errorReporter == null)
- throw new ArgumentException ();
- this.errorReporter = errorReporter;
- }
-
- public Context.Versions LanguageVersion
- {
- get
- {
- return languageVersion;
- }
- set
- {
- languageVersion = value;
- }
- }
-
- public bool isGenerateDebugInfo ()
- {
- return generateDebugInfo;
- }
-
- public virtual void setGenerateDebugInfo (bool flag)
- {
- this.generateDebugInfo = flag;
- }
-
- public bool isReservedKeywordAsIdentifier ()
- {
- return reservedKeywordAsIdentifier;
- }
-
- public virtual void setReservedKeywordAsIdentifier (bool flag)
- {
- reservedKeywordAsIdentifier = flag;
- }
-
- public bool isAllowMemberExprAsFunctionName ()
- {
- return allowMemberExprAsFunctionName;
- }
-
- public virtual void setAllowMemberExprAsFunctionName (bool flag)
- {
- allowMemberExprAsFunctionName = flag;
- }
-
- public bool isXmlAvailable ()
- {
- return xmlAvailable;
- }
-
- public virtual void setXmlAvailable (bool flag)
- {
- xmlAvailable = flag;
- }
-
- public int getOptimizationLevel ()
- {
- return optimizationLevel;
- }
-
- public virtual void setOptimizationLevel (int level)
- {
- Context.CheckOptimizationLevel (level);
- this.optimizationLevel = level;
- }
-
- public bool isGeneratingSource ()
- {
- return generatingSource;
- }
-
- /// Specify whether or not source information should be generated.
- ///
- /// Without source information, evaluating the "toString" method
- /// on JavaScript functions produces only "[native code]" for
- /// the body of the function.
- /// Note that code generated without source is not fully ECMA
- /// conformant.
- ///
- public virtual void setGeneratingSource (bool generatingSource)
- {
- this.generatingSource = generatingSource;
- }
-
- private ErrorReporter errorReporter;
-
- private Context.Versions languageVersion;
- private bool generateDebugInfo;
- private bool useDynamicScope;
- private bool reservedKeywordAsIdentifier;
- private bool allowMemberExprAsFunctionName;
- private bool xmlAvailable;
- private int optimizationLevel;
- private bool generatingSource;
- internal Hashtable activationNames;
- internal bool getterAndSetterSupport;
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+using System.Collections;
+
+namespace EcmaScript.NET
+{
+
+ public class CompilerEnvirons
+ {
+ virtual public bool UseDynamicScope
+ {
+ get
+ {
+ return useDynamicScope;
+ }
+
+ }
+ public CompilerEnvirons ()
+ {
+ errorReporter = DefaultErrorReporter.instance;
+ languageVersion = Context.Versions.Default;
+ generateDebugInfo = true;
+ useDynamicScope = false;
+ reservedKeywordAsIdentifier = false;
+ allowMemberExprAsFunctionName = false;
+ xmlAvailable = true;
+ optimizationLevel = 0;
+ generatingSource = true;
+ }
+
+ public virtual void initFromContext (Context cx)
+ {
+ setErrorReporter (cx.ErrorReporter);
+ this.languageVersion = cx.Version;
+ useDynamicScope = cx.compileFunctionsWithDynamicScopeFlag;
+ generateDebugInfo = (!cx.GeneratingDebugChanged || cx.GeneratingDebug);
+ reservedKeywordAsIdentifier = cx.HasFeature (Context.Features.ReservedKeywordAsIdentifier);
+ allowMemberExprAsFunctionName = cx.HasFeature (Context.Features.MemberExprAsFunctionName);
+ xmlAvailable = cx.HasFeature (Context.Features.E4x);
+ getterAndSetterSupport = cx.HasFeature (Context.Features.GetterAndSetter);
+
+ optimizationLevel = cx.OptimizationLevel;
+
+ generatingSource = cx.GeneratingSource;
+ activationNames = cx.activationNames;
+ }
+
+ public ErrorReporter getErrorReporter ()
+ {
+ return errorReporter;
+ }
+
+ public virtual void setErrorReporter (ErrorReporter errorReporter)
+ {
+ if (errorReporter == null)
+ throw new ArgumentException ();
+ this.errorReporter = errorReporter;
+ }
+
+ public Context.Versions LanguageVersion
+ {
+ get
+ {
+ return languageVersion;
+ }
+ set
+ {
+ languageVersion = value;
+ }
+ }
+
+ public bool isGenerateDebugInfo ()
+ {
+ return generateDebugInfo;
+ }
+
+ public virtual void setGenerateDebugInfo (bool flag)
+ {
+ this.generateDebugInfo = flag;
+ }
+
+ public bool isReservedKeywordAsIdentifier ()
+ {
+ return reservedKeywordAsIdentifier;
+ }
+
+ public virtual void setReservedKeywordAsIdentifier (bool flag)
+ {
+ reservedKeywordAsIdentifier = flag;
+ }
+
+ public bool isAllowMemberExprAsFunctionName ()
+ {
+ return allowMemberExprAsFunctionName;
+ }
+
+ public virtual void setAllowMemberExprAsFunctionName (bool flag)
+ {
+ allowMemberExprAsFunctionName = flag;
+ }
+
+ public bool isXmlAvailable ()
+ {
+ return xmlAvailable;
+ }
+
+ public virtual void setXmlAvailable (bool flag)
+ {
+ xmlAvailable = flag;
+ }
+
+ public int getOptimizationLevel ()
+ {
+ return optimizationLevel;
+ }
+
+ public virtual void setOptimizationLevel (int level)
+ {
+ Context.CheckOptimizationLevel (level);
+ this.optimizationLevel = level;
+ }
+
+ public bool isGeneratingSource ()
+ {
+ return generatingSource;
+ }
+
+ /// Specify whether or not source information should be generated.
+ ///
+ /// Without source information, evaluating the "toString" method
+ /// on JavaScript functions produces only "[native code]" for
+ /// the body of the function.
+ /// Note that code generated without source is not fully ECMA
+ /// conformant.
+ ///
+ public virtual void setGeneratingSource (bool generatingSource)
+ {
+ this.generatingSource = generatingSource;
+ }
+
+ private ErrorReporter errorReporter;
+
+ private Context.Versions languageVersion;
+ private bool generateDebugInfo;
+ private bool useDynamicScope;
+ private bool reservedKeywordAsIdentifier;
+ private bool allowMemberExprAsFunctionName;
+ private bool xmlAvailable;
+ private int optimizationLevel;
+ private bool generatingSource;
+ internal Hashtable activationNames;
+ internal bool getterAndSetterSupport;
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/Context.cs b/src/EcmaScript.NET/Context.cs
similarity index 96%
rename from Code/EcmaScript.NET/Context.cs
rename to src/EcmaScript.NET/Context.cs
index 4d8432a..cc85274 100644
--- a/Code/EcmaScript.NET/Context.cs
+++ b/src/EcmaScript.NET/Context.cs
@@ -1,2013 +1,2013 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-using System.IO;
-using System.Threading;
-using System.Globalization;
-using System.Reflection;
-using System.Collections;
-
-using EcmaScript.NET.Debugging;
-using EcmaScript.NET.Collections;
-using EcmaScript.NET.Types;
-using EcmaScript.NET.Types.Cli;
-using EcmaScript.NET.Types.E4X;
-
-namespace EcmaScript.NET
-{
-
- ///
- /// This class represents the runtime context of an executing script.
- ///
- /// Before executing a script, an instance of Context must be created
- /// and associated with the thread that will be executing the script.
- /// The Context will be used to store information about the executing
- /// of the script such as the call stack. Contexts are associated with
- /// the current thread using the {@link #call(ContextAction)}
- /// or {@link #enter()} methods.
- ///
- /// Different forms of script execution are supported. Scripts may be
- /// evaluated from the source directly, or first compiled and then later
- /// executed. Interactive execution is also supported.
- ///
- /// Some aspects of script execution, such as type conversions and
- /// object creation, may be accessed directly through methods of
- /// Context.
- ///
- ///
- public class Context : IDisposable
- {
-
- public enum Features
- {
- ///
- /// No features at all
- ///
- None = 0,
-
- ///
- /// Support for E4X
- ///
- E4x = 1 << 1,
-
- ///
- /// Support for get and set
- ///
- GetterAndSetter = 1 << 2,
-
- ///
- ///
- ///
- NonEcmaGetYear = 1 << 3,
-
- /// Control if dynamic scope should be used for name access.
- /// If hasFeature(FEATURE_DYNAMIC_SCOPE) returns true, then the name lookup
- /// during name resolution will use the top scope of the script or function
- /// which is at the top of JS execution stack instead of the top scope of the
- /// script or function from the current stack frame if the top scope of
- /// the top stack frame contains the top scope of the current stack frame
- /// on its prototype chain.
- ///
- /// This is useful to define shared scope containing functions that can
- /// be called from scripts and functions using private scopes.
- ///
- /// By default {@link #hasFeature(int)} returns false.
- ///
- DynamicScope = 1 << 4,
- /// Control if member expression as function name extension is available.
- /// If hasFeature(FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME) returns
- /// true, allow function memberExpression(args) { body } to be
- /// syntax sugar for memberExpression = function(args) { body },
- /// when memberExpression is not a simple identifier.
- /// See ECMAScript-262, section 11.2 for definition of memberExpression.
- /// By default {@link #hasFeature(int)} returns false.
- ///
- MemberExprAsFunctionName = 1 << 5,
-
- /// Control if reserved keywords are treated as identifiers.
- /// If hasFeature(RESERVED_KEYWORD_AS_IDENTIFIER) returns true,
- /// treat future reserved keyword (see Ecma-262, section 7.5.3) as ordinary
- /// identifiers but warn about this usage.
- ///
- /// By default {@link #hasFeature(int)} returns false.
- ///
- ReservedKeywordAsIdentifier = 1 << 6,
-
- /// Control if toString() should returns the same result
- /// as toSource() when applied to objects and arrays.
- /// If hasFeature(FEATURE_TO_STRING_AS_SOURCE) returns true,
- /// calling toString() on JS objects gives the same result as
- /// calling toSource(). That is it returns JS source with code
- /// to create an object with all enumeratable fields of the original object
- /// instead of printing [object result of
- /// {@link Scriptable#getClassName()}].
- ///
- /// By default {@link #hasFeature(int)} returns true only if
- /// the current JS version is set to {@link #Versions.JS1_2}.
- ///
- ToStringAsSource = 1 << 7,
-
- /// Control if properties __proto__ and __parent__
- /// are treated specially.
- /// If hasFeature(FEATURE_PARENT_PROTO_PROPRTIES) returns true,
- /// treat __parent__ and __proto__ as special properties.
- ///
- /// The properties allow to query and set scope and prototype chains for the
- /// objects. The special meaning of the properties is available
- /// only when they are used as the right hand side of the dot operator.
- /// For example, while x.__proto__ = y changes the prototype
- /// chain of the object x to point to y,
- /// x["__proto__"] = y simply assigns a new value to the property
- /// __proto__ in x even when the feature is on.
- ///
- /// By default {@link #hasFeature(int)} returns true.
- ///
- ParentProtoProperties = 1 << 8,
-
- /// Control if strict variable mode is enabled.
- /// When the feature is on Rhino reports runtime errors if assignment
- /// to a global variable that does not exist is executed. When the feature
- /// is off such assignments creates new variable in the global scope as
- /// required by ECMA 262.
- ///
- /// By default {@link #hasFeature(int)} returns false.
- ///
- StrictVars = 1 << 9,
-
- /// Control if strict eval mode is enabled.
- /// When the feature is on Rhino reports runtime errors if non-string
- /// argument is passed to the eval function. When the feature is off
- /// eval simply return non-string argument as is without performing any
- /// evaluation as required by ECMA 262.
- ///
- /// By default {@link #hasFeature(int)} returns false.
- ///
- StrictEval = 1 << 10,
-
- ///
- /// Controls if the non-ecma function 'print' is available or not.
- ///
- NonEcmaPrintFunction = 1 << 11,
-
- ///
- /// Controls if the non-ecma function 'version' is available or not
- ///
- NonEcmaVersionFunction = 1 << 12,
-
- ///
- /// Controls if the non-ecma function 'options' is available or not
- ///
- NonEcmaOptionsFunction = 1 << 13,
-
- Strict = 1 << 14,
-
- ///
- /// Controls if the non-ecma function 'options' is available or not
- ///
- NonEcmaGcFunction = 1 << 14,
-
- ///
- /// The famous 'it' object (@see js.c:2315)
- ///
- NonEcmaItObject = 1 << 15,
-
- }
-
- public enum Versions
- {
- Unknown = -1,
- Default = 0,
- JS1_0 = 100,
- JS1_1 = 110,
- JS1_2 = 120,
- JS1_3 = 130,
- JS1_4 = 140,
- JS1_5 = 150,
- JS1_6 = 160
- }
-
- ///
- ///
- ///
- public event ContextWrapHandler OnWrap;
-
- private int m_MaximumInterpreterStackDepth = 8092;
-
- ///
- ///
- ///
- public int MaximumInterpreterStackDepth
- {
- get
- {
- return m_MaximumInterpreterStackDepth;
- }
- set
- {
- if (Sealed)
- OnSealedMutation ();
- m_MaximumInterpreterStackDepth = value;
- }
- }
-
- private AppDomain m_AppDomain = null;
-
- ///
- /// Associated app domain
- ///
- public AppDomain AppDomain
- {
- get { return m_AppDomain; }
- }
-
- private static LocalDataStoreSlot LocalSlot
- {
- get
- {
- LocalDataStoreSlot slot = Thread.GetNamedDataSlot ("Context");
- if (slot == null) {
- slot = Thread.AllocateNamedDataSlot ("Context");
- }
- return slot;
- }
- }
-
- /// Get the current Context.
- ///
- /// The current Context is per-thread; this method looks up
- /// the Context associated with the current thread.
- ///
- ///
- /// the Context associated with the current thread, or
- /// null if no context is associated with the current
- /// thread.
- ///
- public static Context CurrentContext
- {
- get
- {
- Context cx = (Context)Thread.GetData (LocalSlot);
- return cx;
- }
- }
-
- /// Return {@link ContextFactory} instance used to create this Context
- /// or the result of {@link ContextFactory#getGlobal()} if no factory
- /// was used for Context creation.
- ///
- public ContextFactory Factory
- {
- get
- {
- ContextFactory result = factory;
- if (result == null) {
- result = ContextFactory.Global;
- }
- return result;
- }
-
- }
- /// Checks if this is a sealed Context. A sealed Context instance does not
- /// allow to modify any of its properties and will throw an exception
- /// on any such attempt.
- ///
- public bool Sealed
- {
- get
- {
- return m_Sealed;
- }
-
- }
- /// Get the implementation version.
- ///
- ///
- /// The implementation version is of the form
- ///
- /// "name langVer release relNum date"
- ///
- /// where name is the name of the product, langVer is
- /// the language version, relNum is the release number, and
- /// date is the release date for that specific
- /// release in the form "yyyy mm dd".
- ///
- ///
- /// a string that encodes the product, language version, release
- /// number, and date.
- ///
- public string ImplementationVersion
- {
- get
- {
- // TODO: Probably it would be better to embed this directly into source
- // TODO: with special build preprocessing but that would require some ant
- // TODO: tweaking and then replacing token in resource files was simpler
- if (implementationVersion == null) {
- implementationVersion = ScriptRuntime.GetMessage ("implementation.version");
- }
- return implementationVersion;
- }
-
- }
- /// Get the singleton object that represents the JavaScript Undefined value.
- public static object UndefinedValue
- {
- get
- {
- return Undefined.Value;
- }
-
- }
- /// Specify whether or not debug information should be generated.
- ///
- /// Setting the generation of debug information on will set the
- /// optimization level to zero.
- ///
- public bool GeneratingDebug
- {
- get
- {
- return generatingDebug;
- }
-
- set
- {
- if (m_Sealed)
- OnSealedMutation ();
- generatingDebugChanged = true;
- if (value && OptimizationLevel > 0)
- OptimizationLevel = 0;
- this.generatingDebug = value;
- }
-
- }
-
- /// Specify whether or not source information should be generated.
- ///
- /// Without source information, evaluating the "toString" method
- /// on JavaScript functions produces only "[native code]" for
- /// the body of the function.
- /// Note that code generated without source is not fully ECMA
- /// conformant.
- ///
- public bool GeneratingSource
- {
- get
- {
- return generatingSource;
- }
- set
- {
- if (m_Sealed)
- OnSealedMutation ();
- this.generatingSource = value;
- }
-
- }
- /// Set the current optimization level.
- ///
- /// The optimization level is expected to be an integer between -1 and
- /// 9. Any negative values will be interpreted as -1, and any values
- /// greater than 9 will be interpreted as 9.
- /// An optimization level of -1 indicates that interpretive mode will
- /// always be used. Levels 0 through 9 indicate that class files may
- /// be generated. Higher optimization levels trade off compile time
- /// performance for runtime performance.
- /// The optimizer level can't be set greater than -1 if the optimizer
- /// package doesn't exist at run time.
- ///
- /// an integer indicating the level of
- /// optimization to perform
- ///
- public int OptimizationLevel
- {
- get
- {
- return m_OptimizationLevel;
- }
-
- set
- {
- if (m_Sealed)
- OnSealedMutation ();
- if (value == -2) {
- // To be compatible with Cocoon fork
- value = -1;
- }
- CheckOptimizationLevel (value);
- this.m_OptimizationLevel = value;
- }
-
- }
-
- /// Return the debugger context data associated with current context.
- /// the debugger data, or null if debugger is not attached
- ///
- public object DebuggerContextData
- {
- get
- {
- return debuggerData;
- }
-
- }
-
- public object Wrap (IScriptable scope, object obj, Type staticType)
- {
- if (obj == null || obj is IScriptable)
- return obj;
- if (staticType == null)
- staticType = obj.GetType ();
-
- if (staticType.IsArray)
- return new CliArray (scope, obj as Array);
-
- if (staticType.IsPrimitive)
- return obj;
-
- if (OnWrap != null) {
- ContextWrapEventArgs e = new ContextWrapEventArgs (this, scope, obj, staticType);
- OnWrap (this, e);
- obj = e.Target;
- }
-
- return new CliObject (obj);
- }
-
- /// Get/Set threshold of executed instructions counter that triggers call to
- /// observeInstructionCount().
- /// When the threshold is zero, instruction counting is disabled,
- /// otherwise each time the run-time executes at least the threshold value
- /// of script instructions, observeInstructionCount() will
- /// be called.
- ///
- public int InstructionObserverThreshold
- {
- get
- {
- return instructionThreshold;
- }
-
- set
- {
- if (m_Sealed)
- OnSealedMutation ();
- if (value < 0)
- throw new ArgumentException ();
- instructionThreshold = value;
- }
-
- }
-
- internal RegExpProxy RegExpProxy
- {
- get
- {
- if (regExpProxy == null) {
- regExpProxy = new Types.RegExp.RegExpImpl ();
- }
- return regExpProxy;
- }
- set {
- regExpProxy = value;
- }
- }
- internal bool VersionECMA1
- {
- get
- {
- return m_Version == Versions.Default || m_Version >= Versions.JS1_3;
- }
-
- }
- public bool GeneratingDebugChanged
- {
- get
- {
- return generatingDebugChanged;
- }
-
- }
- /// Language versions.
- ///
- /// All integral values are reserved for future version numbers.
- ///
-
-
-
-
-
-
-
-
-
-
-
- public const string languageVersionProperty = "language version";
- public const string errorReporterProperty = "error reporter";
-
- /// Convinient value to use as zero-length array of objects.
- public static readonly object [] EmptyArgs;
-
- /// Create a new Context.
- ///
- /// Note that the Context must be associated with a thread before
- /// it can be used to execute a script.
- ///
- ///
- public Context (AppDomain appDomain)
- {
- if (appDomain == null)
- throw new ArgumentNullException ("appDomain");
- Version = Versions.Default;
- m_AppDomain = appDomain;
- }
-
- /// Get a context associated with the current thread, creating
- /// one if need be.
- ///
- /// The Context stores the execution state of the JavaScript
- /// engine, so it is required that the context be entered
- /// before execution may begin. Once a thread has entered
- /// a Context, then getCurrentContext() may be called to find
- /// the context that is associated with the current thread.
- ///
- /// Calling enter() will
- /// return either the Context currently associated with the
- /// thread, or will create a new context and associate it
- /// with the current thread. Each call to enter()
- /// must have a matching call to exit(). For example,
- ///
- /// Context cx = Context.enter();
- /// try {
- /// ...
- /// cx.evaluateString(...);
- /// } finally {
- /// Context.exit();
- /// }
- ///
- /// Instead of using enter(), exit() pair consider using
- /// {@link #call(ContextAction)} which guarantees proper
- /// association of Context instances with the current thread and is faster.
- /// With this method the above example becomes:
- ///
- /// Context.call(new ContextAction() {
- /// public Object run(Context cx) {
- /// ...
- /// cx.evaluateString(...);
- /// return null;
- /// }
- /// });
- ///
- ///
- ///
- /// a Context associated with the current thread
- ///
- public static Context Enter ()
- {
- return Enter (null, AppDomain.CurrentDomain);
- }
-
- public static Context Enter (AppDomain appDomain)
- {
- return Enter (null, appDomain);
- }
-
- /// Get a Context associated with the current thread, using
- /// the given Context if need be.
- ///
- /// The same as enter() except that cx
- /// is associated with the current thread and returned if
- /// the current thread has no associated context and cx
- /// is not associated with any other thread.
- ///
- /// a Context to associate with the thread if possible
- ///
- /// a Context associated with the current thread
- ///
- ///
- public static Context Enter (Context cx)
- {
- return Enter (cx, AppDomain.CurrentDomain);
- }
-
- public static Context Enter (Context cx, AppDomain appDomain)
- {
- Context old = CurrentContext;
- if (old != null) {
- if (cx != null && cx != old && cx.enterCount != 0) {
- // The suplied context must be the context for
- // the current thread if it is already entered
- throw new ArgumentException ("Cannot enter Context active on another thread");
- }
- if (old.factory != null) {
- // Context with associated factory will be released
- // automatically and does not need to change enterCount
- return old;
- }
- if (old.m_Sealed)
- OnSealedMutation ();
- cx = old;
- }
- else {
- if (cx == null) {
- cx = new Context (appDomain);
- }
- else {
- if (cx.m_Sealed)
- OnSealedMutation ();
- }
- if (cx.enterCount != 0 || cx.factory != null) {
- throw new ApplicationException ();
- }
-
- if (!cx.creationEventWasSent) {
- cx.creationEventWasSent = true;
- ContextFactory.Global.FireOnContextCreated (cx);
- }
- }
-
- if (old == null) {
- Thread.SetData (LocalSlot, cx);
- }
- ++cx.enterCount;
-
- return cx;
- }
-
- /// Exit a block of code requiring a Context.
- ///
- /// Calling exit() will remove the association between
- /// the current thread and a Context if the prior call to
- /// enter() on this thread newly associated a Context
- /// with this thread.
- /// Once the current thread no longer has an associated Context,
- /// it cannot be used to execute JavaScript until it is again associated
- /// with a Context.
- ///
- ///
- public static void Exit ()
- {
- Context cx = CurrentContext;
- if (cx == null) {
- throw new ApplicationException ("Calling Context.exit without previous Context.enter");
- }
- if (cx.factory != null) {
- // Context with associated factory will be released
- // automatically and does not need to change enterCount
- return;
- }
- if (cx.enterCount < 1)
- Context.CodeBug ();
- if (cx.m_Sealed)
- OnSealedMutation ();
- --cx.enterCount;
- if (cx.enterCount == 0) {
- Thread.SetData (LocalSlot, null);
- ContextFactory.Global.FireOnContextReleased (cx);
- }
- }
-
-
- /// Call {@link
- /// Callable#call(Context cx, Scriptable scope, Scriptable thisObj,
- /// Object[] args)}
- /// using the Context instance associated with the current thread.
- /// If no Context is associated with the thread, then
- /// {@link ContextFactory#makeContext()} will be called to construct
- /// new Context instance. The instance will be temporary associated
- /// with the thread during call to {@link ContextAction#run(Context)}.
- ///
- /// It is allowed to use null for factory argument
- /// in which case the factory associated with the scope will be
- /// used to create new context instances.
- ///
- ///
- public static object Call (ContextFactory factory, ICallable callable, IScriptable scope, IScriptable thisObj, object [] args)
- {
- if (factory == null) {
- factory = ContextFactory.Global;
- }
-
- Context cx = CurrentContext;
- if (cx != null) {
- object result;
- if (cx.factory != null) {
- result = callable.Call (cx, scope, thisObj, args);
- }
- else {
- // Context was associated with the thread via Context.enter,
- // set factory to make Context.enter/exit to be no-op
- // during call
- cx.factory = factory;
- try {
- result = callable.Call (cx, scope, thisObj, args);
- }
- finally {
- cx.factory = null;
- }
- }
- return result;
- }
-
- cx = PrepareNewContext (AppDomain.CurrentDomain, factory);
- try {
- return callable.Call (cx, scope, thisObj, args);
- }
- finally {
- ReleaseContext (cx);
- }
- }
-
- internal void InitDefaultFeatures ()
- {
- m_Features = Features.None;
-
- SetFeature (Features.E4x, (Version == Context.Versions.Default || Version >= Context.Versions.JS1_6));
- SetFeature (Features.GetterAndSetter, (Version == Context.Versions.Default || Version >= Context.Versions.JS1_5));
- SetFeature (Features.NonEcmaGetYear, (Version == Context.Versions.JS1_0 || Version == Context.Versions.JS1_1 || Version == Context.Versions.JS1_2));
- SetFeature (Features.ToStringAsSource, Version == Context.Versions.JS1_2);
- SetFeature (Features.ParentProtoProperties, true);
- }
-
-
- private static Context PrepareNewContext (AppDomain appDomain, ContextFactory factory)
- {
- Context cx = new Context (appDomain);
- if (cx.factory != null || cx.enterCount != 0) {
- throw new ApplicationException ("factory.makeContext() returned Context instance already associated with some thread");
- }
- cx.factory = factory;
- factory.FireOnContextCreated (cx);
- if (factory.Sealed && !cx.Sealed) {
- cx.Seal ((object)null);
- }
- Thread.SetData (LocalSlot, cx);
- return cx;
- }
-
- private static void ReleaseContext (Context cx)
- {
- Thread.SetData (LocalSlot, null);
- try {
- cx.factory.FireOnContextReleased (cx);
- }
- finally {
- cx.factory = null;
- }
- }
-
-
-
- /// Seal this Context object so any attempt to modify any of its properties
- /// including calling {@link #enter()} and {@link #exit()} methods will
- /// throw an exception.
- ///
- /// If sealKey is not null, calling
- /// {@link #unseal(Object sealKey)} with the same key unseals
- /// the object. If sealKey is null, unsealing is no longer possible.
- ///
- ///
- public void Seal (object sealKey)
- {
- if (m_Sealed)
- OnSealedMutation ();
- m_Sealed = true;
- this.m_SealKey = sealKey;
- }
-
- /// Unseal previously sealed Context object.
- /// The sealKey argument should not be null and should match
- /// sealKey suplied with the last call to
- /// {@link #seal(Object)} or an exception will be thrown.
- ///
- ///
- public void Unseal (object sealKey)
- {
- if (sealKey == null)
- throw new ArgumentException ();
- if (this.m_SealKey != sealKey)
- throw new ArgumentException ();
- if (!m_Sealed)
- throw new ApplicationException ();
- m_Sealed = false;
- this.m_SealKey = null;
- }
-
- internal static void OnSealedMutation ()
- {
- throw new ApplicationException ();
- }
-
- ///
- /// Get the current language version.
- ///
- public Versions Version
- {
- get
- {
- return m_Version;
- }
- set
- {
- if (m_Sealed)
- OnSealedMutation ();
- this.m_Version = value;
-
- InitDefaultFeatures ();
- }
- }
-
- public static bool IsValidLanguageVersion (int version)
- {
- return ToValidLanguageVersion (version) != Versions.Unknown;
- }
-
- public static Versions ToValidLanguageVersion (int version)
- {
- Versions ver = Versions.Unknown;
- if (version > 0 || version < (int)Versions.JS1_6)
- ver = (Versions)version;
- return ver;
- }
-
- public static void CheckLanguageVersion (int version)
- {
- if (IsValidLanguageVersion (version)) {
- return;
- }
- throw new ArgumentException ("Bad language version: " + version);
- }
-
- /// Get the current error reporter.
- ///
- ///
- public ErrorReporter ErrorReporter
- {
- get
- {
- if (m_ErrorReporter == null) {
- return DefaultErrorReporter.instance;
- }
- return m_ErrorReporter;
- }
- set
- {
- if (m_Sealed)
- OnSealedMutation ();
- if (value == null)
- throw new ArgumentException ();
- this.m_ErrorReporter = value;
- }
- }
-
- ///
- /// Get the current locale. Returns the default locale if none has
- /// been set.
- ///
- public CultureInfo CurrentCulture
- {
- get
- {
- if (culture == null)
- culture = Thread.CurrentThread.CurrentCulture;
- return culture;
- }
- set
- {
- if (m_Sealed)
- OnSealedMutation ();
- culture = value;
-
- // HACK: Needed for example on DateTime.ToString()
- if (Thread.CurrentThread.CurrentCulture != culture)
- Thread.CurrentThread.CurrentCulture = culture;
- }
- }
-
- /// Report a warning using the error reporter for the current thread.
- ///
- ///
- /// the warning message to report
- ///
- /// a string describing the source, such as a filename
- ///
- /// the starting line number
- ///
- /// the text of the line (may be null)
- ///
- /// the offset into lineSource where problem was detected
- ///
-
- public static void ReportWarning (string message, string sourceName, int lineno, string lineSource, int lineOffset)
- {
- Context cx = Context.CurrentContext;
- cx.ErrorReporter.Warning (message, sourceName, lineno, lineSource, lineOffset);
- }
-
- public static void ReportWarningById (string messageId, params string [] arguments)
- {
- int [] linep = new int [] { 0 };
- string filename = GetSourcePositionFromStack (linep);
- Context.ReportWarning (ScriptRuntime.GetMessage (messageId, arguments), filename, linep [0], null, 0);
- }
-
- /// Report a warning using the error reporter for the current thread.
- ///
- ///
- /// the warning message to report
- ///
- public static void ReportWarning (string message)
- {
- int [] linep = new int [] { 0 };
- string filename = GetSourcePositionFromStack (linep);
- Context.ReportWarning (message, filename, linep [0], null, 0);
- }
-
- /// Report an error using the error reporter for the current thread.
- ///
- ///
- /// the error message to report
- ///
- /// a string describing the source, such as a filename
- ///
- /// the starting line number
- ///
- /// the text of the line (may be null)
- ///
- /// the offset into lineSource where problem was detected
- ///
- public static void ReportError (string message, string sourceName, int lineno, string lineSource, int lineOffset)
- {
- Context cx = CurrentContext;
- if (cx != null) {
- cx.ErrorReporter.Error (message, sourceName, lineno, lineSource, lineOffset);
- }
- else {
- throw new EcmaScriptRuntimeException (message, sourceName, lineno, lineSource, lineOffset);
- }
- }
-
- /// Report an error using the error reporter for the current thread.
- ///
- ///
- /// the error message to report
- ///
-
- public static void ReportError (string message)
- {
- int [] linep = new int [] { 0 };
- string filename = GetSourcePositionFromStack (linep);
- Context.ReportError (message, filename, linep [0], null, 0);
- }
-
- /// Report a runtime error using the error reporter for the current thread.
- ///
- ///
- /// the error message to report
- ///
- /// a string describing the source, such as a filename
- ///
- /// the starting line number
- ///
- /// the text of the line (may be null)
- ///
- /// the offset into lineSource where problem was detected
- ///
- /// a runtime exception that will be thrown to terminate the
- /// execution of the script
- ///
- public static EcmaScriptRuntimeException ReportRuntimeError (string message, string sourceName, int lineno, string lineSource, int lineOffset)
- {
- Context cx = CurrentContext;
- if (cx != null) {
- return cx.ErrorReporter.RuntimeError (message, sourceName, lineno, lineSource, lineOffset);
- }
- else {
- throw new EcmaScriptRuntimeException (message, sourceName, lineno, lineSource, lineOffset);
- }
- }
-
-
- internal static EcmaScriptRuntimeException ReportRuntimeErrorById (string messageId, params object [] args)
- {
- return ReportRuntimeError (ScriptRuntime.GetMessage (messageId, args));
- }
-
- /// Report a runtime error using the error reporter for the current thread.
- ///
- ///
- /// the error message to report
- ///
- public static EcmaScriptRuntimeException ReportRuntimeError (string message)
- {
- int [] linep = new int [] { 0 };
- string filename = GetSourcePositionFromStack (linep);
- return Context.ReportRuntimeError (message, filename, linep [0], null, 0);
- }
-
- /// Initialize the standard objects.
- ///
- /// Creates instances of the standard objects and their constructors
- /// (Object, String, Number, Date, etc.), setting up 'scope' to act
- /// as a global object as in ECMA 15.1.
- ///
- /// This method must be called to initialize a scope before scripts
- /// can be evaluated in that scope.
- ///
- /// This method does not affect the Context it is called upon.
- ///
- ///
- /// the initialized scope
- ///
- public ScriptableObject InitStandardObjects ()
- {
- return InitStandardObjects (null, false);
- }
-
- /// Initialize the standard objects.
- ///
- /// Creates instances of the standard objects and their constructors
- /// (Object, String, Number, Date, etc.), setting up 'scope' to act
- /// as a global object as in ECMA 15.1.
- ///
- /// This method must be called to initialize a scope before scripts
- /// can be evaluated in that scope.
- ///
- /// This method does not affect the Context it is called upon.
- ///
- ///
- /// the scope to initialize, or null, in which case a new
- /// object will be created to serve as the scope
- ///
- /// the initialized scope. The method returns the value of the scope
- /// argument if it is not null or newly allocated scope object which
- /// is an instance {@link ScriptableObject}.
- ///
- public IScriptable InitStandardObjects (ScriptableObject scope)
- {
- return InitStandardObjects (scope, false);
- }
-
- /// Initialize the standard objects.
- ///
- /// Creates instances of the standard objects and their constructors
- /// (Object, String, Number, Date, etc.), setting up 'scope' to act
- /// as a global object as in ECMA 15.1.
- ///
- /// This method must be called to initialize a scope before scripts
- /// can be evaluated in that scope.
- ///
- /// This method does not affect the Context it is called upon.
- ///
- /// This form of the method also allows for creating "sealed" standard
- /// objects. An object that is sealed cannot have properties added, changed,
- /// or removed. This is useful to create a "superglobal" that can be shared
- /// among several top-level objects. Note that sealing is not allowed in
- /// the current ECMA/ISO language specification, but is likely for
- /// the next version.
- ///
- ///
- /// the scope to initialize, or null, in which case a new
- /// object will be created to serve as the scope
- ///
- /// whether or not to create sealed standard objects that
- /// cannot be modified.
- ///
- /// the initialized scope. The method returns the value of the scope
- /// argument if it is not null or newly allocated scope object.
- ///
- public ScriptableObject InitStandardObjects (ScriptableObject scope, bool zealed)
- {
- return ScriptRuntime.InitStandardObjects (this, scope, zealed);
- }
-
- /// Evaluate a JavaScript source string.
- ///
- /// The provided source name and line number are used for error messages
- /// and for producing debug information.
- ///
- ///
- /// the scope to execute in
- ///
- /// the JavaScript source
- ///
- /// a string describing the source, such as a filename
- ///
- /// the starting line number
- ///
- /// an arbitrary object that specifies security
- /// information about the origin or owner of the script. For
- /// implementations that don't care about security, this value
- /// may be null.
- ///
- /// the result of evaluating the string
- ///
- public object EvaluateString (IScriptable scope, string source, string sourceName, int lineno, object securityDomain)
- {
- IScript script = CompileString (source, sourceName, lineno, securityDomain);
- if (script != null) {
- return script.Exec (this, scope);
- }
- else {
- return null;
- }
- }
-
- /// Evaluate a reader as JavaScript source.
- ///
- /// All characters of the reader are consumed.
- ///
- ///
- /// the scope to execute in
- ///
- /// the Reader to get JavaScript source from
- ///
- /// a string describing the source, such as a filename
- ///
- /// the starting line number
- ///
- /// an arbitrary object that specifies security
- /// information about the origin or owner of the script. For
- /// implementations that don't care about security, this value
- /// may be null.
- ///
- /// the result of evaluating the source
- ///
- ///
- /// IOException if an IOException was generated by the Reader
- ///
- public object EvaluateReader (IScriptable scope, StreamReader sr, string sourceName, int lineno, object securityDomain)
- {
- IScript script = CompileReader (sr, sourceName, lineno, securityDomain);
-
- if (script != null) {
- return script.Exec (this, scope);
- }
- return null;
- }
-
- /// Check whether a string is ready to be compiled.
- ///
- /// stringIsCompilableUnit is intended to support interactive compilation of
- /// javascript. If compiling the string would result in an error
- /// that might be fixed by appending more source, this method
- /// returns false. In every other case, it returns true.
- ///
- /// Interactive shells may accumulate source lines, using this
- /// method after each new line is appended to check whether the
- /// statement being entered is complete.
- ///
- ///
- /// the source buffer to check
- ///
- /// whether the source is ready for compilation
- ///
- public ScriptOrFnNode IsCompilableUnit (string source)
- {
- ScriptOrFnNode ret = null;
- bool errorseen = false;
- CompilerEnvirons compilerEnv = new CompilerEnvirons ();
- compilerEnv.initFromContext (this);
- // no source name or source text manager, because we're just
- // going to throw away the result.
- compilerEnv.setGeneratingSource (false);
- Parser p = new Parser (compilerEnv, DefaultErrorReporter.instance);
- try {
- ret = p.Parse (source, null, 1);
- }
- catch (EcmaScriptRuntimeException) {
- errorseen = true;
- }
- // Return false only if an error occurred as a result of reading past
- // the end of the file, i.e. if the source could be fixed by
- // appending more source.
- if (!(errorseen && p.Eof))
- return ret;
- return null;
- }
-
-
- /// Compiles the source in the given reader.
- ///
- /// Returns a script that may later be executed.
- /// Will consume all the source in the reader.
- ///
- ///
- /// the input reader
- ///
- /// a string describing the source, such as a filename
- ///
- /// the starting line number for reporting errors
- ///
- /// an arbitrary object that specifies security
- /// information about the origin or owner of the script. For
- /// implementations that don't care about security, this value
- /// may be null.
- ///
- /// a script that may later be executed
- ///
- /// IOException if an IOException was generated by the Reader
- ///
- public IScript CompileReader (StreamReader sr, string sourceName, int lineno, object securityDomain)
- {
- if (lineno < 0)
- throw new ArgumentException ("lineno may not be negative", "lineno");
- return (IScript)CompileImpl (null, sr, null, sourceName, lineno, securityDomain, false, null, null);
- }
-
- /// Compiles the source in the given string.
- ///
- /// Returns a script that may later be executed.
- ///
- ///
- /// the source string
- ///
- /// a string describing the source, such as a filename
- ///
- /// the starting line number for reporting errors
- ///
- /// an arbitrary object that specifies security
- /// information about the origin or owner of the script. For
- /// implementations that don't care about security, this value
- /// may be null.
- ///
- /// a script that may later be executed
- ///
- public IScript CompileString (string source, string sourceName, int lineno, object securityDomain)
- {
- if (lineno < 0) {
- // For compatibility IllegalArgumentException can not be thrown here
- lineno = 0;
- }
- return CompileString (source, null, null, sourceName, lineno, securityDomain);
- }
-
- internal IScript CompileString (string source, Interpreter compiler, ErrorReporter compilationErrorReporter, string sourceName, int lineno, object securityDomain)
- {
- return (IScript)CompileImpl (null, null, source, sourceName, lineno, securityDomain, false, compiler, compilationErrorReporter);
- }
-
- /// Compile a JavaScript function.
- ///
- /// The function source must be a function definition as defined by
- /// ECMA (e.g., "function f(a) { return a; }").
- ///
- ///
- /// the scope to compile relative to
- ///
- /// the function definition source
- ///
- /// a string describing the source, such as a filename
- ///
- /// the starting line number
- ///
- /// an arbitrary object that specifies security
- /// information about the origin or owner of the script. For
- /// implementations that don't care about security, this value
- /// may be null.
- ///
- /// a Function that may later be called
- ///
- public IFunction CompileFunction (IScriptable scope, string source, string sourceName, int lineno, object securityDomain)
- {
- return CompileFunction (scope, source, null, null, sourceName, lineno, securityDomain);
- }
-
- internal IFunction CompileFunction (IScriptable scope, string source, Interpreter compiler, ErrorReporter compilationErrorReporter, string sourceName, int lineno, object securityDomain)
- {
- return (IFunction)CompileImpl (scope, null, source, sourceName, lineno, securityDomain, true, compiler, compilationErrorReporter);
- }
-
- /// Decompile the script.
- ///
- /// The canonical source of the script is returned.
- ///
- ///
- /// the script to decompile
- ///
- /// the number of spaces to indent the result
- ///
- /// a string representing the script source
- ///
- public string DecompileScript (IScript script, int indent)
- {
- BuiltinFunction scriptImpl = (BuiltinFunction)script;
- return scriptImpl.Decompile (indent, 0);
- }
-
- /// Decompile a JavaScript Function.
- ///
- /// Decompiles a previously compiled JavaScript function object to
- /// canonical source.
- ///
- /// Returns function body of '[native code]' if no decompilation
- /// information is available.
- ///
- ///
- /// the JavaScript function to decompile
- ///
- /// the number of spaces to indent the result
- ///
- /// a string representing the function source
- ///
- public string DecompileFunction (IFunction fun, int indent)
- {
- if (fun is BaseFunction)
- return ((BaseFunction)fun).Decompile (indent, 0);
- else
- return "function " + fun.ClassName + "() {\n\t[native code]\n}\n";
- }
-
- /// Decompile the body of a JavaScript Function.
- ///
- /// Decompiles the body a previously compiled JavaScript Function
- /// object to canonical source, omitting the function header and
- /// trailing brace.
- ///
- /// Returns '[native code]' if no decompilation information is available.
- ///
- ///
- /// the JavaScript function to decompile
- ///
- /// the number of spaces to indent the result
- ///
- /// a string representing the function body source.
- ///
- public string DecompileFunctionBody (IFunction fun, int indent)
- {
- if (fun is BaseFunction) {
- BaseFunction bf = (BaseFunction)fun;
- return bf.Decompile (indent, Decompiler.ONLY_BODY_FLAG);
- }
- // ALERT: not sure what the right response here is.
- return "[native code]\n";
- }
-
- /// Create a new JavaScript object.
- ///
- /// Equivalent to evaluating "new Object()".
- ///
- /// the scope to search for the constructor and to evaluate
- /// against
- ///
- /// the new object
- ///
- public IScriptable NewObject (IScriptable scope)
- {
- return NewObject (scope, "Object", ScriptRuntime.EmptyArgs);
- }
-
- /// Create a new JavaScript object by executing the named constructor.
- ///
- /// The call newObject(scope, "Foo") is equivalent to
- /// evaluating "new Foo()".
- ///
- ///
- /// the scope to search for the constructor and to evaluate against
- ///
- /// the name of the constructor to call
- ///
- /// the new object
- ///
- public IScriptable NewObject (IScriptable scope, string constructorName)
- {
- return NewObject (scope, constructorName, ScriptRuntime.EmptyArgs);
- }
-
- /// Creates a new JavaScript object by executing the named constructor.
- ///
- /// Searches scope for the named constructor, calls it with
- /// the given arguments, and returns the result.
- ///
- /// The code
- ///
- /// Object[] args = { "a", "b" };
- /// newObject(scope, "Foo", args)
- /// is equivalent to evaluating "new Foo('a', 'b')", assuming that the Foo
- /// constructor has been defined in scope.
- ///
- ///
- /// The scope to search for the constructor and to evaluate
- /// against
- ///
- /// the name of the constructor to call
- ///
- /// the array of arguments for the constructor
- ///
- /// the new object
- ///
- public IScriptable NewObject (IScriptable scope, string constructorName, object [] args)
- {
- scope = ScriptableObject.GetTopLevelScope (scope);
- IFunction ctor = ScriptRuntime.getExistingCtor (this, scope, constructorName);
- if (args == null) {
- args = ScriptRuntime.EmptyArgs;
- }
- return ctor.Construct (this, scope, args);
- }
-
- /// Create an array with a specified initial length.
- ///
- ///
- /// the scope to create the object in
- ///
- /// the initial length (JavaScript arrays may have
- /// additional properties added dynamically).
- ///
- /// the new array object
- ///
- public IScriptable NewArray (IScriptable scope, int length)
- {
- BuiltinArray result = new BuiltinArray (length);
- ScriptRuntime.setObjectProtoAndParent (result, scope);
- return result;
- }
-
- /// Create an array with a set of initial elements.
- ///
- ///
- /// the scope to create the object in.
- ///
- /// the initial elements. Each object in this array
- /// must be an acceptable JavaScript type and type
- /// of array should be exactly Object[], not
- /// SomeObjectSubclass[].
- ///
- /// the new array object.
- ///
- public IScriptable NewArray (IScriptable scope, object [] elements)
- {
- Type elementType = elements.GetType ().GetElementType ();
- if (elementType != typeof (object))
- throw new ArgumentException ();
- BuiltinArray result = new BuiltinArray (elements);
- ScriptRuntime.setObjectProtoAndParent (result, scope);
- return result;
- }
-
- /// Get the elements of a JavaScript array.
- ///
- /// If the object defines a length property convertible to double number,
- /// then the number is converted Uint32 value as defined in Ecma 9.6
- /// and Java array of that size is allocated.
- /// The array is initialized with the values obtained by
- /// calling get() on object for each value of i in [0,length-1]. If
- /// there is not a defined value for a property the Undefined value
- /// is used to initialize the corresponding element in the array. The
- /// Java array is then returned.
- /// If the object doesn't define a length property or it is not a number,
- /// empty array is returned.
- ///
- /// the JavaScript array or array-like object
- ///
- /// a Java array of objects
- ///
-
- public object [] GetElements (IScriptable obj)
- {
- return ScriptRuntime.getArrayElements (obj);
- }
-
-
- /// Convenient method to convert java value to its closest representation
- /// in JavaScript.
- ///
- /// If value is an instance of String, Number, Boolean, Function or
- /// Scriptable, it is returned as it and will be treated as the corresponding
- /// JavaScript type of string, number, boolean, function and object.
- ///
- /// Note that for Number instances during any arithmetic operation in
- /// JavaScript the engine will always use the result of
- /// Number.doubleValue() resulting in a precision loss if
- /// the number can not fit into double.
- ///
- /// If value is an instance of Character, it will be converted to string of
- /// length 1 and its JavaScript type will be string.
- ///
- /// The rest of values will be wrapped as LiveConnect objects
- /// by calling {@link WrapFactory#wrap(Context cx, Scriptable scope,
- /// Object obj, Class staticType)} as in:
- ///
- /// Context cx = Context.getCurrentContext();
- /// return cx.getWrapFactory().wrap(cx, scope, value, null);
- ///
- ///
- ///
- /// any Java object
- ///
- /// top scope object
- ///
- /// value suitable to pass to any API that takes JavaScript values.
- ///
- public static object CliToJS (Context cx, object value, IScriptable scope)
- {
- if (value is string || CliHelper.IsNumber (value) || value is bool || value is IScriptable) {
- return value;
- }
- else if (value is char) {
- return Convert.ToString (((char)value));
- }
- else {
- Type type = (value as Type);
- if (type != null) {
- return cx.Wrap (scope, value, (Type)value);
- } else {
- return cx.Wrap (scope, value, null);
- }
- }
- }
-
- /// Convert a JavaScript value into the desired type.
- /// Uses the semantics defined with LiveConnect3 and throws an
- /// Illegal argument exception if the conversion cannot be performed.
- ///
- /// the JavaScript value to convert
- ///
- /// the Java type to convert to. Primitive Java
- /// types are represented using the TYPE fields in the corresponding
- /// wrapper class in java.lang.
- ///
- /// the converted value
- ///
- /// EvaluatorException if the conversion cannot be performed
- public static object JsToCli (object value, System.Type desiredType)
- {
- return CliObject.CoerceType (desiredType, value);
- }
-
-
-
- /// Rethrow the exception wrapping it as the script runtime exception.
- /// Unless the exception is instance of {@link EcmaError} or
- /// {@link EvaluatorException} it will be wrapped as
- /// {@link WrappedException}, a subclass of {@link EvaluatorException}.
- /// The resulting exception object always contains
- /// source name and line number of script that triggered exception.
- ///
- /// This method always throws an exception, its return value is provided
- /// only for convenience to allow a usage like:
- ///
- /// throw Context.throwAsScriptRuntimeEx(ex);
- ///
- /// to indicate that code after the method is unreachable.
- ///
- /// EvaluatorException
- /// EcmaError
- public static ApplicationException ThrowAsScriptRuntimeEx (Exception e)
- {
- while ((e is TargetInvocationException)) {
- e = ((TargetInvocationException)e).InnerException;
- }
- if (e is EcmaScriptException) {
- throw e;
- }
- throw new EcmaScriptRuntimeException (e);
- }
-
- public static bool IsValidOptimizationLevel (int optimizationLevel)
- {
- return -1 <= optimizationLevel && optimizationLevel <= 9;
- }
-
- public static void CheckOptimizationLevel (int optimizationLevel)
- {
- if (IsValidOptimizationLevel (optimizationLevel)) {
- return;
- }
- throw new ArgumentException ("Optimization level outside [-1..9]: " + optimizationLevel);
- }
-
- /// Set the security controller for this context.
- /// SecurityController may only be set if it is currently null
- /// and {@link SecurityController#hasGlobal()} is false.
- /// Otherwise a SecurityException is thrown.
- ///
- /// a SecurityController object
- ///
- /// SecurityException if there is already a SecurityController
- /// object for this Context or globally installed.
- ///
- public SecurityController SecurityController
- {
- set
- {
- if (m_Sealed)
- OnSealedMutation ();
- if (value == null)
- throw new ArgumentException ();
- if (securityController != null) {
- throw new System.Security.SecurityException ("Can not overwrite existing SecurityController object");
- }
- if (SecurityController.HasGlobal ()) {
- throw new System.Security.SecurityException ("Can not overwrite existing global SecurityController object");
- }
- securityController = value;
- }
- get
- {
- SecurityController global = SecurityController.Global;
- if (global != null) {
- return global;
- }
- return securityController;
- }
- }
-
- /// Get a value corresponding to a key.
- ///
- /// Since the Context is associated with a thread it can be
- /// used to maintain values that can be later retrieved using
- /// the current thread.
- ///
- /// Note that the values are maintained with the Context, so
- /// if the Context is disassociated from the thread the values
- /// cannot be retreived. Also, if private data is to be maintained
- /// in this manner the key should be a java.lang.Object
- /// whose reference is not divulged to untrusted code.
- ///
- /// the key used to lookup the value
- ///
- /// a value previously stored using putThreadLocal.
- ///
- public object GetThreadLocal (object key)
- {
- if (hashtable == null)
- return null;
- return hashtable [key];
- }
-
- /// Put a value that can later be retrieved using a given key.
- ///
- ///
- /// the key used to index the value
- ///
- /// the value to save
- ///
- public void PutThreadLocal (object key, object value)
- {
- if (m_Sealed)
- OnSealedMutation ();
- if (hashtable == null)
- hashtable = Hashtable.Synchronized (new Hashtable ());
- hashtable [key] = value;
- }
-
- /// Remove values from thread-local storage.
- /// the key for the entry to remove.
- ///
- public void RemoveThreadLocal (object key)
- {
- if (m_Sealed)
- OnSealedMutation ();
- if (hashtable == null)
- return;
- hashtable.Remove (key);
- }
-
-
-
- /// Return the current debugger.
- /// the debugger, or null if none is attached.
- ///
- public Debugger Debugger
- {
- get
- {
- return m_Debugger;
- }
- }
-
- /// Set the associated debugger.
- /// the debugger to be used on callbacks from
- /// the engine.
- ///
- /// arbitrary object that debugger can use to store
- /// per Context data.
- ///
- public void SetDebugger (Debugger debugger, object contextData)
- {
- if (m_Sealed)
- OnSealedMutation ();
- this.m_Debugger = debugger;
- debuggerData = contextData;
- }
-
- /// Return DebuggableScript instance if any associated with the script.
- /// If callable supports DebuggableScript implementation, the method
- /// returns it. Otherwise null is returned.
- ///
- public static DebuggableScript getDebuggableView (IScript script)
- {
- if (script is BuiltinFunction) {
- return ((BuiltinFunction)script).DebuggableView;
- }
- return null;
- }
-
-
- private Features m_Features = Features.None;
-
- ///
- /// Controls certain aspects of script semantics.
- /// Should be overwritten to alter default behavior.
- ///
- /// The default implementation calls
- /// {@link ContextFactory#hasFeature(Context cx, int featureIndex)}
- /// that allows to customize Context behavior without introducing
- /// Context subclasses. {@link ContextFactory} documentation gives
- /// an example of hasFeature implementation.
- ///
- ///
- /// feature to check
- ///
- /// true if the feature feature is turned on
- ///
- public bool HasFeature (Features feature)
- {
- return (m_Features & feature) == feature;
- }
-
- public void SetFeature (Features feature, bool isEnabled)
- {
- if (isEnabled) {
- m_Features |= feature;
- }
- else {
- if (HasFeature (feature))
- m_Features = m_Features ^ feature;
- }
- }
-
-
- /// Allow application to monitor counter of executed script instructions
- /// in Context subclasses.
- /// Run-time calls this when instruction counting is enabled and the counter
- /// reaches limit set by setInstructionObserverThreshold().
- /// The method is useful to observe long running scripts and if necessary
- /// to terminate them.
- ///
- /// The instruction counting support is available only for interpreted
- /// scripts generated when the optimization level is set to -1.
- ///
- /// The default implementation calls
- /// {@link ContextFactory#observeInstructionCount(Context cx,
- /// int instructionCount)}
- /// that allows to customize Context behavior without introducing
- /// Context subclasses.
- ///
- ///
- /// amount of script instruction executed since
- /// last call to observeInstructionCount
- ///
- /// Error to terminate the script
- protected internal void ObserveInstructionCount (int instructionCount)
- {
- Factory.ObserveInstructionCount (this, instructionCount);
- }
-
- private object CompileImpl (IScriptable scope, StreamReader sourceReader, string sourceString, string sourceName, int lineno, object securityDomain, bool returnFunction, Interpreter compiler, ErrorReporter compilationErrorReporter)
- {
- if (securityDomain != null && securityController == null) {
- throw new ArgumentException ("securityDomain should be null if setSecurityController() was never called");
- }
-
- // One of sourceReader or sourceString has to be null
- if (!(sourceReader == null ^ sourceString == null))
- Context.CodeBug ();
- // scope should be given if and only if compiling function
- if (!(scope == null ^ returnFunction))
- Context.CodeBug ();
-
- CompilerEnvirons compilerEnv = new CompilerEnvirons ();
- compilerEnv.initFromContext (this);
- if (compilationErrorReporter == null) {
- compilationErrorReporter = compilerEnv.getErrorReporter ();
- }
-
- if (m_Debugger != null) {
- if (sourceReader != null) {
- sourceString = sourceReader.ReadToEnd ();
- sourceReader = null;
- }
- }
-
- Parser p = new Parser (compilerEnv, compilationErrorReporter);
- if (returnFunction) {
- p.calledByCompileFunction = true;
- }
- ScriptOrFnNode tree;
- if (sourceString != null) {
- tree = p.Parse (sourceString, sourceName, lineno);
- }
- else {
- tree = p.Parse (sourceReader, sourceName, lineno);
- }
- if (returnFunction) {
- if (!(tree.FunctionCount == 1 && tree.FirstChild != null && tree.FirstChild.Type == Token.FUNCTION)) {
- // TODO: the check just look for the first child
- // TODO: and allows for more nodes after it for compatibility
- // TODO: with sources like function() {};;;
- throw new ArgumentException ("compileFunction only accepts source with single JS function: " + sourceString);
- }
- }
-
-
-
- if (compiler == null) {
- compiler = new Interpreter ();
- //compiler = new Compiler();
- }
-
- string encodedSource = p.EncodedSource;
-
- object bytecode = compiler.Compile (compilerEnv, tree, encodedSource, returnFunction);
-
- if (m_Debugger != null) {
- if (sourceString == null)
- Context.CodeBug ();
- if (bytecode is DebuggableScript) {
- DebuggableScript dscript = (DebuggableScript)bytecode;
- NotifyDebugger (this, dscript, sourceString);
- }
- else {
- throw new ApplicationException ("NOT SUPPORTED");
- }
- }
-
- object result;
- if (returnFunction) {
- result = compiler.CreateFunctionObject (this, scope, bytecode, securityDomain);
- }
- else {
- result = compiler.CreateScriptObject (bytecode, securityDomain);
- }
-
- return result;
- }
-
- private static void NotifyDebugger (Context cx, DebuggableScript dscript, string debugSource)
- {
- cx.m_Debugger.HandleCompilationDone (cx, dscript, debugSource);
- for (int i = 0; i != dscript.FunctionCount; ++i) {
- NotifyDebugger (cx, dscript.GetFunction (i), debugSource);
- }
- }
-
- internal static string GetSourcePositionFromStack (int [] linep)
- {
- Context cx = CurrentContext;
- if (cx == null)
- return null;
- if (cx.lastInterpreterFrame != null) {
- return Interpreter.GetSourcePositionFromStack (cx, linep);
- }
-
- System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace ();
- System.Diagnostics.StackFrame sf = st.GetFrame (0);
- linep [0] = sf.GetFileLineNumber ();
- return Path.GetFileName (sf.GetFileName ());
- }
-
-
- /// Add a name to the list of names forcing the creation of real
- /// activation objects for functions.
- ///
- ///
- /// the name of the object to add to the list
- ///
- public void AddActivationName (string name)
- {
- if (m_Sealed)
- OnSealedMutation ();
- if (activationNames == null)
- activationNames = Hashtable.Synchronized (new Hashtable (5));
- activationNames [name] = name;
- }
-
- /// Check whether the name is in the list of names of objects
- /// forcing the creation of activation objects.
- ///
- ///
- /// the name of the object to test
- ///
- ///
- /// true if an function activation object is needed.
- ///
- public bool IsActivationNeeded (string name)
- {
- return activationNames != null && activationNames.ContainsKey (name);
- }
-
- /// Remove a name from the list of names forcing the creation of real
- /// activation objects for functions.
- ///
- ///
- /// the name of the object to remove from the list
- ///
- public void RemoveActivationName (string name)
- {
- if (m_Sealed)
- OnSealedMutation ();
- if (activationNames != null)
- activationNames.Remove (name);
- }
-
- private static string implementationVersion;
-
- private ContextFactory factory;
- private bool m_Sealed;
- private object m_SealKey;
-
- internal IScriptable topCallScope;
- internal BuiltinCall currentActivationCall;
- internal XMLLib cachedXMLLib;
-
- // for Objects, Arrays to tag themselves as being printed out,
- // so they don't print themselves out recursively.
- // Use ObjToIntMap instead of java.util.HashSet for JDK 1.1 compatibility
- internal ObjToIntMap iterating;
-
- internal object interpreterSecurityDomain;
-
- internal Versions m_Version = Versions.Unknown;
-
- private SecurityController securityController;
-
- private ErrorReporter m_ErrorReporter;
- internal RegExpProxy regExpProxy;
- private System.Globalization.CultureInfo culture;
- private bool generatingDebug;
- private bool generatingDebugChanged;
- private bool generatingSource = true;
- internal bool compileFunctionsWithDynamicScopeFlag = false;
- internal bool useDynamicScope;
- private int m_OptimizationLevel;
-
- internal Debugger m_Debugger;
- private object debuggerData;
- private int enterCount;
- private Hashtable hashtable;
-
- private bool creationEventWasSent;
-
- /// This is the list of names of objects forcing the creation of
- /// function activation records.
- ///
- internal Hashtable activationNames;
-
- // For the interpreter to store the last frame for error reports etc.
- internal object lastInterpreterFrame;
-
- // For the interpreter to store information about previous invocations
- // interpreter invocations
- internal ObjArray previousInterpreterInvocations;
-
- // For instruction counting (interpreter only)
- internal int instructionCount;
- internal int instructionThreshold;
-
- // It can be used to return the second index-like result from function
- internal int scratchIndex;
-
- // It can be used to return the second uint32 result from function
- internal long scratchUint32;
-
- // It can be used to return the second Scriptable result from function
- internal IScriptable scratchScriptable;
- static Context ()
- {
- EmptyArgs = ScriptRuntime.EmptyArgs;
- }
-
- public void Dispose ()
- {
- Context.Exit ();
- }
-
- ///
- /// Throws RuntimeException to indicate failed assertion.
- /// The function never returns and its return type is RuntimeException
- /// only to be able to write throw EcmaScriptHelper.CodeBug() if plain
- /// EcmaScriptHelper.CodeBug() triggers unreachable code error.
- ///
- public static ApplicationException CodeBug ()
- {
- ApplicationException ex = new ApplicationException ("FAILED ASSERTION");
- Console.Error.WriteLine (ex.ToString ());
- throw ex;
- }
-
- }
-}
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+using System.IO;
+using System.Threading;
+using System.Globalization;
+using System.Reflection;
+using System.Collections;
+
+using EcmaScript.NET.Debugging;
+using EcmaScript.NET.Collections;
+using EcmaScript.NET.Types;
+using EcmaScript.NET.Types.Cli;
+using EcmaScript.NET.Types.E4X;
+
+namespace EcmaScript.NET
+{
+
+ ///
+ /// This class represents the runtime context of an executing script.
+ ///
+ /// Before executing a script, an instance of Context must be created
+ /// and associated with the thread that will be executing the script.
+ /// The Context will be used to store information about the executing
+ /// of the script such as the call stack. Contexts are associated with
+ /// the current thread using the {@link #call(ContextAction)}
+ /// or {@link #enter()} methods.
+ ///
+ /// Different forms of script execution are supported. Scripts may be
+ /// evaluated from the source directly, or first compiled and then later
+ /// executed. Interactive execution is also supported.
+ ///
+ /// Some aspects of script execution, such as type conversions and
+ /// object creation, may be accessed directly through methods of
+ /// Context.
+ ///
+ ///
+ public class Context : IDisposable
+ {
+
+ public enum Features
+ {
+ ///
+ /// No features at all
+ ///
+ None = 0,
+
+ ///
+ /// Support for E4X
+ ///
+ E4x = 1 << 1,
+
+ ///
+ /// Support for get and set
+ ///
+ GetterAndSetter = 1 << 2,
+
+ ///
+ ///
+ ///
+ NonEcmaGetYear = 1 << 3,
+
+ /// Control if dynamic scope should be used for name access.
+ /// If hasFeature(FEATURE_DYNAMIC_SCOPE) returns true, then the name lookup
+ /// during name resolution will use the top scope of the script or function
+ /// which is at the top of JS execution stack instead of the top scope of the
+ /// script or function from the current stack frame if the top scope of
+ /// the top stack frame contains the top scope of the current stack frame
+ /// on its prototype chain.
+ ///
+ /// This is useful to define shared scope containing functions that can
+ /// be called from scripts and functions using private scopes.
+ ///
+ /// By default {@link #hasFeature(int)} returns false.
+ ///
+ DynamicScope = 1 << 4,
+ /// Control if member expression as function name extension is available.
+ /// If hasFeature(FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME) returns
+ /// true, allow function memberExpression(args) { body } to be
+ /// syntax sugar for memberExpression = function(args) { body },
+ /// when memberExpression is not a simple identifier.
+ /// See ECMAScript-262, section 11.2 for definition of memberExpression.
+ /// By default {@link #hasFeature(int)} returns false.
+ ///
+ MemberExprAsFunctionName = 1 << 5,
+
+ /// Control if reserved keywords are treated as identifiers.
+ /// If hasFeature(RESERVED_KEYWORD_AS_IDENTIFIER) returns true,
+ /// treat future reserved keyword (see Ecma-262, section 7.5.3) as ordinary
+ /// identifiers but warn about this usage.
+ ///
+ /// By default {@link #hasFeature(int)} returns false.
+ ///
+ ReservedKeywordAsIdentifier = 1 << 6,
+
+ /// Control if toString() should returns the same result
+ /// as toSource() when applied to objects and arrays.
+ /// If hasFeature(FEATURE_TO_STRING_AS_SOURCE) returns true,
+ /// calling toString() on JS objects gives the same result as
+ /// calling toSource(). That is it returns JS source with code
+ /// to create an object with all enumeratable fields of the original object
+ /// instead of printing [object result of
+ /// {@link Scriptable#getClassName()}].
+ ///
+ /// By default {@link #hasFeature(int)} returns true only if
+ /// the current JS version is set to {@link #Versions.JS1_2}.
+ ///
+ ToStringAsSource = 1 << 7,
+
+ /// Control if properties __proto__ and __parent__
+ /// are treated specially.
+ /// If hasFeature(FEATURE_PARENT_PROTO_PROPRTIES) returns true,
+ /// treat __parent__ and __proto__ as special properties.
+ ///
+ /// The properties allow to query and set scope and prototype chains for the
+ /// objects. The special meaning of the properties is available
+ /// only when they are used as the right hand side of the dot operator.
+ /// For example, while x.__proto__ = y changes the prototype
+ /// chain of the object x to point to y,
+ /// x["__proto__"] = y simply assigns a new value to the property
+ /// __proto__ in x even when the feature is on.
+ ///
+ /// By default {@link #hasFeature(int)} returns true.
+ ///
+ ParentProtoProperties = 1 << 8,
+
+ /// Control if strict variable mode is enabled.
+ /// When the feature is on Rhino reports runtime errors if assignment
+ /// to a global variable that does not exist is executed. When the feature
+ /// is off such assignments creates new variable in the global scope as
+ /// required by ECMA 262.
+ ///
+ /// By default {@link #hasFeature(int)} returns false.
+ ///
+ StrictVars = 1 << 9,
+
+ /// Control if strict eval mode is enabled.
+ /// When the feature is on Rhino reports runtime errors if non-string
+ /// argument is passed to the eval function. When the feature is off
+ /// eval simply return non-string argument as is without performing any
+ /// evaluation as required by ECMA 262.
+ ///
+ /// By default {@link #hasFeature(int)} returns false.
+ ///
+ StrictEval = 1 << 10,
+
+ ///
+ /// Controls if the non-ecma function 'print' is available or not.
+ ///
+ NonEcmaPrintFunction = 1 << 11,
+
+ ///
+ /// Controls if the non-ecma function 'version' is available or not
+ ///
+ NonEcmaVersionFunction = 1 << 12,
+
+ ///
+ /// Controls if the non-ecma function 'options' is available or not
+ ///
+ NonEcmaOptionsFunction = 1 << 13,
+
+ Strict = 1 << 14,
+
+ ///
+ /// Controls if the non-ecma function 'options' is available or not
+ ///
+ NonEcmaGcFunction = 1 << 14,
+
+ ///
+ /// The famous 'it' object (@see js.c:2315)
+ ///
+ NonEcmaItObject = 1 << 15,
+
+ }
+
+ public enum Versions
+ {
+ Unknown = -1,
+ Default = 0,
+ JS1_0 = 100,
+ JS1_1 = 110,
+ JS1_2 = 120,
+ JS1_3 = 130,
+ JS1_4 = 140,
+ JS1_5 = 150,
+ JS1_6 = 160
+ }
+
+ ///
+ ///
+ ///
+ public event ContextWrapHandler OnWrap;
+
+ private int m_MaximumInterpreterStackDepth = 8092;
+
+ ///
+ ///
+ ///
+ public int MaximumInterpreterStackDepth
+ {
+ get
+ {
+ return m_MaximumInterpreterStackDepth;
+ }
+ set
+ {
+ if (Sealed)
+ OnSealedMutation ();
+ m_MaximumInterpreterStackDepth = value;
+ }
+ }
+
+ private AppDomain m_AppDomain = null;
+
+ ///
+ /// Associated app domain
+ ///
+ public AppDomain AppDomain
+ {
+ get { return m_AppDomain; }
+ }
+
+ private static LocalDataStoreSlot LocalSlot
+ {
+ get
+ {
+ LocalDataStoreSlot slot = Thread.GetNamedDataSlot ("Context");
+ if (slot == null) {
+ slot = Thread.AllocateNamedDataSlot ("Context");
+ }
+ return slot;
+ }
+ }
+
+ /// Get the current Context.
+ ///
+ /// The current Context is per-thread; this method looks up
+ /// the Context associated with the current thread.
+ ///
+ ///
+ /// the Context associated with the current thread, or
+ /// null if no context is associated with the current
+ /// thread.
+ ///
+ public static Context CurrentContext
+ {
+ get
+ {
+ Context cx = (Context)Thread.GetData (LocalSlot);
+ return cx;
+ }
+ }
+
+ /// Return {@link ContextFactory} instance used to create this Context
+ /// or the result of {@link ContextFactory#getGlobal()} if no factory
+ /// was used for Context creation.
+ ///
+ public ContextFactory Factory
+ {
+ get
+ {
+ ContextFactory result = factory;
+ if (result == null) {
+ result = ContextFactory.Global;
+ }
+ return result;
+ }
+
+ }
+ /// Checks if this is a sealed Context. A sealed Context instance does not
+ /// allow to modify any of its properties and will throw an exception
+ /// on any such attempt.
+ ///
+ public bool Sealed
+ {
+ get
+ {
+ return m_Sealed;
+ }
+
+ }
+ /// Get the implementation version.
+ ///
+ ///
+ /// The implementation version is of the form
+ ///
+ /// "name langVer release relNum date"
+ ///
+ /// where name is the name of the product, langVer is
+ /// the language version, relNum is the release number, and
+ /// date is the release date for that specific
+ /// release in the form "yyyy mm dd".
+ ///
+ ///
+ /// a string that encodes the product, language version, release
+ /// number, and date.
+ ///
+ public string ImplementationVersion
+ {
+ get
+ {
+ // TODO: Probably it would be better to embed this directly into source
+ // TODO: with special build preprocessing but that would require some ant
+ // TODO: tweaking and then replacing token in resource files was simpler
+ if (implementationVersion == null) {
+ implementationVersion = ScriptRuntime.GetMessage ("implementation.version");
+ }
+ return implementationVersion;
+ }
+
+ }
+ /// Get the singleton object that represents the JavaScript Undefined value.
+ public static object UndefinedValue
+ {
+ get
+ {
+ return Undefined.Value;
+ }
+
+ }
+ /// Specify whether or not debug information should be generated.
+ ///
+ /// Setting the generation of debug information on will set the
+ /// optimization level to zero.
+ ///
+ public bool GeneratingDebug
+ {
+ get
+ {
+ return generatingDebug;
+ }
+
+ set
+ {
+ if (m_Sealed)
+ OnSealedMutation ();
+ generatingDebugChanged = true;
+ if (value && OptimizationLevel > 0)
+ OptimizationLevel = 0;
+ this.generatingDebug = value;
+ }
+
+ }
+
+ /// Specify whether or not source information should be generated.
+ ///
+ /// Without source information, evaluating the "toString" method
+ /// on JavaScript functions produces only "[native code]" for
+ /// the body of the function.
+ /// Note that code generated without source is not fully ECMA
+ /// conformant.
+ ///
+ public bool GeneratingSource
+ {
+ get
+ {
+ return generatingSource;
+ }
+ set
+ {
+ if (m_Sealed)
+ OnSealedMutation ();
+ this.generatingSource = value;
+ }
+
+ }
+ /// Set the current optimization level.
+ ///
+ /// The optimization level is expected to be an integer between -1 and
+ /// 9. Any negative values will be interpreted as -1, and any values
+ /// greater than 9 will be interpreted as 9.
+ /// An optimization level of -1 indicates that interpretive mode will
+ /// always be used. Levels 0 through 9 indicate that class files may
+ /// be generated. Higher optimization levels trade off compile time
+ /// performance for runtime performance.
+ /// The optimizer level can't be set greater than -1 if the optimizer
+ /// package doesn't exist at run time.
+ ///
+ /// an integer indicating the level of
+ /// optimization to perform
+ ///
+ public int OptimizationLevel
+ {
+ get
+ {
+ return m_OptimizationLevel;
+ }
+
+ set
+ {
+ if (m_Sealed)
+ OnSealedMutation ();
+ if (value == -2) {
+ // To be compatible with Cocoon fork
+ value = -1;
+ }
+ CheckOptimizationLevel (value);
+ this.m_OptimizationLevel = value;
+ }
+
+ }
+
+ /// Return the debugger context data associated with current context.
+ /// the debugger data, or null if debugger is not attached
+ ///
+ public object DebuggerContextData
+ {
+ get
+ {
+ return debuggerData;
+ }
+
+ }
+
+ public object Wrap (IScriptable scope, object obj, Type staticType)
+ {
+ if (obj == null || obj is IScriptable)
+ return obj;
+ if (staticType == null)
+ staticType = obj.GetType ();
+
+ if (staticType.IsArray)
+ return new CliArray (scope, obj as Array);
+
+ if (staticType.IsPrimitive)
+ return obj;
+
+ if (OnWrap != null) {
+ ContextWrapEventArgs e = new ContextWrapEventArgs (this, scope, obj, staticType);
+ OnWrap (this, e);
+ obj = e.Target;
+ }
+
+ return new CliObject (obj);
+ }
+
+ /// Get/Set threshold of executed instructions counter that triggers call to
+ /// observeInstructionCount().
+ /// When the threshold is zero, instruction counting is disabled,
+ /// otherwise each time the run-time executes at least the threshold value
+ /// of script instructions, observeInstructionCount() will
+ /// be called.
+ ///
+ public int InstructionObserverThreshold
+ {
+ get
+ {
+ return instructionThreshold;
+ }
+
+ set
+ {
+ if (m_Sealed)
+ OnSealedMutation ();
+ if (value < 0)
+ throw new ArgumentException ();
+ instructionThreshold = value;
+ }
+
+ }
+
+ internal RegExpProxy RegExpProxy
+ {
+ get
+ {
+ if (regExpProxy == null) {
+ regExpProxy = new Types.RegExp.RegExpImpl ();
+ }
+ return regExpProxy;
+ }
+ set {
+ regExpProxy = value;
+ }
+ }
+ internal bool VersionECMA1
+ {
+ get
+ {
+ return m_Version == Versions.Default || m_Version >= Versions.JS1_3;
+ }
+
+ }
+ public bool GeneratingDebugChanged
+ {
+ get
+ {
+ return generatingDebugChanged;
+ }
+
+ }
+ /// Language versions.
+ ///
+ /// All integral values are reserved for future version numbers.
+ ///
+
+
+
+
+
+
+
+
+
+
+
+ public const string languageVersionProperty = "language version";
+ public const string errorReporterProperty = "error reporter";
+
+ /// Convinient value to use as zero-length array of objects.
+ public static readonly object [] EmptyArgs;
+
+ /// Create a new Context.
+ ///
+ /// Note that the Context must be associated with a thread before
+ /// it can be used to execute a script.
+ ///
+ ///
+ public Context (AppDomain appDomain)
+ {
+ if (appDomain == null)
+ throw new ArgumentNullException ("appDomain");
+ Version = Versions.Default;
+ m_AppDomain = appDomain;
+ }
+
+ /// Get a context associated with the current thread, creating
+ /// one if need be.
+ ///
+ /// The Context stores the execution state of the JavaScript
+ /// engine, so it is required that the context be entered
+ /// before execution may begin. Once a thread has entered
+ /// a Context, then getCurrentContext() may be called to find
+ /// the context that is associated with the current thread.
+ ///
+ /// Calling enter() will
+ /// return either the Context currently associated with the
+ /// thread, or will create a new context and associate it
+ /// with the current thread. Each call to enter()
+ /// must have a matching call to exit(). For example,
+ ///
+ /// Context cx = Context.enter();
+ /// try {
+ /// ...
+ /// cx.evaluateString(...);
+ /// } finally {
+ /// Context.exit();
+ /// }
+ ///
+ /// Instead of using enter(), exit() pair consider using
+ /// {@link #call(ContextAction)} which guarantees proper
+ /// association of Context instances with the current thread and is faster.
+ /// With this method the above example becomes:
+ ///
+ /// Context.call(new ContextAction() {
+ /// public Object run(Context cx) {
+ /// ...
+ /// cx.evaluateString(...);
+ /// return null;
+ /// }
+ /// });
+ ///
+ ///
+ ///
+ /// a Context associated with the current thread
+ ///
+ public static Context Enter ()
+ {
+ return Enter (null, AppDomain.CurrentDomain);
+ }
+
+ public static Context Enter (AppDomain appDomain)
+ {
+ return Enter (null, appDomain);
+ }
+
+ /// Get a Context associated with the current thread, using
+ /// the given Context if need be.
+ ///
+ /// The same as enter() except that cx
+ /// is associated with the current thread and returned if
+ /// the current thread has no associated context and cx
+ /// is not associated with any other thread.
+ ///
+ /// a Context to associate with the thread if possible
+ ///
+ /// a Context associated with the current thread
+ ///
+ ///
+ public static Context Enter (Context cx)
+ {
+ return Enter (cx, AppDomain.CurrentDomain);
+ }
+
+ public static Context Enter (Context cx, AppDomain appDomain)
+ {
+ Context old = CurrentContext;
+ if (old != null) {
+ if (cx != null && cx != old && cx.enterCount != 0) {
+ // The suplied context must be the context for
+ // the current thread if it is already entered
+ throw new ArgumentException ("Cannot enter Context active on another thread");
+ }
+ if (old.factory != null) {
+ // Context with associated factory will be released
+ // automatically and does not need to change enterCount
+ return old;
+ }
+ if (old.m_Sealed)
+ OnSealedMutation ();
+ cx = old;
+ }
+ else {
+ if (cx == null) {
+ cx = new Context (appDomain);
+ }
+ else {
+ if (cx.m_Sealed)
+ OnSealedMutation ();
+ }
+ if (cx.enterCount != 0 || cx.factory != null) {
+ throw new Exception ();
+ }
+
+ if (!cx.creationEventWasSent) {
+ cx.creationEventWasSent = true;
+ ContextFactory.Global.FireOnContextCreated (cx);
+ }
+ }
+
+ if (old == null) {
+ Thread.SetData (LocalSlot, cx);
+ }
+ ++cx.enterCount;
+
+ return cx;
+ }
+
+ /// Exit a block of code requiring a Context.
+ ///
+ /// Calling exit() will remove the association between
+ /// the current thread and a Context if the prior call to
+ /// enter() on this thread newly associated a Context
+ /// with this thread.
+ /// Once the current thread no longer has an associated Context,
+ /// it cannot be used to execute JavaScript until it is again associated
+ /// with a Context.
+ ///
+ ///
+ public static void Exit ()
+ {
+ Context cx = CurrentContext;
+ if (cx == null) {
+ throw new Exception ("Calling Context.exit without previous Context.enter");
+ }
+ if (cx.factory != null) {
+ // Context with associated factory will be released
+ // automatically and does not need to change enterCount
+ return;
+ }
+ if (cx.enterCount < 1)
+ Context.CodeBug ();
+ if (cx.m_Sealed)
+ OnSealedMutation ();
+ --cx.enterCount;
+ if (cx.enterCount == 0) {
+ Thread.SetData (LocalSlot, null);
+ ContextFactory.Global.FireOnContextReleased (cx);
+ }
+ }
+
+
+ /// Call {@link
+ /// Callable#call(Context cx, Scriptable scope, Scriptable thisObj,
+ /// Object[] args)}
+ /// using the Context instance associated with the current thread.
+ /// If no Context is associated with the thread, then
+ /// {@link ContextFactory#makeContext()} will be called to construct
+ /// new Context instance. The instance will be temporary associated
+ /// with the thread during call to {@link ContextAction#run(Context)}.
+ ///
+ /// It is allowed to use null for factory argument
+ /// in which case the factory associated with the scope will be
+ /// used to create new context instances.
+ ///
+ ///
+ public static object Call (ContextFactory factory, ICallable callable, IScriptable scope, IScriptable thisObj, object [] args)
+ {
+ if (factory == null) {
+ factory = ContextFactory.Global;
+ }
+
+ Context cx = CurrentContext;
+ if (cx != null) {
+ object result;
+ if (cx.factory != null) {
+ result = callable.Call (cx, scope, thisObj, args);
+ }
+ else {
+ // Context was associated with the thread via Context.enter,
+ // set factory to make Context.enter/exit to be no-op
+ // during call
+ cx.factory = factory;
+ try {
+ result = callable.Call (cx, scope, thisObj, args);
+ }
+ finally {
+ cx.factory = null;
+ }
+ }
+ return result;
+ }
+
+ cx = PrepareNewContext (AppDomain.CurrentDomain, factory);
+ try {
+ return callable.Call (cx, scope, thisObj, args);
+ }
+ finally {
+ ReleaseContext (cx);
+ }
+ }
+
+ internal void InitDefaultFeatures ()
+ {
+ m_Features = Features.None;
+
+ SetFeature (Features.E4x, (Version == Context.Versions.Default || Version >= Context.Versions.JS1_6));
+ SetFeature (Features.GetterAndSetter, (Version == Context.Versions.Default || Version >= Context.Versions.JS1_5));
+ SetFeature (Features.NonEcmaGetYear, (Version == Context.Versions.JS1_0 || Version == Context.Versions.JS1_1 || Version == Context.Versions.JS1_2));
+ SetFeature (Features.ToStringAsSource, Version == Context.Versions.JS1_2);
+ SetFeature (Features.ParentProtoProperties, true);
+ }
+
+
+ private static Context PrepareNewContext (AppDomain appDomain, ContextFactory factory)
+ {
+ Context cx = new Context (appDomain);
+ if (cx.factory != null || cx.enterCount != 0) {
+ throw new Exception ("factory.makeContext() returned Context instance already associated with some thread");
+ }
+ cx.factory = factory;
+ factory.FireOnContextCreated (cx);
+ if (factory.Sealed && !cx.Sealed) {
+ cx.Seal ((object)null);
+ }
+ Thread.SetData (LocalSlot, cx);
+ return cx;
+ }
+
+ private static void ReleaseContext (Context cx)
+ {
+ Thread.SetData (LocalSlot, null);
+ try {
+ cx.factory.FireOnContextReleased (cx);
+ }
+ finally {
+ cx.factory = null;
+ }
+ }
+
+
+
+ /// Seal this Context object so any attempt to modify any of its properties
+ /// including calling {@link #enter()} and {@link #exit()} methods will
+ /// throw an exception.
+ ///
+ /// If sealKey is not null, calling
+ /// {@link #unseal(Object sealKey)} with the same key unseals
+ /// the object. If sealKey is null, unsealing is no longer possible.
+ ///
+ ///
+ public void Seal (object sealKey)
+ {
+ if (m_Sealed)
+ OnSealedMutation ();
+ m_Sealed = true;
+ this.m_SealKey = sealKey;
+ }
+
+ /// Unseal previously sealed Context object.
+ /// The sealKey argument should not be null and should match
+ /// sealKey suplied with the last call to
+ /// {@link #seal(Object)} or an exception will be thrown.
+ ///
+ ///
+ public void Unseal (object sealKey)
+ {
+ if (sealKey == null)
+ throw new ArgumentException ();
+ if (this.m_SealKey != sealKey)
+ throw new ArgumentException ();
+ if (!m_Sealed)
+ throw new Exception ();
+ m_Sealed = false;
+ this.m_SealKey = null;
+ }
+
+ internal static void OnSealedMutation ()
+ {
+ throw new Exception ();
+ }
+
+ ///
+ /// Get the current language version.
+ ///
+ public Versions Version
+ {
+ get
+ {
+ return m_Version;
+ }
+ set
+ {
+ if (m_Sealed)
+ OnSealedMutation ();
+ this.m_Version = value;
+
+ InitDefaultFeatures ();
+ }
+ }
+
+ public static bool IsValidLanguageVersion (int version)
+ {
+ return ToValidLanguageVersion (version) != Versions.Unknown;
+ }
+
+ public static Versions ToValidLanguageVersion (int version)
+ {
+ Versions ver = Versions.Unknown;
+ if (version > 0 || version < (int)Versions.JS1_6)
+ ver = (Versions)version;
+ return ver;
+ }
+
+ public static void CheckLanguageVersion (int version)
+ {
+ if (IsValidLanguageVersion (version)) {
+ return;
+ }
+ throw new ArgumentException ("Bad language version: " + version);
+ }
+
+ /// Get the current error reporter.
+ ///
+ ///
+ public ErrorReporter ErrorReporter
+ {
+ get
+ {
+ if (m_ErrorReporter == null) {
+ return DefaultErrorReporter.instance;
+ }
+ return m_ErrorReporter;
+ }
+ set
+ {
+ if (m_Sealed)
+ OnSealedMutation ();
+ if (value == null)
+ throw new ArgumentException ();
+ this.m_ErrorReporter = value;
+ }
+ }
+
+ ///
+ /// Get the current locale. Returns the default locale if none has
+ /// been set.
+ ///
+ public CultureInfo CurrentCulture
+ {
+ get
+ {
+ if (culture == null)
+ culture = Thread.CurrentThread.CurrentCulture;
+ return culture;
+ }
+ set
+ {
+ if (m_Sealed)
+ OnSealedMutation ();
+ culture = value;
+
+ // HACK: Needed for example on DateTime.ToString()
+ if (Thread.CurrentThread.CurrentCulture != culture)
+ Thread.CurrentThread.CurrentCulture = culture;
+ }
+ }
+
+ /// Report a warning using the error reporter for the current thread.
+ ///
+ ///
+ /// the warning message to report
+ ///
+ /// a string describing the source, such as a filename
+ ///
+ /// the starting line number
+ ///
+ /// the text of the line (may be null)
+ ///
+ /// the offset into lineSource where problem was detected
+ ///
+
+ public static void ReportWarning (string message, string sourceName, int lineno, string lineSource, int lineOffset)
+ {
+ Context cx = Context.CurrentContext;
+ cx.ErrorReporter.Warning (message, sourceName, lineno, lineSource, lineOffset);
+ }
+
+ public static void ReportWarningById (string messageId, params string [] arguments)
+ {
+ int [] linep = new int [] { 0 };
+ string filename = GetSourcePositionFromStack (linep);
+ Context.ReportWarning (ScriptRuntime.GetMessage (messageId, arguments), filename, linep [0], null, 0);
+ }
+
+ /// Report a warning using the error reporter for the current thread.
+ ///
+ ///
+ /// the warning message to report
+ ///
+ public static void ReportWarning (string message)
+ {
+ int [] linep = new int [] { 0 };
+ string filename = GetSourcePositionFromStack (linep);
+ Context.ReportWarning (message, filename, linep [0], null, 0);
+ }
+
+ /// Report an error using the error reporter for the current thread.
+ ///
+ ///
+ /// the error message to report
+ ///
+ /// a string describing the source, such as a filename
+ ///
+ /// the starting line number
+ ///
+ /// the text of the line (may be null)
+ ///
+ /// the offset into lineSource where problem was detected
+ ///
+ public static void ReportError (string message, string sourceName, int lineno, string lineSource, int lineOffset)
+ {
+ Context cx = CurrentContext;
+ if (cx != null) {
+ cx.ErrorReporter.Error (message, sourceName, lineno, lineSource, lineOffset);
+ }
+ else {
+ throw new EcmaScriptRuntimeException (message, sourceName, lineno, lineSource, lineOffset);
+ }
+ }
+
+ /// Report an error using the error reporter for the current thread.
+ ///
+ ///
+ /// the error message to report
+ ///
+
+ public static void ReportError (string message)
+ {
+ int [] linep = new int [] { 0 };
+ string filename = GetSourcePositionFromStack (linep);
+ Context.ReportError (message, filename, linep [0], null, 0);
+ }
+
+ /// Report a runtime error using the error reporter for the current thread.
+ ///
+ ///
+ /// the error message to report
+ ///
+ /// a string describing the source, such as a filename
+ ///
+ /// the starting line number
+ ///
+ /// the text of the line (may be null)
+ ///
+ /// the offset into lineSource where problem was detected
+ ///
+ /// a runtime exception that will be thrown to terminate the
+ /// execution of the script
+ ///
+ public static EcmaScriptRuntimeException ReportRuntimeError (string message, string sourceName, int lineno, string lineSource, int lineOffset)
+ {
+ Context cx = CurrentContext;
+ if (cx != null) {
+ return cx.ErrorReporter.RuntimeError (message, sourceName, lineno, lineSource, lineOffset);
+ }
+ else {
+ throw new EcmaScriptRuntimeException (message, sourceName, lineno, lineSource, lineOffset);
+ }
+ }
+
+
+ internal static EcmaScriptRuntimeException ReportRuntimeErrorById (string messageId, params object [] args)
+ {
+ return ReportRuntimeError (ScriptRuntime.GetMessage (messageId, args));
+ }
+
+ /// Report a runtime error using the error reporter for the current thread.
+ ///
+ ///
+ /// the error message to report
+ ///
+ public static EcmaScriptRuntimeException ReportRuntimeError (string message)
+ {
+ int [] linep = new int [] { 0 };
+ string filename = GetSourcePositionFromStack (linep);
+ return Context.ReportRuntimeError (message, filename, linep [0], null, 0);
+ }
+
+ /// Initialize the standard objects.
+ ///
+ /// Creates instances of the standard objects and their constructors
+ /// (Object, String, Number, Date, etc.), setting up 'scope' to act
+ /// as a global object as in ECMA 15.1.
+ ///
+ /// This method must be called to initialize a scope before scripts
+ /// can be evaluated in that scope.
+ ///
+ /// This method does not affect the Context it is called upon.
+ ///
+ ///
+ /// the initialized scope
+ ///
+ public ScriptableObject InitStandardObjects ()
+ {
+ return InitStandardObjects (null, false);
+ }
+
+ /// Initialize the standard objects.
+ ///
+ /// Creates instances of the standard objects and their constructors
+ /// (Object, String, Number, Date, etc.), setting up 'scope' to act
+ /// as a global object as in ECMA 15.1.
+ ///
+ /// This method must be called to initialize a scope before scripts
+ /// can be evaluated in that scope.
+ ///
+ /// This method does not affect the Context it is called upon.
+ ///
+ ///
+ /// the scope to initialize, or null, in which case a new
+ /// object will be created to serve as the scope
+ ///
+ /// the initialized scope. The method returns the value of the scope
+ /// argument if it is not null or newly allocated scope object which
+ /// is an instance {@link ScriptableObject}.
+ ///
+ public IScriptable InitStandardObjects (ScriptableObject scope)
+ {
+ return InitStandardObjects (scope, false);
+ }
+
+ /// Initialize the standard objects.
+ ///
+ /// Creates instances of the standard objects and their constructors
+ /// (Object, String, Number, Date, etc.), setting up 'scope' to act
+ /// as a global object as in ECMA 15.1.
+ ///
+ /// This method must be called to initialize a scope before scripts
+ /// can be evaluated in that scope.
+ ///
+ /// This method does not affect the Context it is called upon.
+ ///
+ /// This form of the method also allows for creating "sealed" standard
+ /// objects. An object that is sealed cannot have properties added, changed,
+ /// or removed. This is useful to create a "superglobal" that can be shared
+ /// among several top-level objects. Note that sealing is not allowed in
+ /// the current ECMA/ISO language specification, but is likely for
+ /// the next version.
+ ///
+ ///
+ /// the scope to initialize, or null, in which case a new
+ /// object will be created to serve as the scope
+ ///
+ /// whether or not to create sealed standard objects that
+ /// cannot be modified.
+ ///
+ /// the initialized scope. The method returns the value of the scope
+ /// argument if it is not null or newly allocated scope object.
+ ///
+ public ScriptableObject InitStandardObjects (ScriptableObject scope, bool zealed)
+ {
+ return ScriptRuntime.InitStandardObjects (this, scope, zealed);
+ }
+
+ /// Evaluate a JavaScript source string.
+ ///
+ /// The provided source name and line number are used for error messages
+ /// and for producing debug information.
+ ///
+ ///
+ /// the scope to execute in
+ ///
+ /// the JavaScript source
+ ///
+ /// a string describing the source, such as a filename
+ ///
+ /// the starting line number
+ ///
+ /// an arbitrary object that specifies security
+ /// information about the origin or owner of the script. For
+ /// implementations that don't care about security, this value
+ /// may be null.
+ ///
+ /// the result of evaluating the string
+ ///
+ public object EvaluateString (IScriptable scope, string source, string sourceName, int lineno, object securityDomain)
+ {
+ IScript script = CompileString (source, sourceName, lineno, securityDomain);
+ if (script != null) {
+ return script.Exec (this, scope);
+ }
+ else {
+ return null;
+ }
+ }
+
+ /// Evaluate a reader as JavaScript source.
+ ///
+ /// All characters of the reader are consumed.
+ ///
+ ///
+ /// the scope to execute in
+ ///
+ /// the Reader to get JavaScript source from
+ ///
+ /// a string describing the source, such as a filename
+ ///
+ /// the starting line number
+ ///
+ /// an arbitrary object that specifies security
+ /// information about the origin or owner of the script. For
+ /// implementations that don't care about security, this value
+ /// may be null.
+ ///
+ /// the result of evaluating the source
+ ///
+ ///
+ /// IOException if an IOException was generated by the Reader
+ ///
+ public object EvaluateReader (IScriptable scope, StreamReader sr, string sourceName, int lineno, object securityDomain)
+ {
+ IScript script = CompileReader (sr, sourceName, lineno, securityDomain);
+
+ if (script != null) {
+ return script.Exec (this, scope);
+ }
+ return null;
+ }
+
+ /// Check whether a string is ready to be compiled.
+ ///
+ /// stringIsCompilableUnit is intended to support interactive compilation of
+ /// javascript. If compiling the string would result in an error
+ /// that might be fixed by appending more source, this method
+ /// returns false. In every other case, it returns true.
+ ///
+ /// Interactive shells may accumulate source lines, using this
+ /// method after each new line is appended to check whether the
+ /// statement being entered is complete.
+ ///
+ ///
+ /// the source buffer to check
+ ///
+ /// whether the source is ready for compilation
+ ///
+ public ScriptOrFnNode IsCompilableUnit (string source)
+ {
+ ScriptOrFnNode ret = null;
+ bool errorseen = false;
+ CompilerEnvirons compilerEnv = new CompilerEnvirons ();
+ compilerEnv.initFromContext (this);
+ // no source name or source text manager, because we're just
+ // going to throw away the result.
+ compilerEnv.setGeneratingSource (false);
+ Parser p = new Parser (compilerEnv, DefaultErrorReporter.instance);
+ try {
+ ret = p.Parse (source, null, 1);
+ }
+ catch (EcmaScriptRuntimeException) {
+ errorseen = true;
+ }
+ // Return false only if an error occurred as a result of reading past
+ // the end of the file, i.e. if the source could be fixed by
+ // appending more source.
+ if (!(errorseen && p.Eof))
+ return ret;
+ return null;
+ }
+
+
+ /// Compiles the source in the given reader.
+ ///
+ /// Returns a script that may later be executed.
+ /// Will consume all the source in the reader.
+ ///
+ ///
+ /// the input reader
+ ///
+ /// a string describing the source, such as a filename
+ ///
+ /// the starting line number for reporting errors
+ ///
+ /// an arbitrary object that specifies security
+ /// information about the origin or owner of the script. For
+ /// implementations that don't care about security, this value
+ /// may be null.
+ ///
+ /// a script that may later be executed
+ ///
+ /// IOException if an IOException was generated by the Reader
+ ///
+ public IScript CompileReader (StreamReader sr, string sourceName, int lineno, object securityDomain)
+ {
+ if (lineno < 0)
+ throw new ArgumentException ("lineno may not be negative", "lineno");
+ return (IScript)CompileImpl (null, sr, null, sourceName, lineno, securityDomain, false, null, null);
+ }
+
+ /// Compiles the source in the given string.
+ ///
+ /// Returns a script that may later be executed.
+ ///
+ ///
+ /// the source string
+ ///
+ /// a string describing the source, such as a filename
+ ///
+ /// the starting line number for reporting errors
+ ///
+ /// an arbitrary object that specifies security
+ /// information about the origin or owner of the script. For
+ /// implementations that don't care about security, this value
+ /// may be null.
+ ///
+ /// a script that may later be executed
+ ///
+ public IScript CompileString (string source, string sourceName, int lineno, object securityDomain)
+ {
+ if (lineno < 0) {
+ // For compatibility IllegalArgumentException can not be thrown here
+ lineno = 0;
+ }
+ return CompileString (source, null, null, sourceName, lineno, securityDomain);
+ }
+
+ internal IScript CompileString (string source, Interpreter compiler, ErrorReporter compilationErrorReporter, string sourceName, int lineno, object securityDomain)
+ {
+ return (IScript)CompileImpl (null, null, source, sourceName, lineno, securityDomain, false, compiler, compilationErrorReporter);
+ }
+
+ /// Compile a JavaScript function.
+ ///
+ /// The function source must be a function definition as defined by
+ /// ECMA (e.g., "function f(a) { return a; }").
+ ///
+ ///
+ /// the scope to compile relative to
+ ///
+ /// the function definition source
+ ///
+ /// a string describing the source, such as a filename
+ ///
+ /// the starting line number
+ ///
+ /// an arbitrary object that specifies security
+ /// information about the origin or owner of the script. For
+ /// implementations that don't care about security, this value
+ /// may be null.
+ ///
+ /// a Function that may later be called
+ ///
+ public IFunction CompileFunction (IScriptable scope, string source, string sourceName, int lineno, object securityDomain)
+ {
+ return CompileFunction (scope, source, null, null, sourceName, lineno, securityDomain);
+ }
+
+ internal IFunction CompileFunction (IScriptable scope, string source, Interpreter compiler, ErrorReporter compilationErrorReporter, string sourceName, int lineno, object securityDomain)
+ {
+ return (IFunction)CompileImpl (scope, null, source, sourceName, lineno, securityDomain, true, compiler, compilationErrorReporter);
+ }
+
+ /// Decompile the script.
+ ///
+ /// The canonical source of the script is returned.
+ ///
+ ///
+ /// the script to decompile
+ ///
+ /// the number of spaces to indent the result
+ ///
+ /// a string representing the script source
+ ///
+ public string DecompileScript (IScript script, int indent)
+ {
+ BuiltinFunction scriptImpl = (BuiltinFunction)script;
+ return scriptImpl.Decompile (indent, 0);
+ }
+
+ /// Decompile a JavaScript Function.
+ ///
+ /// Decompiles a previously compiled JavaScript function object to
+ /// canonical source.
+ ///
+ /// Returns function body of '[native code]' if no decompilation
+ /// information is available.
+ ///
+ ///
+ /// the JavaScript function to decompile
+ ///
+ /// the number of spaces to indent the result
+ ///
+ /// a string representing the function source
+ ///
+ public string DecompileFunction (IFunction fun, int indent)
+ {
+ if (fun is BaseFunction)
+ return ((BaseFunction)fun).Decompile (indent, 0);
+ else
+ return "function " + fun.ClassName + "() {\n\t[native code]\n}\n";
+ }
+
+ /// Decompile the body of a JavaScript Function.
+ ///
+ /// Decompiles the body a previously compiled JavaScript Function
+ /// object to canonical source, omitting the function header and
+ /// trailing brace.
+ ///
+ /// Returns '[native code]' if no decompilation information is available.
+ ///
+ ///
+ /// the JavaScript function to decompile
+ ///
+ /// the number of spaces to indent the result
+ ///
+ /// a string representing the function body source.
+ ///
+ public string DecompileFunctionBody (IFunction fun, int indent)
+ {
+ if (fun is BaseFunction) {
+ BaseFunction bf = (BaseFunction)fun;
+ return bf.Decompile (indent, Decompiler.ONLY_BODY_FLAG);
+ }
+ // ALERT: not sure what the right response here is.
+ return "[native code]\n";
+ }
+
+ /// Create a new JavaScript object.
+ ///
+ /// Equivalent to evaluating "new Object()".
+ ///
+ /// the scope to search for the constructor and to evaluate
+ /// against
+ ///
+ /// the new object
+ ///
+ public IScriptable NewObject (IScriptable scope)
+ {
+ return NewObject (scope, "Object", ScriptRuntime.EmptyArgs);
+ }
+
+ /// Create a new JavaScript object by executing the named constructor.
+ ///
+ /// The call newObject(scope, "Foo") is equivalent to
+ /// evaluating "new Foo()".
+ ///
+ ///
+ /// the scope to search for the constructor and to evaluate against
+ ///
+ /// the name of the constructor to call
+ ///
+ /// the new object
+ ///
+ public IScriptable NewObject (IScriptable scope, string constructorName)
+ {
+ return NewObject (scope, constructorName, ScriptRuntime.EmptyArgs);
+ }
+
+ /// Creates a new JavaScript object by executing the named constructor.
+ ///
+ /// Searches scope for the named constructor, calls it with
+ /// the given arguments, and returns the result.
+ ///
+ /// The code
+ ///
+ /// Object[] args = { "a", "b" };
+ /// newObject(scope, "Foo", args)
+ /// is equivalent to evaluating "new Foo('a', 'b')", assuming that the Foo
+ /// constructor has been defined in scope.
+ ///
+ ///
+ /// The scope to search for the constructor and to evaluate
+ /// against
+ ///
+ /// the name of the constructor to call
+ ///
+ /// the array of arguments for the constructor
+ ///
+ /// the new object
+ ///
+ public IScriptable NewObject (IScriptable scope, string constructorName, object [] args)
+ {
+ scope = ScriptableObject.GetTopLevelScope (scope);
+ IFunction ctor = ScriptRuntime.getExistingCtor (this, scope, constructorName);
+ if (args == null) {
+ args = ScriptRuntime.EmptyArgs;
+ }
+ return ctor.Construct (this, scope, args);
+ }
+
+ /// Create an array with a specified initial length.
+ ///
+ ///
+ /// the scope to create the object in
+ ///
+ /// the initial length (JavaScript arrays may have
+ /// additional properties added dynamically).
+ ///
+ /// the new array object
+ ///
+ public IScriptable NewArray (IScriptable scope, int length)
+ {
+ BuiltinArray result = new BuiltinArray (length);
+ ScriptRuntime.setObjectProtoAndParent (result, scope);
+ return result;
+ }
+
+ /// Create an array with a set of initial elements.
+ ///
+ ///
+ /// the scope to create the object in.
+ ///
+ /// the initial elements. Each object in this array
+ /// must be an acceptable JavaScript type and type
+ /// of array should be exactly Object[], not
+ /// SomeObjectSubclass[].
+ ///
+ /// the new array object.
+ ///
+ public IScriptable NewArray (IScriptable scope, object [] elements)
+ {
+ Type elementType = elements.GetType ().GetElementType ();
+ if (elementType != typeof (object))
+ throw new ArgumentException ();
+ BuiltinArray result = new BuiltinArray (elements);
+ ScriptRuntime.setObjectProtoAndParent (result, scope);
+ return result;
+ }
+
+ /// Get the elements of a JavaScript array.
+ ///
+ /// If the object defines a length property convertible to double number,
+ /// then the number is converted Uint32 value as defined in Ecma 9.6
+ /// and Java array of that size is allocated.
+ /// The array is initialized with the values obtained by
+ /// calling get() on object for each value of i in [0,length-1]. If
+ /// there is not a defined value for a property the Undefined value
+ /// is used to initialize the corresponding element in the array. The
+ /// Java array is then returned.
+ /// If the object doesn't define a length property or it is not a number,
+ /// empty array is returned.
+ ///
+ /// the JavaScript array or array-like object
+ ///
+ /// a Java array of objects
+ ///
+
+ public object [] GetElements (IScriptable obj)
+ {
+ return ScriptRuntime.getArrayElements (obj);
+ }
+
+
+ /// Convenient method to convert java value to its closest representation
+ /// in JavaScript.
+ ///
+ /// If value is an instance of String, Number, Boolean, Function or
+ /// Scriptable, it is returned as it and will be treated as the corresponding
+ /// JavaScript type of string, number, boolean, function and object.
+ ///
+ /// Note that for Number instances during any arithmetic operation in
+ /// JavaScript the engine will always use the result of
+ /// Number.doubleValue() resulting in a precision loss if
+ /// the number can not fit into double.
+ ///
+ /// If value is an instance of Character, it will be converted to string of
+ /// length 1 and its JavaScript type will be string.
+ ///
+ /// The rest of values will be wrapped as LiveConnect objects
+ /// by calling {@link WrapFactory#wrap(Context cx, Scriptable scope,
+ /// Object obj, Class staticType)} as in:
+ ///
+ /// Context cx = Context.getCurrentContext();
+ /// return cx.getWrapFactory().wrap(cx, scope, value, null);
+ ///
+ ///
+ ///
+ /// any Java object
+ ///
+ /// top scope object
+ ///
+ /// value suitable to pass to any API that takes JavaScript values.
+ ///
+ public static object CliToJS (Context cx, object value, IScriptable scope)
+ {
+ if (value is string || CliHelper.IsNumber (value) || value is bool || value is IScriptable) {
+ return value;
+ }
+ else if (value is char) {
+ return Convert.ToString (((char)value));
+ }
+ else {
+ Type type = (value as Type);
+ if (type != null) {
+ return cx.Wrap (scope, value, (Type)value);
+ } else {
+ return cx.Wrap (scope, value, null);
+ }
+ }
+ }
+
+ /// Convert a JavaScript value into the desired type.
+ /// Uses the semantics defined with LiveConnect3 and throws an
+ /// Illegal argument exception if the conversion cannot be performed.
+ ///
+ /// the JavaScript value to convert
+ ///
+ /// the Java type to convert to. Primitive Java
+ /// types are represented using the TYPE fields in the corresponding
+ /// wrapper class in java.lang.
+ ///
+ /// the converted value
+ ///
+ /// EvaluatorException if the conversion cannot be performed
+ public static object JsToCli (object value, System.Type desiredType)
+ {
+ return CliObject.CoerceType (desiredType, value);
+ }
+
+
+
+ /// Rethrow the exception wrapping it as the script runtime exception.
+ /// Unless the exception is instance of {@link EcmaError} or
+ /// {@link EvaluatorException} it will be wrapped as
+ /// {@link WrappedException}, a subclass of {@link EvaluatorException}.
+ /// The resulting exception object always contains
+ /// source name and line number of script that triggered exception.
+ ///
+ /// This method always throws an exception, its return value is provided
+ /// only for convenience to allow a usage like:
+ ///
+ /// throw Context.throwAsScriptRuntimeEx(ex);
+ ///
+ /// to indicate that code after the method is unreachable.
+ ///
+ /// EvaluatorException
+ /// EcmaError
+ public static Exception ThrowAsScriptRuntimeEx (Exception e)
+ {
+ while ((e is TargetInvocationException)) {
+ e = ((TargetInvocationException)e).InnerException;
+ }
+ if (e is EcmaScriptException) {
+ throw e;
+ }
+ throw new EcmaScriptRuntimeException (e);
+ }
+
+ public static bool IsValidOptimizationLevel (int optimizationLevel)
+ {
+ return -1 <= optimizationLevel && optimizationLevel <= 9;
+ }
+
+ public static void CheckOptimizationLevel (int optimizationLevel)
+ {
+ if (IsValidOptimizationLevel (optimizationLevel)) {
+ return;
+ }
+ throw new ArgumentException ("Optimization level outside [-1..9]: " + optimizationLevel);
+ }
+
+ /// Set the security controller for this context.
+ /// SecurityController may only be set if it is currently null
+ /// and {@link SecurityController#hasGlobal()} is false.
+ /// Otherwise a SecurityException is thrown.
+ ///
+ /// a SecurityController object
+ ///
+ /// SecurityException if there is already a SecurityController
+ /// object for this Context or globally installed.
+ ///
+ public SecurityController SecurityController
+ {
+ set
+ {
+ if (m_Sealed)
+ OnSealedMutation ();
+ if (value == null)
+ throw new ArgumentException ();
+ if (securityController != null) {
+ throw new System.Security.SecurityException ("Can not overwrite existing SecurityController object");
+ }
+ if (SecurityController.HasGlobal ()) {
+ throw new System.Security.SecurityException ("Can not overwrite existing global SecurityController object");
+ }
+ securityController = value;
+ }
+ get
+ {
+ SecurityController global = SecurityController.Global;
+ if (global != null) {
+ return global;
+ }
+ return securityController;
+ }
+ }
+
+ /// Get a value corresponding to a key.
+ ///
+ /// Since the Context is associated with a thread it can be
+ /// used to maintain values that can be later retrieved using
+ /// the current thread.
+ ///
+ /// Note that the values are maintained with the Context, so
+ /// if the Context is disassociated from the thread the values
+ /// cannot be retreived. Also, if private data is to be maintained
+ /// in this manner the key should be a java.lang.Object
+ /// whose reference is not divulged to untrusted code.
+ ///
+ /// the key used to lookup the value
+ ///
+ /// a value previously stored using putThreadLocal.
+ ///
+ public object GetThreadLocal (object key)
+ {
+ if (hashtable == null)
+ return null;
+ return hashtable [key];
+ }
+
+ /// Put a value that can later be retrieved using a given key.
+ ///
+ ///
+ /// the key used to index the value
+ ///
+ /// the value to save
+ ///
+ public void PutThreadLocal (object key, object value)
+ {
+ if (m_Sealed)
+ OnSealedMutation ();
+ if (hashtable == null)
+ hashtable = Hashtable.Synchronized (new Hashtable ());
+ hashtable [key] = value;
+ }
+
+ /// Remove values from thread-local storage.
+ /// the key for the entry to remove.
+ ///
+ public void RemoveThreadLocal (object key)
+ {
+ if (m_Sealed)
+ OnSealedMutation ();
+ if (hashtable == null)
+ return;
+ hashtable.Remove (key);
+ }
+
+
+
+ /// Return the current debugger.
+ /// the debugger, or null if none is attached.
+ ///
+ public Debugger Debugger
+ {
+ get
+ {
+ return m_Debugger;
+ }
+ }
+
+ /// Set the associated debugger.
+ /// the debugger to be used on callbacks from
+ /// the engine.
+ ///
+ /// arbitrary object that debugger can use to store
+ /// per Context data.
+ ///
+ public void SetDebugger (Debugger debugger, object contextData)
+ {
+ if (m_Sealed)
+ OnSealedMutation ();
+ this.m_Debugger = debugger;
+ debuggerData = contextData;
+ }
+
+ /// Return DebuggableScript instance if any associated with the script.
+ /// If callable supports DebuggableScript implementation, the method
+ /// returns it. Otherwise null is returned.
+ ///
+ public static DebuggableScript getDebuggableView (IScript script)
+ {
+ if (script is BuiltinFunction) {
+ return ((BuiltinFunction)script).DebuggableView;
+ }
+ return null;
+ }
+
+
+ private Features m_Features = Features.None;
+
+ ///
+ /// Controls certain aspects of script semantics.
+ /// Should be overwritten to alter default behavior.
+ ///
+ /// The default implementation calls
+ /// {@link ContextFactory#hasFeature(Context cx, int featureIndex)}
+ /// that allows to customize Context behavior without introducing
+ /// Context subclasses. {@link ContextFactory} documentation gives
+ /// an example of hasFeature implementation.
+ ///
+ ///
+ /// feature to check
+ ///
+ /// true if the feature feature is turned on
+ ///
+ public bool HasFeature (Features feature)
+ {
+ return (m_Features & feature) == feature;
+ }
+
+ public void SetFeature (Features feature, bool isEnabled)
+ {
+ if (isEnabled) {
+ m_Features |= feature;
+ }
+ else {
+ if (HasFeature (feature))
+ m_Features = m_Features ^ feature;
+ }
+ }
+
+
+ /// Allow application to monitor counter of executed script instructions
+ /// in Context subclasses.
+ /// Run-time calls this when instruction counting is enabled and the counter
+ /// reaches limit set by setInstructionObserverThreshold().
+ /// The method is useful to observe long running scripts and if necessary
+ /// to terminate them.
+ ///
+ /// The instruction counting support is available only for interpreted
+ /// scripts generated when the optimization level is set to -1.
+ ///
+ /// The default implementation calls
+ /// {@link ContextFactory#observeInstructionCount(Context cx,
+ /// int instructionCount)}
+ /// that allows to customize Context behavior without introducing
+ /// Context subclasses.
+ ///
+ ///
+ /// amount of script instruction executed since
+ /// last call to observeInstructionCount
+ ///
+ /// Error to terminate the script
+ protected internal void ObserveInstructionCount (int instructionCount)
+ {
+ Factory.ObserveInstructionCount (this, instructionCount);
+ }
+
+ private object CompileImpl (IScriptable scope, StreamReader sourceReader, string sourceString, string sourceName, int lineno, object securityDomain, bool returnFunction, Interpreter compiler, ErrorReporter compilationErrorReporter)
+ {
+ if (securityDomain != null && securityController == null) {
+ throw new ArgumentException ("securityDomain should be null if setSecurityController() was never called");
+ }
+
+ // One of sourceReader or sourceString has to be null
+ if (!(sourceReader == null ^ sourceString == null))
+ Context.CodeBug ();
+ // scope should be given if and only if compiling function
+ if (!(scope == null ^ returnFunction))
+ Context.CodeBug ();
+
+ CompilerEnvirons compilerEnv = new CompilerEnvirons ();
+ compilerEnv.initFromContext (this);
+ if (compilationErrorReporter == null) {
+ compilationErrorReporter = compilerEnv.getErrorReporter ();
+ }
+
+ if (m_Debugger != null) {
+ if (sourceReader != null) {
+ sourceString = sourceReader.ReadToEnd ();
+ sourceReader = null;
+ }
+ }
+
+ Parser p = new Parser (compilerEnv, compilationErrorReporter);
+ if (returnFunction) {
+ p.calledByCompileFunction = true;
+ }
+ ScriptOrFnNode tree;
+ if (sourceString != null) {
+ tree = p.Parse (sourceString, sourceName, lineno);
+ }
+ else {
+ tree = p.Parse (sourceReader, sourceName, lineno);
+ }
+ if (returnFunction) {
+ if (!(tree.FunctionCount == 1 && tree.FirstChild != null && tree.FirstChild.Type == Token.FUNCTION)) {
+ // TODO: the check just look for the first child
+ // TODO: and allows for more nodes after it for compatibility
+ // TODO: with sources like function() {};;;
+ throw new ArgumentException ("compileFunction only accepts source with single JS function: " + sourceString);
+ }
+ }
+
+
+
+ if (compiler == null) {
+ compiler = new Interpreter ();
+ //compiler = new Compiler();
+ }
+
+ string encodedSource = p.EncodedSource;
+
+ object bytecode = compiler.Compile (compilerEnv, tree, encodedSource, returnFunction);
+
+ if (m_Debugger != null) {
+ if (sourceString == null)
+ Context.CodeBug ();
+ if (bytecode is DebuggableScript) {
+ DebuggableScript dscript = (DebuggableScript)bytecode;
+ NotifyDebugger (this, dscript, sourceString);
+ }
+ else {
+ throw new Exception ("NOT SUPPORTED");
+ }
+ }
+
+ object result;
+ if (returnFunction) {
+ result = compiler.CreateFunctionObject (this, scope, bytecode, securityDomain);
+ }
+ else {
+ result = compiler.CreateScriptObject (bytecode, securityDomain);
+ }
+
+ return result;
+ }
+
+ private static void NotifyDebugger (Context cx, DebuggableScript dscript, string debugSource)
+ {
+ cx.m_Debugger.HandleCompilationDone (cx, dscript, debugSource);
+ for (int i = 0; i != dscript.FunctionCount; ++i) {
+ NotifyDebugger (cx, dscript.GetFunction (i), debugSource);
+ }
+ }
+
+ internal static string GetSourcePositionFromStack (int [] linep)
+ {
+ Context cx = CurrentContext;
+ if (cx == null)
+ return null;
+ if (cx.lastInterpreterFrame != null) {
+ return Interpreter.GetSourcePositionFromStack (cx, linep);
+ }
+
+ System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace ();
+ System.Diagnostics.StackFrame sf = st.GetFrame (0);
+ linep [0] = sf.GetFileLineNumber ();
+ return Path.GetFileName (sf.GetFileName ());
+ }
+
+
+ /// Add a name to the list of names forcing the creation of real
+ /// activation objects for functions.
+ ///
+ ///
+ /// the name of the object to add to the list
+ ///
+ public void AddActivationName (string name)
+ {
+ if (m_Sealed)
+ OnSealedMutation ();
+ if (activationNames == null)
+ activationNames = Hashtable.Synchronized (new Hashtable (5));
+ activationNames [name] = name;
+ }
+
+ /// Check whether the name is in the list of names of objects
+ /// forcing the creation of activation objects.
+ ///
+ ///
+ /// the name of the object to test
+ ///
+ ///
+ /// true if an function activation object is needed.
+ ///
+ public bool IsActivationNeeded (string name)
+ {
+ return activationNames != null && activationNames.ContainsKey (name);
+ }
+
+ /// Remove a name from the list of names forcing the creation of real
+ /// activation objects for functions.
+ ///
+ ///
+ /// the name of the object to remove from the list
+ ///
+ public void RemoveActivationName (string name)
+ {
+ if (m_Sealed)
+ OnSealedMutation ();
+ if (activationNames != null)
+ activationNames.Remove (name);
+ }
+
+ private static string implementationVersion;
+
+ private ContextFactory factory;
+ private bool m_Sealed;
+ private object m_SealKey;
+
+ internal IScriptable topCallScope;
+ internal BuiltinCall currentActivationCall;
+ internal XMLLib cachedXMLLib;
+
+ // for Objects, Arrays to tag themselves as being printed out,
+ // so they don't print themselves out recursively.
+ // Use ObjToIntMap instead of java.util.HashSet for JDK 1.1 compatibility
+ internal ObjToIntMap iterating;
+
+ internal object interpreterSecurityDomain;
+
+ internal Versions m_Version = Versions.Unknown;
+
+ private SecurityController securityController;
+
+ private ErrorReporter m_ErrorReporter;
+ internal RegExpProxy regExpProxy;
+ private System.Globalization.CultureInfo culture;
+ private bool generatingDebug;
+ private bool generatingDebugChanged;
+ private bool generatingSource = true;
+ internal bool compileFunctionsWithDynamicScopeFlag = false;
+ internal bool useDynamicScope;
+ private int m_OptimizationLevel;
+
+ internal Debugger m_Debugger;
+ private object debuggerData;
+ private int enterCount;
+ private Hashtable hashtable;
+
+ private bool creationEventWasSent;
+
+ /// This is the list of names of objects forcing the creation of
+ /// function activation records.
+ ///
+ internal Hashtable activationNames;
+
+ // For the interpreter to store the last frame for error reports etc.
+ internal object lastInterpreterFrame;
+
+ // For the interpreter to store information about previous invocations
+ // interpreter invocations
+ internal ObjArray previousInterpreterInvocations;
+
+ // For instruction counting (interpreter only)
+ internal int instructionCount;
+ internal int instructionThreshold;
+
+ // It can be used to return the second index-like result from function
+ internal int scratchIndex;
+
+ // It can be used to return the second uint32 result from function
+ internal long scratchUint32;
+
+ // It can be used to return the second Scriptable result from function
+ internal IScriptable scratchScriptable;
+ static Context ()
+ {
+ EmptyArgs = ScriptRuntime.EmptyArgs;
+ }
+
+ public void Dispose ()
+ {
+ Context.Exit ();
+ }
+
+ ///
+ /// Throws RuntimeException to indicate failed assertion.
+ /// The function never returns and its return type is RuntimeException
+ /// only to be able to write throw EcmaScriptHelper.CodeBug() if plain
+ /// EcmaScriptHelper.CodeBug() triggers unreachable code error.
+ ///
+ public static Exception CodeBug ()
+ {
+ Exception ex = new Exception ("FAILED ASSERTION");
+ Console.Error.WriteLine (ex.ToString ());
+ throw ex;
+ }
+
+ }
+}
diff --git a/Code/EcmaScript.NET/ContextEvents.cs b/src/EcmaScript.NET/ContextEvents.cs
similarity index 95%
rename from Code/EcmaScript.NET/ContextEvents.cs
rename to src/EcmaScript.NET/ContextEvents.cs
index d7ce984..20a6e39 100644
--- a/Code/EcmaScript.NET/ContextEvents.cs
+++ b/src/EcmaScript.NET/ContextEvents.cs
@@ -1,105 +1,105 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-namespace EcmaScript.NET
-{
-
- public class ContextEventArgs : EventArgs
- {
-
- private Context m_Context = null;
-
- ///
- /// The underlying context
- ///
- public Context Context
- {
- get { return m_Context; }
- }
-
- ///
- /// Creates a new ContextEventArgs object
- ///
- ///
- public ContextEventArgs (Context cx)
- {
- m_Context = cx;
- }
-
- }
-
- public class ContextScriptableEventArgs : ContextEventArgs
- {
-
-
- private IScriptable m_Scope = null;
-
- public ContextScriptableEventArgs (Context cx, IScriptable scope)
- : base (cx)
- {
- m_Scope = scope;
- }
-
- public IScriptable Scope
- {
- get { return m_Scope; }
- }
-
- }
-
-
- ///
- ///
- ///
- public class ContextWrapEventArgs : ContextScriptableEventArgs
- {
-
- private object m_Source = null;
-
- public object Source
- {
- get { return m_Source; }
- }
-
- private object m_Target = null;
-
- public object Target
- {
- get { return m_Target; }
- set { m_Target = null; }
- }
-
-
- private Type m_StaticType = null;
-
- public Type staticType
- {
- get { return m_StaticType; }
- }
-
- public ContextWrapEventArgs (Context cx, IScriptable scope, object obj, Type staticType)
- : base (cx, scope)
- {
- m_Source = obj;
- m_StaticType = staticType;
- }
-
- }
-
- public delegate void ContextEventHandler (object sender, ContextEventArgs e);
-
- public delegate void ContextWrapHandler (object sender, ContextWrapEventArgs e);
-
-}
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+namespace EcmaScript.NET
+{
+
+ public class ContextEventArgs : EventArgs
+ {
+
+ private Context m_Context = null;
+
+ ///
+ /// The underlying context
+ ///
+ public Context Context
+ {
+ get { return m_Context; }
+ }
+
+ ///
+ /// Creates a new ContextEventArgs object
+ ///
+ ///
+ public ContextEventArgs (Context cx)
+ {
+ m_Context = cx;
+ }
+
+ }
+
+ public class ContextScriptableEventArgs : ContextEventArgs
+ {
+
+
+ private IScriptable m_Scope = null;
+
+ public ContextScriptableEventArgs (Context cx, IScriptable scope)
+ : base (cx)
+ {
+ m_Scope = scope;
+ }
+
+ public IScriptable Scope
+ {
+ get { return m_Scope; }
+ }
+
+ }
+
+
+ ///
+ ///
+ ///
+ public class ContextWrapEventArgs : ContextScriptableEventArgs
+ {
+
+ private object m_Source = null;
+
+ public object Source
+ {
+ get { return m_Source; }
+ }
+
+ private object m_Target = null;
+
+ public object Target
+ {
+ get { return m_Target; }
+ set { m_Target = null; }
+ }
+
+
+ private Type m_StaticType = null;
+
+ public Type staticType
+ {
+ get { return m_StaticType; }
+ }
+
+ public ContextWrapEventArgs (Context cx, IScriptable scope, object obj, Type staticType)
+ : base (cx, scope)
+ {
+ m_Source = obj;
+ m_StaticType = staticType;
+ }
+
+ }
+
+ public delegate void ContextEventHandler (object sender, ContextEventArgs e);
+
+ public delegate void ContextWrapHandler (object sender, ContextWrapEventArgs e);
+
+}
diff --git a/Code/EcmaScript.NET/ContextFactory.cs b/src/EcmaScript.NET/ContextFactory.cs
similarity index 95%
rename from Code/EcmaScript.NET/ContextFactory.cs
rename to src/EcmaScript.NET/ContextFactory.cs
index 65819fc..f80d038 100644
--- a/Code/EcmaScript.NET/ContextFactory.cs
+++ b/src/EcmaScript.NET/ContextFactory.cs
@@ -1,150 +1,150 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-namespace EcmaScript.NET
-{
-
- /// Factory class that Rhino runtime use to create new {@link Context}
- /// instances or to notify about Context execution.
- ///
- /// When Rhino runtime needs to create new {@link Context} instance during
- /// execution of {@link Context#enter()} or {@link Context}, it will call
- /// {@link #makeContext()} of the current global ContextFactory.
- /// See {@link #getGlobal()} and {@link #initGlobal(ContextFactory)}.
- ///
- /// It is also possible to use explicit ContextFactory instances for Context
- /// creation. This is useful to have a set of independent Rhino runtime
- /// instances under single JVM. See {@link #call(ContextAction)}.
- ///
- ///
-
- public class ContextFactory
- {
- /// Get global ContextFactory.
- ///
- ///
- public static ContextFactory Global
- {
- get
- {
- return global;
- }
-
- }
-
- /// Checks if this is a sealed ContextFactory.
- virtual public bool Sealed
- {
- get
- {
- return zealed;
- }
-
- }
- private static volatile bool hasCustomGlobal;
- private static ContextFactory global = new ContextFactory ();
-
- private volatile bool zealed;
-
-
- /// Notify about newly created {@link Context} object.
- public event ContextEventHandler OnContextCreated;
-
- /// Notify that the specified {@link Context} instance is no longer
- /// associated with the current thread.
- ///
- public event ContextEventHandler OnContextReleased;
-
- /// Check if global factory was set.
- /// Return true to indicate that {@link #initGlobal(ContextFactory)} was
- /// already called and false to indicate that the global factory was not
- /// explicitly set.
- ///
- ///
- public static bool HasExplicitGlobal
- {
- get
- {
- return hasCustomGlobal;
- }
- }
-
- /// Set global ContextFactory.
- /// The method can only be called once.
- ///
- ///
- public static void InitGlobal (ContextFactory factory)
- {
- if (factory == null) {
- throw new ArgumentException ();
- }
- if (hasCustomGlobal) {
- throw new ApplicationException ();
- }
- hasCustomGlobal = true;
- global = factory;
- }
-
-
- /// Execute top call to script or function.
- /// When the runtime is about to execute a script or function that will
- /// create the first stack frame with scriptable code, it calls this method
- /// to perform the real call. In this way execution of any script
- /// happens inside this function.
- ///
- protected internal virtual object DoTopCall (ICallable callable, Context cx, IScriptable scope, IScriptable thisObj, object [] args)
- {
- return callable.Call (cx, scope, thisObj, args);
- }
-
- /// Implementation of
- /// {@link Context#observeInstructionCount(int instructionCount)}.
- /// This can be used to customize {@link Context} without introducing
- /// additional subclasses.
- ///
- protected internal virtual void ObserveInstructionCount (Context cx, int instructionCount)
- {
- }
-
- protected internal virtual void FireOnContextCreated (Context cx)
- {
- if (OnContextCreated != null)
- OnContextCreated (this, new ContextEventArgs (cx));
- }
-
- protected internal virtual void FireOnContextReleased (Context cx)
- {
- if (OnContextReleased != null)
- OnContextReleased (this, new ContextEventArgs (cx));
- }
-
-
- /// Seal this ContextFactory so any attempt to modify it like to add or
- /// remove its listeners will throw an exception.
- ///
- public void Seal ()
- {
- CheckNotSealed ();
- zealed = true;
- }
-
- protected internal void CheckNotSealed ()
- {
- if (zealed)
- throw new ApplicationException ();
- }
-
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+namespace EcmaScript.NET
+{
+
+ /// Factory class that Rhino runtime use to create new {@link Context}
+ /// instances or to notify about Context execution.
+ ///
+ /// When Rhino runtime needs to create new {@link Context} instance during
+ /// execution of {@link Context#enter()} or {@link Context}, it will call
+ /// {@link #makeContext()} of the current global ContextFactory.
+ /// See {@link #getGlobal()} and {@link #initGlobal(ContextFactory)}.
+ ///
+ /// It is also possible to use explicit ContextFactory instances for Context
+ /// creation. This is useful to have a set of independent Rhino runtime
+ /// instances under single JVM. See {@link #call(ContextAction)}.
+ ///
+ ///
+
+ public class ContextFactory
+ {
+ /// Get global ContextFactory.
+ ///
+ ///
+ public static ContextFactory Global
+ {
+ get
+ {
+ return global;
+ }
+
+ }
+
+ /// Checks if this is a sealed ContextFactory.
+ virtual public bool Sealed
+ {
+ get
+ {
+ return zealed;
+ }
+
+ }
+ private static volatile bool hasCustomGlobal;
+ private static ContextFactory global = new ContextFactory ();
+
+ private volatile bool zealed;
+
+
+ /// Notify about newly created {@link Context} object.
+ public event ContextEventHandler OnContextCreated;
+
+ /// Notify that the specified {@link Context} instance is no longer
+ /// associated with the current thread.
+ ///
+ public event ContextEventHandler OnContextReleased;
+
+ /// Check if global factory was set.
+ /// Return true to indicate that {@link #initGlobal(ContextFactory)} was
+ /// already called and false to indicate that the global factory was not
+ /// explicitly set.
+ ///
+ ///
+ public static bool HasExplicitGlobal
+ {
+ get
+ {
+ return hasCustomGlobal;
+ }
+ }
+
+ /// Set global ContextFactory.
+ /// The method can only be called once.
+ ///
+ ///
+ public static void InitGlobal (ContextFactory factory)
+ {
+ if (factory == null) {
+ throw new ArgumentException ();
+ }
+ if (hasCustomGlobal) {
+ throw new Exception ();
+ }
+ hasCustomGlobal = true;
+ global = factory;
+ }
+
+
+ /// Execute top call to script or function.
+ /// When the runtime is about to execute a script or function that will
+ /// create the first stack frame with scriptable code, it calls this method
+ /// to perform the real call. In this way execution of any script
+ /// happens inside this function.
+ ///
+ protected internal virtual object DoTopCall (ICallable callable, Context cx, IScriptable scope, IScriptable thisObj, object [] args)
+ {
+ return callable.Call (cx, scope, thisObj, args);
+ }
+
+ /// Implementation of
+ /// {@link Context#observeInstructionCount(int instructionCount)}.
+ /// This can be used to customize {@link Context} without introducing
+ /// additional subclasses.
+ ///
+ protected internal virtual void ObserveInstructionCount (Context cx, int instructionCount)
+ {
+ }
+
+ protected internal virtual void FireOnContextCreated (Context cx)
+ {
+ if (OnContextCreated != null)
+ OnContextCreated (this, new ContextEventArgs (cx));
+ }
+
+ protected internal virtual void FireOnContextReleased (Context cx)
+ {
+ if (OnContextReleased != null)
+ OnContextReleased (this, new ContextEventArgs (cx));
+ }
+
+
+ /// Seal this ContextFactory so any attempt to modify it like to add or
+ /// remove its listeners will throw an exception.
+ ///
+ public void Seal ()
+ {
+ CheckNotSealed ();
+ zealed = true;
+ }
+
+ protected internal void CheckNotSealed ()
+ {
+ if (zealed)
+ throw new Exception ();
+ }
+
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/Continuation.cs b/src/EcmaScript.NET/Continuation.cs
similarity index 96%
rename from Code/EcmaScript.NET/Continuation.cs
rename to src/EcmaScript.NET/Continuation.cs
index bd0d89e..7df3552 100644
--- a/Code/EcmaScript.NET/Continuation.cs
+++ b/src/EcmaScript.NET/Continuation.cs
@@ -1,130 +1,130 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-using EcmaScript.NET;
-
-namespace EcmaScript.NET
-{
-
-
- public sealed class Continuation : IdScriptableObject, IFunction
- {
- public object Implementation
- {
- get
- {
- return implementation;
- }
-
- }
- override public string ClassName
- {
- get
- {
- return "Continuation";
- }
-
- }
-
-
- private static readonly object FTAG = new object ();
-
- private object implementation;
-
- public static void Init (IScriptable scope, bool zealed)
- {
- Continuation obj = new Continuation ();
- obj.ExportAsJSClass (MAX_PROTOTYPE_ID, scope, zealed);
- }
-
- public void initImplementation (object implementation)
- {
- this.implementation = implementation;
- }
-
- public IScriptable Construct (Context cx, IScriptable scope, object [] args)
- {
- throw Context.ReportRuntimeError ("Direct call is not supported");
- }
-
- public object Call (Context cx, IScriptable scope, IScriptable thisObj, object [] args)
- {
- return Interpreter.restartContinuation (this, cx, scope, args);
- }
-
- public static bool IsContinuationConstructor (IdFunctionObject f)
- {
- if (f.HasTag (FTAG) && f.MethodId == Id_constructor) {
- return true;
- }
- return false;
- }
-
- protected internal override void InitPrototypeId (int id)
- {
- string s;
- int arity;
- switch (id) {
-
- case Id_constructor:
- arity = 0;
- s = "constructor";
- break;
-
- default:
- throw new ArgumentException (Convert.ToString (id));
-
- }
- InitPrototypeMethod (FTAG, id, s, arity);
- }
-
- public override object ExecIdCall (IdFunctionObject f, Context cx, IScriptable scope, IScriptable thisObj, object [] args)
- {
- if (!f.HasTag (FTAG)) {
- return base.ExecIdCall (f, cx, scope, thisObj, args);
- }
- int id = f.MethodId;
- switch (id) {
-
- case Id_constructor:
- throw Context.ReportRuntimeError ("Direct call is not supported");
- }
- throw new ArgumentException (Convert.ToString (id));
- }
-
- // #string_id_map#
-
- protected internal override int FindPrototypeId (string s)
- {
- int id;
- #region Generated PrototypeId Switch
- L0: {
- id = 0;
- string X = null;
- if (s.Length == 11) { X = "constructor"; id = Id_constructor; }
- if (X != null && X != s && !X.Equals (s))
- id = 0;
- }
- EL0:
- #endregion
- return id;
- }
-
- #region PrototypeIds
- private const int Id_constructor = 1;
- private const int MAX_PROTOTYPE_ID = 1;
- #endregion
-
- }
-}
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+using EcmaScript.NET;
+
+namespace EcmaScript.NET
+{
+
+
+ public sealed class Continuation : IdScriptableObject, IFunction
+ {
+ public object Implementation
+ {
+ get
+ {
+ return implementation;
+ }
+
+ }
+ override public string ClassName
+ {
+ get
+ {
+ return "Continuation";
+ }
+
+ }
+
+
+ private static readonly object FTAG = new object ();
+
+ private object implementation;
+
+ public static void Init (IScriptable scope, bool zealed)
+ {
+ Continuation obj = new Continuation ();
+ obj.ExportAsJSClass (MAX_PROTOTYPE_ID, scope, zealed);
+ }
+
+ public void initImplementation (object implementation)
+ {
+ this.implementation = implementation;
+ }
+
+ public IScriptable Construct (Context cx, IScriptable scope, object [] args)
+ {
+ throw Context.ReportRuntimeError ("Direct call is not supported");
+ }
+
+ public object Call (Context cx, IScriptable scope, IScriptable thisObj, object [] args)
+ {
+ return Interpreter.restartContinuation (this, cx, scope, args);
+ }
+
+ public static bool IsContinuationConstructor (IdFunctionObject f)
+ {
+ if (f.HasTag (FTAG) && f.MethodId == Id_constructor) {
+ return true;
+ }
+ return false;
+ }
+
+ protected internal override void InitPrototypeId (int id)
+ {
+ string s;
+ int arity;
+ switch (id) {
+
+ case Id_constructor:
+ arity = 0;
+ s = "constructor";
+ break;
+
+ default:
+ throw new ArgumentException (Convert.ToString (id));
+
+ }
+ InitPrototypeMethod (FTAG, id, s, arity);
+ }
+
+ public override object ExecIdCall (IdFunctionObject f, Context cx, IScriptable scope, IScriptable thisObj, object [] args)
+ {
+ if (!f.HasTag (FTAG)) {
+ return base.ExecIdCall (f, cx, scope, thisObj, args);
+ }
+ int id = f.MethodId;
+ switch (id) {
+
+ case Id_constructor:
+ throw Context.ReportRuntimeError ("Direct call is not supported");
+ }
+ throw new ArgumentException (Convert.ToString (id));
+ }
+
+ // #string_id_map#
+
+ protected internal override int FindPrototypeId (string s)
+ {
+ int id;
+ #region Generated PrototypeId Switch
+ L0: {
+ id = 0;
+ string X = null;
+ if (s.Length == 11) { X = "constructor"; id = Id_constructor; }
+ if (X != null && X != s && !X.Equals (s))
+ id = 0;
+ }
+ EL0:
+ #endregion
+ return id;
+ }
+
+ #region PrototypeIds
+ private const int Id_constructor = 1;
+ private const int MAX_PROTOTYPE_ID = 1;
+ #endregion
+
+ }
+}
diff --git a/Code/EcmaScript.NET/Debugging/DebugFrame.cs b/src/EcmaScript.NET/Debugging/DebugFrame.cs
similarity index 97%
rename from Code/EcmaScript.NET/Debugging/DebugFrame.cs
rename to src/EcmaScript.NET/Debugging/DebugFrame.cs
index d8f263e..a6b7208 100644
--- a/Code/EcmaScript.NET/Debugging/DebugFrame.cs
+++ b/src/EcmaScript.NET/Debugging/DebugFrame.cs
@@ -1,68 +1,68 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-// API class
-using System;
-using Context = EcmaScript.NET.Context;
-using Scriptable = EcmaScript.NET.IScriptable;
-namespace EcmaScript.NET.Debugging
-{
-
- /// Interface to implement if the application is interested in receiving debug
- /// information during execution of a particular script or function.
- ///
- public interface DebugFrame
- {
-
- /// Called when execution is ready to start bytecode interpretation for entered a particular function or script.
- /// current Context for this thread
- ///
- /// the activation scope for the function or script.
- ///
- /// value of the JavaScript this object
- ///
- /// the array of arguments
- ///
- void OnEnter (Context cx, IScriptable activation, IScriptable thisObj, object [] args);
- /// Called when executed code reaches new line in the source.
- /// current Context for this thread
- ///
- /// current line number in the script source
- ///
- void OnLineChange (Context cx, int lineNumber);
-
- /// Called when thrown exception is handled by the function or script.
- /// current Context for this thread
- ///
- /// exception object
- ///
- void OnExceptionThrown (Context cx, Exception ex);
-
- /// Called when the function or script for this frame is about to return.
- /// current Context for this thread
- ///
- /// if true function will leave by throwing exception, otherwise it
- /// will execute normal return
- ///
- /// function result in case of normal return or
- /// exception object if about to throw exception
- ///
- void OnExit (Context cx, bool byThrow, object resultOrException);
-
- ///
- /// Called when the function or script executes a 'debugger' statement.
- ///
- /// current Context for this thread
- void OnDebuggerStatement(Context cx);
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+// API class
+using System;
+using Context = EcmaScript.NET.Context;
+using Scriptable = EcmaScript.NET.IScriptable;
+namespace EcmaScript.NET.Debugging
+{
+
+ /// Interface to implement if the application is interested in receiving debug
+ /// information during execution of a particular script or function.
+ ///
+ public interface DebugFrame
+ {
+
+ /// Called when execution is ready to start bytecode interpretation for entered a particular function or script.
+ /// current Context for this thread
+ ///
+ /// the activation scope for the function or script.
+ ///
+ /// value of the JavaScript this object
+ ///
+ /// the array of arguments
+ ///
+ void OnEnter (Context cx, IScriptable activation, IScriptable thisObj, object [] args);
+ /// Called when executed code reaches new line in the source.
+ /// current Context for this thread
+ ///
+ /// current line number in the script source
+ ///
+ void OnLineChange (Context cx, int lineNumber);
+
+ /// Called when thrown exception is handled by the function or script.
+ /// current Context for this thread
+ ///
+ /// exception object
+ ///
+ void OnExceptionThrown (Context cx, Exception ex);
+
+ /// Called when the function or script for this frame is about to return.
+ /// current Context for this thread
+ ///
+ /// if true function will leave by throwing exception, otherwise it
+ /// will execute normal return
+ ///
+ /// function result in case of normal return or
+ /// exception object if about to throw exception
+ ///
+ void OnExit (Context cx, bool byThrow, object resultOrException);
+
+ ///
+ /// Called when the function or script executes a 'debugger' statement.
+ ///
+ /// current Context for this thread
+ void OnDebuggerStatement(Context cx);
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/Debugging/DebuggableObject.cs b/src/EcmaScript.NET/Debugging/DebuggableObject.cs
similarity index 97%
rename from Code/EcmaScript.NET/Debugging/DebuggableObject.cs
rename to src/EcmaScript.NET/Debugging/DebuggableObject.cs
index b960823..73bacc2 100644
--- a/Code/EcmaScript.NET/Debugging/DebuggableObject.cs
+++ b/src/EcmaScript.NET/Debugging/DebuggableObject.cs
@@ -1,40 +1,40 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-// API class
-using System;
-namespace EcmaScript.NET.Debugging
-{
-
- /// This interface exposes debugging information from objects.
- public interface DebuggableObject
- {
- /// Returns an array of ids for the properties of the object.
- ///
- /// All properties, even those with attribute {DontEnum}, are listed.
- /// This allows the debugger to display all properties of the object.
- ///
- ///
- /// an array of java.lang.Objects with an entry for every
- /// listed property. Properties accessed via an integer index will
- /// have a corresponding
- /// Integer entry in the returned array. Properties accessed by
- /// a String will have a String entry in the returned array.
- ///
- object [] AllIds
- {
- get;
-
- }
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+// API class
+using System;
+namespace EcmaScript.NET.Debugging
+{
+
+ /// This interface exposes debugging information from objects.
+ public interface DebuggableObject
+ {
+ /// Returns an array of ids for the properties of the object.
+ ///
+ /// All properties, even those with attribute {DontEnum}, are listed.
+ /// This allows the debugger to display all properties of the object.
+ ///
+ ///
+ /// an array of java.lang.Objects with an entry for every
+ /// listed property. Properties accessed via an integer index will
+ /// have a corresponding
+ /// Integer entry in the returned array. Properties accessed by
+ /// a String will have a String entry in the returned array.
+ ///
+ object [] AllIds
+ {
+ get;
+
+ }
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/Debugging/DebuggableScript.cs b/src/EcmaScript.NET/Debugging/DebuggableScript.cs
similarity index 96%
rename from Code/EcmaScript.NET/Debugging/DebuggableScript.cs
rename to src/EcmaScript.NET/Debugging/DebuggableScript.cs
index c192aff..c997228 100644
--- a/Code/EcmaScript.NET/Debugging/DebuggableScript.cs
+++ b/src/EcmaScript.NET/Debugging/DebuggableScript.cs
@@ -1,108 +1,108 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-// API class
-using System;
-namespace EcmaScript.NET.Debugging
-{
-
- /// This interface exposes debugging information from executable
- /// code (either functions or top-level scripts).
- ///
- public interface DebuggableScript
- {
- bool TopLevel
- {
- get;
-
- }
- /// Get name of the function described by this script.
- /// Return null or an empty string if this script is not function.
- ///
- string FunctionName
- {
- get;
-
- }
- /// Get number of declared parameters in function.
- /// Return 0 if this script is not function.
- ///
- ///
- int ParamCount
- {
- get;
-
- }
- /// Get number of declared parameters and local variables.
- /// Return number of declared global variables if this script is not
- /// function.
- ///
- ///
- int ParamAndVarCount
- {
- get;
-
- }
- /// Get the name of the source (usually filename or URL)
- /// of the script.
- ///
- string SourceName
- {
- get;
-
- }
- /// Returns true if this script or function were runtime-generated
- /// from JavaScript using eval function or Function
- /// or Script constructors.
- ///
- bool GeneratedScript
- {
- get;
-
- }
- /// Get array containing the line numbers that
- /// that can be passed to DebugFrame.onLineChange().
- /// Note that line order in the resulting array is arbitrary
- ///
- int [] LineNumbers
- {
- get;
-
- }
- int FunctionCount
- {
- get;
-
- }
- DebuggableScript Parent
- {
- get;
-
- }
-
- /// Returns true if this is a function, false if it is a script.
- bool IsFunction ();
-
- /// Get name of a declared parameter or local variable.
- /// index should be less then {@link #getParamAndVarCount()}.
- /// If index < {@link #getParamCount()}, return
- /// the name of the corresponding parameter, otherwise return the name
- /// of variable.
- /// If this script is not function, return the name of the declared
- /// global variable.
- ///
- string GetParamOrVarName (int index);
-
- DebuggableScript GetFunction (int index);
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+// API class
+using System;
+namespace EcmaScript.NET.Debugging
+{
+
+ /// This interface exposes debugging information from executable
+ /// code (either functions or top-level scripts).
+ ///
+ public interface DebuggableScript
+ {
+ bool TopLevel
+ {
+ get;
+
+ }
+ /// Get name of the function described by this script.
+ /// Return null or an empty string if this script is not function.
+ ///
+ string FunctionName
+ {
+ get;
+
+ }
+ /// Get number of declared parameters in function.
+ /// Return 0 if this script is not function.
+ ///
+ ///
+ int ParamCount
+ {
+ get;
+
+ }
+ /// Get number of declared parameters and local variables.
+ /// Return number of declared global variables if this script is not
+ /// function.
+ ///
+ ///
+ int ParamAndVarCount
+ {
+ get;
+
+ }
+ /// Get the name of the source (usually filename or URL)
+ /// of the script.
+ ///
+ string SourceName
+ {
+ get;
+
+ }
+ /// Returns true if this script or function were runtime-generated
+ /// from JavaScript using eval function or Function
+ /// or Script constructors.
+ ///
+ bool GeneratedScript
+ {
+ get;
+
+ }
+ /// Get array containing the line numbers that
+ /// that can be passed to DebugFrame.onLineChange().
+ /// Note that line order in the resulting array is arbitrary
+ ///
+ int [] LineNumbers
+ {
+ get;
+
+ }
+ int FunctionCount
+ {
+ get;
+
+ }
+ DebuggableScript Parent
+ {
+ get;
+
+ }
+
+ /// Returns true if this is a function, false if it is a script.
+ bool IsFunction ();
+
+ /// Get name of a declared parameter or local variable.
+ /// index should be less then {@link #getParamAndVarCount()}.
+ /// If index < {@link #getParamCount()}, return
+ /// the name of the corresponding parameter, otherwise return the name
+ /// of variable.
+ /// If this script is not function, return the name of the declared
+ /// global variable.
+ ///
+ string GetParamOrVarName (int index);
+
+ DebuggableScript GetFunction (int index);
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/Debugging/Debugger.cs b/src/EcmaScript.NET/Debugging/Debugger.cs
similarity index 97%
rename from Code/EcmaScript.NET/Debugging/Debugger.cs
rename to src/EcmaScript.NET/Debugging/Debugger.cs
index 970f451..06b279a 100644
--- a/Code/EcmaScript.NET/Debugging/Debugger.cs
+++ b/src/EcmaScript.NET/Debugging/Debugger.cs
@@ -1,43 +1,43 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-// API class
-using System;
-using Context = EcmaScript.NET.Context;
-namespace EcmaScript.NET.Debugging
-{
-
- /// Interface to implement if the application is interested in receiving debug
- /// information.
- ///
- public interface Debugger
- {
-
- /// Called when compilation of a particular function or script into internal
- /// bytecode is done.
- ///
- /// current Context for this thread
- ///
- /// object describing the function or script
- ///
- /// the function or script source
- ///
- void HandleCompilationDone (Context cx, DebuggableScript fnOrScript, string source);
-
- /// Called when execution entered a particular function or script.
- /// implementation of DebugFrame which receives debug information during
- /// the function or script execution or null otherwise
- ///
- DebugFrame GetFrame (Context cx, DebuggableScript fnOrScript);
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+// API class
+using System;
+using Context = EcmaScript.NET.Context;
+namespace EcmaScript.NET.Debugging
+{
+
+ /// Interface to implement if the application is interested in receiving debug
+ /// information.
+ ///
+ public interface Debugger
+ {
+
+ /// Called when compilation of a particular function or script into internal
+ /// bytecode is done.
+ ///
+ /// current Context for this thread
+ ///
+ /// object describing the function or script
+ ///
+ /// the function or script source
+ ///
+ void HandleCompilationDone (Context cx, DebuggableScript fnOrScript, string source);
+
+ /// Called when execution entered a particular function or script.
+ /// implementation of DebugFrame which receives debug information during
+ /// the function or script execution or null otherwise
+ ///
+ DebugFrame GetFrame (Context cx, DebuggableScript fnOrScript);
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/Decompiler.cs b/src/EcmaScript.NET/Decompiler.cs
similarity index 96%
rename from Code/EcmaScript.NET/Decompiler.cs
rename to src/EcmaScript.NET/Decompiler.cs
index 5eed814..77f6496 100644
--- a/Code/EcmaScript.NET/Decompiler.cs
+++ b/src/EcmaScript.NET/Decompiler.cs
@@ -1,1032 +1,1032 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-using EcmaScript.NET.Collections;
-
-namespace EcmaScript.NET
-{
-
- /// The following class save decompilation information about the source.
- /// Source information is returned from the parser as a String
- /// associated with function nodes and with the toplevel script. When
- /// saved in the constant pool of a class, this string will be UTF-8
- /// encoded, and token values will occupy a single byte.
- /// Source is saved (mostly) as token numbers. The tokens saved pretty
- /// much correspond to the token stream of a 'canonical' representation
- /// of the input program, as directed by the parser. (There were a few
- /// cases where tokens could have been left out where decompiler could
- /// easily reconstruct them, but I left them in for clarity). (I also
- /// looked adding source collection to TokenStream instead, where I
- /// could have limited the changes to a few lines in getToken... but
- /// this wouldn't have saved any space in the resulting source
- /// representation, and would have meant that I'd have to duplicate
- /// parser logic in the decompiler to disambiguate situations where
- /// newlines are important.) The function decompile expands the
- /// tokens back into their string representations, using simple
- /// lookahead to correct spacing and indentation.
- ///
- /// Assignments are saved as two-token pairs (Token.ASSIGN, op). Number tokens
- /// are stored inline, as a NUMBER token, a character representing the type, and
- /// either 1 or 4 characters representing the bit-encoding of the number. String
- /// types NAME, STRING and OBJECT are currently stored as a token type,
- /// followed by a character giving the length of the string (assumed to
- /// be less than 2^16), followed by the characters of the string
- /// inlined into the source string. Changing this to some reference to
- /// to the string in the compiled class' constant pool would probably
- /// save a lot of space... but would require some method of deriving
- /// the final constant pool entry from information available at parse
- /// time.
- ///
- public class Decompiler
- {
- internal string EncodedSource
- {
- get
- {
- return SourceToString(0);
- }
-
- }
- internal int CurrentOffset
- {
- get
- {
- return sourceTop;
- }
-
- }
- /// Flag to indicate that the decompilation should omit the
- /// function header and trailing brace.
- ///
- public const int ONLY_BODY_FLAG = 1 << 0;
-
- /// Flag to indicate that the decompilation generates toSource result.
- public const int TO_SOURCE_FLAG = 1 << 1;
-
- public const int TO_STRING_FLAG = 1 << 2;
-
- /// Decompilation property to specify initial ident value.
- public const int INITIAL_INDENT_PROP = 1;
-
- /// Decompilation property to specify default identation offset.
- public const int INDENT_GAP_PROP = 2;
-
- /// Decompilation property to specify identation offset for case labels.
- public const int CASE_GAP_PROP = 3;
-
- // Marker to denote the last RC of function so it can be distinguished from
- // the last RC of object literals in case of function expressions
- private const int FUNCTION_END = 147;
-
- internal int MarkFunctionStart(int functionType)
- {
- int savedOffset = CurrentOffset;
- AddToken(Token.FUNCTION);
- Append((char)functionType);
- return savedOffset;
- }
-
- internal int MarkFunctionEnd(int functionStart)
- {
- int offset = CurrentOffset;
- Append((char)FUNCTION_END);
- return offset;
- }
-
- internal void AddToken(int token)
- {
- if (!(0 <= token && token <= Token.LAST_TOKEN))
- throw new ArgumentException();
-
- Append((char)token);
- }
-
- internal void AddEol(int token)
- {
- if (!(0 <= token && token <= Token.LAST_TOKEN))
- throw new ArgumentException();
-
- Append((char)token);
- Append((char)Token.EOL);
- }
-
- internal void AddName(string str)
- {
- AddToken(Token.NAME);
- AppendString(str);
- }
-
- internal void AddString(string str)
- {
- AddToken(Token.STRING);
- AppendString(str);
- }
-
- internal void AddRegexp(string regexp, string flags)
- {
- AddToken(Token.REGEXP);
- AppendString('/' + regexp + '/' + flags);
- }
-
- internal void AddJScriptConditionalComment(String str)
- {
- AddToken(Token.CONDCOMMENT);
- AppendString(str);
- }
-
- internal void AddPreservedComment(String str)
- {
- AddToken(Token.KEEPCOMMENT);
- AppendString(str);
- }
-
- internal void AddNumber(double n)
- {
- AddToken(Token.NUMBER);
-
- /* encode the number in the source stream.
- * Save as NUMBER type (char | char char char char)
- * where type is
- * 'D' - double, 'S' - short, 'J' - long.
-
- * We need to retain float vs. integer type info to keep the
- * behavior of liveconnect type-guessing the same after
- * decompilation. (Liveconnect tries to present 1.0 to Java
- * as a float/double)
- * OPT: This is no longer true. We could compress the format.
-
- * This may not be the most space-efficient encoding;
- * the chars created below may take up to 3 bytes in
- * constant pool UTF-8 encoding, so a Double could take
- * up to 12 bytes.
- */
-
- long lbits = (long)n;
- if (lbits != n)
- {
- // if it's floating point, save as a Double bit pattern.
- // (12/15/97 our scanner only returns Double for f.p.)
- lbits = BitConverter.DoubleToInt64Bits(n);
- Append('D');
- Append((char)(lbits >> 48));
- Append((char)(lbits >> 32));
- Append((char)(lbits >> 16));
- Append((char)lbits);
- }
- else
- {
- // we can ignore negative values, bc they're already prefixed
- // by NEG
- if (lbits < 0)
- Context.CodeBug();
-
- // will it fit in a char?
- // this gives a short encoding for integer values up to 2^16.
- if (lbits <= char.MaxValue)
- {
- Append('S');
- Append((char)lbits);
- }
- else
- {
- // Integral, but won't fit in a char. Store as a long.
- Append('J');
- Append((char)(lbits >> 48));
- Append((char)(lbits >> 32));
- Append((char)(lbits >> 16));
- Append((char)lbits);
- }
- }
- }
-
- private void AppendString(string str)
- {
- int L = str.Length;
- int lengthEncodingSize = 1;
- if (L >= 0x8000)
- {
- lengthEncodingSize = 2;
- }
- int nextTop = sourceTop + lengthEncodingSize + L;
- if (nextTop > sourceBuffer.Length)
- {
- IncreaseSourceCapacity(nextTop);
- }
- if (L >= 0x8000)
- {
- // Use 2 chars to encode strings exceeding 32K, were the highest
- // bit in the first char indicates presence of the next byte
- sourceBuffer[sourceTop] = (char)(0x8000 | (int)((uint)L >> 16));
- ++sourceTop;
- }
- sourceBuffer[sourceTop] = (char)L;
- ++sourceTop;
- str.ToCharArray(0, L).CopyTo(sourceBuffer, sourceTop);
- sourceTop = nextTop;
- }
-
- private void Append(char c)
- {
- if (sourceTop == sourceBuffer.Length)
- {
- IncreaseSourceCapacity(sourceTop + 1);
- }
- sourceBuffer[sourceTop] = c;
- ++sourceTop;
- }
-
- private void IncreaseSourceCapacity(int minimalCapacity)
- {
- // Call this only when capacity increase is must
- if (minimalCapacity <= sourceBuffer.Length)
- Context.CodeBug();
- int newCapacity = sourceBuffer.Length * 2;
- if (newCapacity < minimalCapacity)
- {
- newCapacity = minimalCapacity;
- }
- char[] tmp = new char[newCapacity];
- Array.Copy(sourceBuffer, 0, tmp, 0, sourceTop);
- sourceBuffer = tmp;
- }
-
- private string SourceToString(int offset)
- {
- if (offset < 0 || sourceTop < offset)
- Context.CodeBug();
- return new string(sourceBuffer, offset, sourceTop - offset);
- }
-
- /// Decompile the source information associated with this js
- /// function/script back into a string. For the most part, this
- /// just means translating tokens back to their string
- /// representations; there's a little bit of lookahead logic to
- /// decide the proper spacing/indentation. Most of the work in
- /// mapping the original source to the prettyprinted decompiled
- /// version is done by the parser.
- ///
- ///
- /// encoded source tree presentation
- ///
- ///
- /// flags to select output format
- ///
- ///
- /// indentation properties
- ///
- ///
- public static string Decompile(string source, int flags, UintMap properties)
- {
- int length = source.Length;
- if (length == 0)
- {
- return "";
- }
-
- int indent = properties.getInt(INITIAL_INDENT_PROP, 0);
- if (indent < 0)
- throw new ArgumentException();
- int indentGap = properties.getInt(INDENT_GAP_PROP, 4);
- if (indentGap < 0)
- throw new ArgumentException();
- int caseGap = properties.getInt(CASE_GAP_PROP, 2);
- if (caseGap < 0)
- throw new ArgumentException();
-
- System.Text.StringBuilder result = new System.Text.StringBuilder();
- bool justFunctionBody = (0 != (flags & Decompiler.ONLY_BODY_FLAG));
- bool toSource = (0 != (flags & Decompiler.TO_SOURCE_FLAG));
- bool toString = (0 != (flags & Decompiler.TO_STRING_FLAG));
-
- // Spew tokens in source, for debugging.
- // as TYPE number char
- if (printSource)
- {
- System.Console.Error.WriteLine("length:" + length);
- for (int i = 0; i < length; ++i)
- {
- // Note that tokenToName will fail unless Context.printTrees
- // is true.
- string tokenname = null;
- if (Token.printNames)
- {
- tokenname = Token.name(source[i]);
- }
- if (tokenname == null)
- {
- tokenname = "---";
- }
- string pad = tokenname.Length > 7 ? "\t" : "\t\t";
- System.Console.Error.WriteLine(tokenname + pad + (int)source[i] + "\t'" + ScriptRuntime.escapeString(source.Substring(i, (i + 1) - (i))) + "'");
- }
- System.Console.Error.WriteLine();
- }
-
- int braceNesting = 0;
- bool afterFirstEOL = false;
- int i2 = 0;
- int topFunctionType;
- if (source[i2] == Token.SCRIPT)
- {
- ++i2;
- topFunctionType = -1;
- }
- else
- {
- topFunctionType = source[i2 + 1];
- }
-
- if (!toSource)
- {
- if (!toString)
- {
- // add an initial newline to exactly match js.
- result.Append('\n');
- }
- for (int j = 0; j < indent; j++)
- result.Append(' ');
- }
- else
- {
- if (topFunctionType == FunctionNode.FUNCTION_EXPRESSION)
- {
- result.Append('(');
- }
- }
-
- while (i2 < length)
- {
- switch (source[i2])
- {
-
- case (char)(Token.NAME):
- case (char)(Token.REGEXP): // re-wrapped in '/'s in parser...
- i2 = PrintSourceString(source, i2 + 1, false, result);
- continue;
-
-
- case (char)(Token.STRING):
- i2 = PrintSourceString(source, i2 + 1, true, result);
- continue;
-
-
- case (char)(Token.NUMBER):
- i2 = PrintSourceNumber(source, i2 + 1, result);
- continue;
-
-
- case (char)(Token.TRUE):
- result.Append("true");
- break;
-
-
- case (char)(Token.FALSE):
- result.Append("false");
- break;
-
-
- case (char)(Token.NULL):
- result.Append("null");
- break;
-
-
- case (char)(Token.THIS):
- result.Append("this");
- break;
-
-
- case (char)(Token.FUNCTION):
- ++i2; // skip function type
- result.Append("function ");
- break;
-
-
- case (char)(FUNCTION_END):
- // Do nothing
- break;
-
-
- case (char)(Token.COMMA):
- result.Append(", ");
- break;
-
-
- case (char)(Token.LC):
- ++braceNesting;
- if (Token.EOL == GetNext(source, length, i2))
- indent += indentGap;
- result.Append('{');
- break;
-
-
- case (char)(Token.RC):
- {
- --braceNesting;
- /* don't print the closing RC if it closes the
- * toplevel function and we're called from
- * decompileFunctionBody.
- */
- if (justFunctionBody && braceNesting == 0)
- break;
-
- result.Append('}');
- switch (GetNext(source, length, i2))
- {
-
- case Token.EOL:
- case FUNCTION_END:
- indent -= indentGap;
- break;
-
- case Token.WHILE:
- case Token.ELSE:
- indent -= indentGap;
- result.Append(' ');
- break;
- }
- break;
- }
-
- case (char)(Token.LP):
- result.Append('(');
- break;
-
-
- case (char)(Token.RP):
- result.Append(')');
- if (Token.LC == GetNext(source, length, i2))
- result.Append(' ');
- break;
-
-
- case (char)(Token.LB):
- result.Append('[');
- break;
-
-
- case (char)(Token.RB):
- result.Append(']');
- break;
-
-
- case (char)(Token.EOL):
- {
- if (toSource)
- break;
- bool newLine = true;
- if (!afterFirstEOL)
- {
- afterFirstEOL = true;
- if (justFunctionBody)
- {
- /* throw away just added 'function name(...) {'
- * and restore the original indent
- */
- result.Length = 0;
- indent -= indentGap;
- newLine = false;
- }
- }
- if (newLine)
- {
- result.Append('\n');
- }
-
- /* add indent if any tokens remain,
- * less setback if next token is
- * a label, case or default.
- */
- if (i2 + 1 < length)
- {
- int less = 0;
- int nextToken = source[i2 + 1];
- if (nextToken == Token.CASE || nextToken == Token.DEFAULT)
- {
- less = indentGap - caseGap;
- }
- else if (nextToken == Token.RC)
- {
- less = indentGap;
- }
- /* elaborate check against label... skip past a
- * following inlined NAME and look for a COLON.
- */
- else if (nextToken == Token.NAME)
- {
- int afterName = GetSourceStringEnd(source, i2 + 2);
- if (source[afterName] == Token.COLON)
- less = indentGap;
- }
-
- for (; less < indent; less++)
- result.Append(' ');
- }
- break;
- }
-
- case (char)(Token.DOT):
- result.Append('.');
- break;
-
-
- case (char)(Token.NEW):
- result.Append("new ");
- break;
-
-
- case (char)(Token.DELPROP):
- result.Append("delete ");
- break;
-
-
- case (char)(Token.IF):
- result.Append("if ");
- break;
-
-
- case (char)(Token.ELSE):
- result.Append("else ");
- break;
-
-
- case (char)(Token.FOR):
- result.Append("for ");
- break;
-
-
- case (char)(Token.IN):
- result.Append(" in ");
- break;
-
-
- case (char)(Token.WITH):
- result.Append("with ");
- break;
-
-
- case (char)(Token.WHILE):
- result.Append("while ");
- break;
-
-
- case (char)(Token.DO):
- result.Append("do ");
- break;
-
-
- case (char)(Token.TRY):
- result.Append("try ");
- break;
-
-
- case (char)(Token.CATCH):
- result.Append("catch ");
- break;
-
-
- case (char)(Token.FINALLY):
- result.Append("finally ");
- break;
-
-
- case (char)(Token.THROW):
- result.Append("throw ");
- break;
-
-
- case (char)(Token.SWITCH):
- result.Append("switch ");
- break;
-
-
- case (char)(Token.BREAK):
- result.Append("break");
- if (Token.NAME == GetNext(source, length, i2))
- result.Append(' ');
- break;
-
-
- case (char)(Token.CONTINUE):
- result.Append("continue");
- if (Token.NAME == GetNext(source, length, i2))
- result.Append(' ');
- break;
-
-
- case (char)(Token.CASE):
- result.Append("case ");
- break;
-
-
- case (char)(Token.DEFAULT):
- result.Append("default");
- break;
-
-
- case (char)(Token.RETURN):
- result.Append("return");
- if (Token.SEMI != GetNext(source, length, i2))
- result.Append(' ');
- break;
-
-
- case (char)(Token.VAR):
- result.Append("var ");
- break;
-
-
- case (char)(Token.SEMI):
- result.Append(';');
- if (Token.EOL != GetNext(source, length, i2))
- {
- // separators in FOR
- result.Append(' ');
- }
- break;
-
-
- case (char)(Token.ASSIGN):
- result.Append(" = ");
- break;
-
-
- case (char)(Token.ASSIGN_ADD):
- result.Append(" += ");
- break;
-
-
- case (char)(Token.ASSIGN_SUB):
- result.Append(" -= ");
- break;
-
-
- case (char)(Token.ASSIGN_MUL):
- result.Append(" *= ");
- break;
-
-
- case (char)(Token.ASSIGN_DIV):
- result.Append(" /= ");
- break;
-
-
- case (char)(Token.ASSIGN_MOD):
- result.Append(" %= ");
- break;
-
-
- case (char)(Token.ASSIGN_BITOR):
- result.Append(" |= ");
- break;
-
-
- case (char)(Token.ASSIGN_BITXOR):
- result.Append(" ^= ");
- break;
-
-
- case (char)(Token.ASSIGN_BITAND):
- result.Append(" &= ");
- break;
-
-
- case (char)(Token.ASSIGN_LSH):
- result.Append(" <<= ");
- break;
-
-
- case (char)(Token.ASSIGN_RSH):
- result.Append(" >>= ");
- break;
-
-
- case (char)(Token.ASSIGN_URSH):
- result.Append(" >>>= ");
- break;
-
-
- case (char)(Token.HOOK):
- result.Append(" ? ");
- break;
-
-
- case (char)(Token.OBJECTLIT):
- // pun OBJECTLIT to mean colon in objlit property
- // initialization.
- // This needs to be distinct from COLON in the general case
- // to distinguish from the colon in a ternary... which needs
- // different spacing.
- result.Append(':');
- break;
-
-
- case (char)(Token.COLON):
- if (Token.EOL == GetNext(source, length, i2))
- // it's the end of a label
- result.Append(':');
- // it's the middle part of a ternary
- else
- result.Append(" : ");
- break;
-
-
- case (char)(Token.OR):
- result.Append(" || ");
- break;
-
-
- case (char)(Token.AND):
- result.Append(" && ");
- break;
-
-
- case (char)(Token.BITOR):
- result.Append(" | ");
- break;
-
-
- case (char)(Token.BITXOR):
- result.Append(" ^ ");
- break;
-
-
- case (char)(Token.BITAND):
- result.Append(" & ");
- break;
-
-
- case (char)(Token.SHEQ):
- result.Append(" === ");
- break;
-
-
- case (char)(Token.SHNE):
- result.Append(" !== ");
- break;
-
-
- case (char)(Token.EQ):
- result.Append(" == ");
- break;
-
-
- case (char)(Token.NE):
- result.Append(" != ");
- break;
-
-
- case (char)(Token.LE):
- result.Append(" <= ");
- break;
-
-
- case (char)(Token.LT):
- result.Append(" < ");
- break;
-
-
- case (char)(Token.GE):
- result.Append(" >= ");
- break;
-
-
- case (char)(Token.GT):
- result.Append(" > ");
- break;
-
-
- case (char)(Token.INSTANCEOF):
- result.Append(" instanceof ");
- break;
-
-
- case (char)(Token.LSH):
- result.Append(" << ");
- break;
-
-
- case (char)(Token.RSH):
- result.Append(" >> ");
- break;
-
-
- case (char)(Token.URSH):
- result.Append(" >>> ");
- break;
-
-
- case (char)(Token.TYPEOF):
- result.Append("typeof ");
- break;
-
-
- case (char)(Token.VOID):
- result.Append("void ");
- break;
-
-
- case (char)(Token.NOT):
- result.Append('!');
- break;
-
-
- case (char)(Token.BITNOT):
- result.Append('~');
- break;
-
-
- case (char)(Token.POS):
- result.Append('+');
- break;
-
-
- case (char)(Token.NEG):
- result.Append('-');
- break;
-
-
- case (char)(Token.INC):
- result.Append("++");
- break;
-
-
- case (char)(Token.DEC):
- result.Append("--");
- break;
-
-
- case (char)(Token.ADD):
- result.Append(" + ");
- break;
-
-
- case (char)(Token.SUB):
- result.Append(" - ");
- break;
-
-
- case (char)(Token.MUL):
- result.Append(" * ");
- break;
-
-
- case (char)(Token.DIV):
- result.Append(" / ");
- break;
-
-
- case (char)(Token.MOD):
- result.Append(" % ");
- break;
-
-
- case (char)(Token.COLONCOLON):
- result.Append("::");
- break;
-
-
- case (char)(Token.DOTDOT):
- result.Append("..");
- break;
-
-
- case (char)(Token.DOTQUERY):
- result.Append(".(");
- break;
-
-
- case (char)(Token.XMLATTR):
- result.Append('@');
- break;
-
-
- default:
- // If we don't know how to decompile it, raise an exception.
- throw new ApplicationException();
-
- }
- ++i2;
- }
-
- if (!toSource)
- {
- // add that trailing newline if it's an outermost function.
- if (!justFunctionBody && !toString)
- result.Append('\n');
- }
- else
- {
- if (topFunctionType == FunctionNode.FUNCTION_EXPRESSION)
- {
- result.Append(')');
- }
- }
-
- return result.ToString();
- }
-
- private static int GetNext(string source, int length, int i)
- {
- return (i + 1 < length) ? source[i + 1] : Token.EOF;
- }
-
- private static int GetSourceStringEnd(string source, int offset)
- {
- return PrintSourceString(source, offset, false, null);
- }
-
- private static int PrintSourceString(string source, int offset, bool asQuotedString, System.Text.StringBuilder sb)
- {
- int length = source[offset];
- ++offset;
- if ((0x8000 & length) != 0)
- {
- length = ((0x7FFF & length) << 16) | source[offset];
- ++offset;
- }
- if (sb != null)
- {
- string str = source.Substring(offset, (offset + length) - (offset));
- if (!asQuotedString)
- {
- sb.Append(str);
- }
- else
- {
- sb.Append('"');
- sb.Append(ScriptRuntime.escapeString(str));
- sb.Append('"');
- }
- }
- return offset + length;
- }
-
- private static int PrintSourceNumber(string source, int offset, System.Text.StringBuilder sb)
- {
- double number = 0.0;
- char type = source[offset];
- ++offset;
- if (type == 'S')
- {
- if (sb != null)
- {
- int ival = source[offset];
- number = ival;
- }
- ++offset;
- }
- else if (type == 'J' || type == 'D')
- {
- if (sb != null)
- {
- long lbits;
- lbits = (long)source[offset] << 48;
- lbits |= (long)source[offset + 1] << 32;
- lbits |= (long)source[offset + 2] << 16;
- lbits |= (long)source[offset + 3];
- if (type == 'J')
- {
- number = lbits;
- }
- else
- {
- number = BitConverter.Int64BitsToDouble(lbits);
- }
- }
- offset += 4;
- }
- else
- {
- // Bad source
- throw new ApplicationException();
- }
- if (sb != null)
- {
- sb.Append(ScriptConvert.ToString(number, 10));
- }
- return offset;
- }
-
- private char[] sourceBuffer = new char[128];
-
- // Per script/function source buffer top: parent source does not include a
- // nested functions source and uses function index as a reference instead.
- private int sourceTop;
-
- // whether to do a debug print of the source information, when decompiling.
- private static bool printSource = false; // TODO: make preprocessor directive
-
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+using EcmaScript.NET.Collections;
+
+namespace EcmaScript.NET
+{
+
+ /// The following class save decompilation information about the source.
+ /// Source information is returned from the parser as a String
+ /// associated with function nodes and with the toplevel script. When
+ /// saved in the constant pool of a class, this string will be UTF-8
+ /// encoded, and token values will occupy a single byte.
+ /// Source is saved (mostly) as token numbers. The tokens saved pretty
+ /// much correspond to the token stream of a 'canonical' representation
+ /// of the input program, as directed by the parser. (There were a few
+ /// cases where tokens could have been left out where decompiler could
+ /// easily reconstruct them, but I left them in for clarity). (I also
+ /// looked adding source collection to TokenStream instead, where I
+ /// could have limited the changes to a few lines in getToken... but
+ /// this wouldn't have saved any space in the resulting source
+ /// representation, and would have meant that I'd have to duplicate
+ /// parser logic in the decompiler to disambiguate situations where
+ /// newlines are important.) The function decompile expands the
+ /// tokens back into their string representations, using simple
+ /// lookahead to correct spacing and indentation.
+ ///
+ /// Assignments are saved as two-token pairs (Token.ASSIGN, op). Number tokens
+ /// are stored inline, as a NUMBER token, a character representing the type, and
+ /// either 1 or 4 characters representing the bit-encoding of the number. String
+ /// types NAME, STRING and OBJECT are currently stored as a token type,
+ /// followed by a character giving the length of the string (assumed to
+ /// be less than 2^16), followed by the characters of the string
+ /// inlined into the source string. Changing this to some reference to
+ /// to the string in the compiled class' constant pool would probably
+ /// save a lot of space... but would require some method of deriving
+ /// the final constant pool entry from information available at parse
+ /// time.
+ ///
+ public class Decompiler
+ {
+ internal string EncodedSource
+ {
+ get
+ {
+ return SourceToString(0);
+ }
+
+ }
+ internal int CurrentOffset
+ {
+ get
+ {
+ return sourceTop;
+ }
+
+ }
+ /// Flag to indicate that the decompilation should omit the
+ /// function header and trailing brace.
+ ///
+ public const int ONLY_BODY_FLAG = 1 << 0;
+
+ /// Flag to indicate that the decompilation generates toSource result.
+ public const int TO_SOURCE_FLAG = 1 << 1;
+
+ public const int TO_STRING_FLAG = 1 << 2;
+
+ /// Decompilation property to specify initial ident value.
+ public const int INITIAL_INDENT_PROP = 1;
+
+ /// Decompilation property to specify default identation offset.
+ public const int INDENT_GAP_PROP = 2;
+
+ /// Decompilation property to specify identation offset for case labels.
+ public const int CASE_GAP_PROP = 3;
+
+ // Marker to denote the last RC of function so it can be distinguished from
+ // the last RC of object literals in case of function expressions
+ private const int FUNCTION_END = 147;
+
+ internal int MarkFunctionStart(int functionType)
+ {
+ int savedOffset = CurrentOffset;
+ AddToken(Token.FUNCTION);
+ Append((char)functionType);
+ return savedOffset;
+ }
+
+ internal int MarkFunctionEnd(int functionStart)
+ {
+ int offset = CurrentOffset;
+ Append((char)FUNCTION_END);
+ return offset;
+ }
+
+ internal void AddToken(int token)
+ {
+ if (!(0 <= token && token <= Token.LAST_TOKEN))
+ throw new ArgumentException();
+
+ Append((char)token);
+ }
+
+ internal void AddEol(int token)
+ {
+ if (!(0 <= token && token <= Token.LAST_TOKEN))
+ throw new ArgumentException();
+
+ Append((char)token);
+ Append((char)Token.EOL);
+ }
+
+ internal void AddName(string str)
+ {
+ AddToken(Token.NAME);
+ AppendString(str);
+ }
+
+ internal void AddString(string str)
+ {
+ AddToken(Token.STRING);
+ AppendString(str);
+ }
+
+ internal void AddRegexp(string regexp, string flags)
+ {
+ AddToken(Token.REGEXP);
+ AppendString('/' + regexp + '/' + flags);
+ }
+
+ internal void AddJScriptConditionalComment(String str)
+ {
+ AddToken(Token.CONDCOMMENT);
+ AppendString(str);
+ }
+
+ internal void AddPreservedComment(String str)
+ {
+ AddToken(Token.KEEPCOMMENT);
+ AppendString(str);
+ }
+
+ internal void AddNumber(double n)
+ {
+ AddToken(Token.NUMBER);
+
+ /* encode the number in the source stream.
+ * Save as NUMBER type (char | char char char char)
+ * where type is
+ * 'D' - double, 'S' - short, 'J' - long.
+
+ * We need to retain float vs. integer type info to keep the
+ * behavior of liveconnect type-guessing the same after
+ * decompilation. (Liveconnect tries to present 1.0 to Java
+ * as a float/double)
+ * OPT: This is no longer true. We could compress the format.
+
+ * This may not be the most space-efficient encoding;
+ * the chars created below may take up to 3 bytes in
+ * constant pool UTF-8 encoding, so a Double could take
+ * up to 12 bytes.
+ */
+
+ long lbits = (long)n;
+ if (lbits != n)
+ {
+ // if it's floating point, save as a Double bit pattern.
+ // (12/15/97 our scanner only returns Double for f.p.)
+ lbits = BitConverter.DoubleToInt64Bits(n);
+ Append('D');
+ Append((char)(lbits >> 48));
+ Append((char)(lbits >> 32));
+ Append((char)(lbits >> 16));
+ Append((char)lbits);
+ }
+ else
+ {
+ // we can ignore negative values, bc they're already prefixed
+ // by NEG
+ if (lbits < 0)
+ Context.CodeBug();
+
+ // will it fit in a char?
+ // this gives a short encoding for integer values up to 2^16.
+ if (lbits <= char.MaxValue)
+ {
+ Append('S');
+ Append((char)lbits);
+ }
+ else
+ {
+ // Integral, but won't fit in a char. Store as a long.
+ Append('J');
+ Append((char)(lbits >> 48));
+ Append((char)(lbits >> 32));
+ Append((char)(lbits >> 16));
+ Append((char)lbits);
+ }
+ }
+ }
+
+ private void AppendString(string str)
+ {
+ int L = str.Length;
+ int lengthEncodingSize = 1;
+ if (L >= 0x8000)
+ {
+ lengthEncodingSize = 2;
+ }
+ int nextTop = sourceTop + lengthEncodingSize + L;
+ if (nextTop > sourceBuffer.Length)
+ {
+ IncreaseSourceCapacity(nextTop);
+ }
+ if (L >= 0x8000)
+ {
+ // Use 2 chars to encode strings exceeding 32K, were the highest
+ // bit in the first char indicates presence of the next byte
+ sourceBuffer[sourceTop] = (char)(0x8000 | (int)((uint)L >> 16));
+ ++sourceTop;
+ }
+ sourceBuffer[sourceTop] = (char)L;
+ ++sourceTop;
+ str.ToCharArray(0, L).CopyTo(sourceBuffer, sourceTop);
+ sourceTop = nextTop;
+ }
+
+ private void Append(char c)
+ {
+ if (sourceTop == sourceBuffer.Length)
+ {
+ IncreaseSourceCapacity(sourceTop + 1);
+ }
+ sourceBuffer[sourceTop] = c;
+ ++sourceTop;
+ }
+
+ private void IncreaseSourceCapacity(int minimalCapacity)
+ {
+ // Call this only when capacity increase is must
+ if (minimalCapacity <= sourceBuffer.Length)
+ Context.CodeBug();
+ int newCapacity = sourceBuffer.Length * 2;
+ if (newCapacity < minimalCapacity)
+ {
+ newCapacity = minimalCapacity;
+ }
+ char[] tmp = new char[newCapacity];
+ Array.Copy(sourceBuffer, 0, tmp, 0, sourceTop);
+ sourceBuffer = tmp;
+ }
+
+ private string SourceToString(int offset)
+ {
+ if (offset < 0 || sourceTop < offset)
+ Context.CodeBug();
+ return new string(sourceBuffer, offset, sourceTop - offset);
+ }
+
+ /// Decompile the source information associated with this js
+ /// function/script back into a string. For the most part, this
+ /// just means translating tokens back to their string
+ /// representations; there's a little bit of lookahead logic to
+ /// decide the proper spacing/indentation. Most of the work in
+ /// mapping the original source to the prettyprinted decompiled
+ /// version is done by the parser.
+ ///
+ ///
+ /// encoded source tree presentation
+ ///
+ ///
+ /// flags to select output format
+ ///
+ ///
+ /// indentation properties
+ ///
+ ///
+ public static string Decompile(string source, int flags, UintMap properties)
+ {
+ int length = source.Length;
+ if (length == 0)
+ {
+ return "";
+ }
+
+ int indent = properties.getInt(INITIAL_INDENT_PROP, 0);
+ if (indent < 0)
+ throw new ArgumentException();
+ int indentGap = properties.getInt(INDENT_GAP_PROP, 4);
+ if (indentGap < 0)
+ throw new ArgumentException();
+ int caseGap = properties.getInt(CASE_GAP_PROP, 2);
+ if (caseGap < 0)
+ throw new ArgumentException();
+
+ System.Text.StringBuilder result = new System.Text.StringBuilder();
+ bool justFunctionBody = (0 != (flags & Decompiler.ONLY_BODY_FLAG));
+ bool toSource = (0 != (flags & Decompiler.TO_SOURCE_FLAG));
+ bool toString = (0 != (flags & Decompiler.TO_STRING_FLAG));
+
+ // Spew tokens in source, for debugging.
+ // as TYPE number char
+ if (printSource)
+ {
+ System.Console.Error.WriteLine("length:" + length);
+ for (int i = 0; i < length; ++i)
+ {
+ // Note that tokenToName will fail unless Context.printTrees
+ // is true.
+ string tokenname = null;
+ if (Token.printNames)
+ {
+ tokenname = Token.name(source[i]);
+ }
+ if (tokenname == null)
+ {
+ tokenname = "---";
+ }
+ string pad = tokenname.Length > 7 ? "\t" : "\t\t";
+ System.Console.Error.WriteLine(tokenname + pad + (int)source[i] + "\t'" + ScriptRuntime.escapeString(source.Substring(i, (i + 1) - (i))) + "'");
+ }
+ System.Console.Error.WriteLine();
+ }
+
+ int braceNesting = 0;
+ bool afterFirstEOL = false;
+ int i2 = 0;
+ int topFunctionType;
+ if (source[i2] == Token.SCRIPT)
+ {
+ ++i2;
+ topFunctionType = -1;
+ }
+ else
+ {
+ topFunctionType = source[i2 + 1];
+ }
+
+ if (!toSource)
+ {
+ if (!toString)
+ {
+ // add an initial newline to exactly match js.
+ result.Append('\n');
+ }
+ for (int j = 0; j < indent; j++)
+ result.Append(' ');
+ }
+ else
+ {
+ if (topFunctionType == FunctionNode.FUNCTION_EXPRESSION)
+ {
+ result.Append('(');
+ }
+ }
+
+ while (i2 < length)
+ {
+ switch (source[i2])
+ {
+
+ case (char)(Token.NAME):
+ case (char)(Token.REGEXP): // re-wrapped in '/'s in parser...
+ i2 = PrintSourceString(source, i2 + 1, false, result);
+ continue;
+
+
+ case (char)(Token.STRING):
+ i2 = PrintSourceString(source, i2 + 1, true, result);
+ continue;
+
+
+ case (char)(Token.NUMBER):
+ i2 = PrintSourceNumber(source, i2 + 1, result);
+ continue;
+
+
+ case (char)(Token.TRUE):
+ result.Append("true");
+ break;
+
+
+ case (char)(Token.FALSE):
+ result.Append("false");
+ break;
+
+
+ case (char)(Token.NULL):
+ result.Append("null");
+ break;
+
+
+ case (char)(Token.THIS):
+ result.Append("this");
+ break;
+
+
+ case (char)(Token.FUNCTION):
+ ++i2; // skip function type
+ result.Append("function ");
+ break;
+
+
+ case (char)(FUNCTION_END):
+ // Do nothing
+ break;
+
+
+ case (char)(Token.COMMA):
+ result.Append(", ");
+ break;
+
+
+ case (char)(Token.LC):
+ ++braceNesting;
+ if (Token.EOL == GetNext(source, length, i2))
+ indent += indentGap;
+ result.Append('{');
+ break;
+
+
+ case (char)(Token.RC):
+ {
+ --braceNesting;
+ /* don't print the closing RC if it closes the
+ * toplevel function and we're called from
+ * decompileFunctionBody.
+ */
+ if (justFunctionBody && braceNesting == 0)
+ break;
+
+ result.Append('}');
+ switch (GetNext(source, length, i2))
+ {
+
+ case Token.EOL:
+ case FUNCTION_END:
+ indent -= indentGap;
+ break;
+
+ case Token.WHILE:
+ case Token.ELSE:
+ indent -= indentGap;
+ result.Append(' ');
+ break;
+ }
+ break;
+ }
+
+ case (char)(Token.LP):
+ result.Append('(');
+ break;
+
+
+ case (char)(Token.RP):
+ result.Append(')');
+ if (Token.LC == GetNext(source, length, i2))
+ result.Append(' ');
+ break;
+
+
+ case (char)(Token.LB):
+ result.Append('[');
+ break;
+
+
+ case (char)(Token.RB):
+ result.Append(']');
+ break;
+
+
+ case (char)(Token.EOL):
+ {
+ if (toSource)
+ break;
+ bool newLine = true;
+ if (!afterFirstEOL)
+ {
+ afterFirstEOL = true;
+ if (justFunctionBody)
+ {
+ /* throw away just added 'function name(...) {'
+ * and restore the original indent
+ */
+ result.Length = 0;
+ indent -= indentGap;
+ newLine = false;
+ }
+ }
+ if (newLine)
+ {
+ result.Append('\n');
+ }
+
+ /* add indent if any tokens remain,
+ * less setback if next token is
+ * a label, case or default.
+ */
+ if (i2 + 1 < length)
+ {
+ int less = 0;
+ int nextToken = source[i2 + 1];
+ if (nextToken == Token.CASE || nextToken == Token.DEFAULT)
+ {
+ less = indentGap - caseGap;
+ }
+ else if (nextToken == Token.RC)
+ {
+ less = indentGap;
+ }
+ /* elaborate check against label... skip past a
+ * following inlined NAME and look for a COLON.
+ */
+ else if (nextToken == Token.NAME)
+ {
+ int afterName = GetSourceStringEnd(source, i2 + 2);
+ if (source[afterName] == Token.COLON)
+ less = indentGap;
+ }
+
+ for (; less < indent; less++)
+ result.Append(' ');
+ }
+ break;
+ }
+
+ case (char)(Token.DOT):
+ result.Append('.');
+ break;
+
+
+ case (char)(Token.NEW):
+ result.Append("new ");
+ break;
+
+
+ case (char)(Token.DELPROP):
+ result.Append("delete ");
+ break;
+
+
+ case (char)(Token.IF):
+ result.Append("if ");
+ break;
+
+
+ case (char)(Token.ELSE):
+ result.Append("else ");
+ break;
+
+
+ case (char)(Token.FOR):
+ result.Append("for ");
+ break;
+
+
+ case (char)(Token.IN):
+ result.Append(" in ");
+ break;
+
+
+ case (char)(Token.WITH):
+ result.Append("with ");
+ break;
+
+
+ case (char)(Token.WHILE):
+ result.Append("while ");
+ break;
+
+
+ case (char)(Token.DO):
+ result.Append("do ");
+ break;
+
+
+ case (char)(Token.TRY):
+ result.Append("try ");
+ break;
+
+
+ case (char)(Token.CATCH):
+ result.Append("catch ");
+ break;
+
+
+ case (char)(Token.FINALLY):
+ result.Append("finally ");
+ break;
+
+
+ case (char)(Token.THROW):
+ result.Append("throw ");
+ break;
+
+
+ case (char)(Token.SWITCH):
+ result.Append("switch ");
+ break;
+
+
+ case (char)(Token.BREAK):
+ result.Append("break");
+ if (Token.NAME == GetNext(source, length, i2))
+ result.Append(' ');
+ break;
+
+
+ case (char)(Token.CONTINUE):
+ result.Append("continue");
+ if (Token.NAME == GetNext(source, length, i2))
+ result.Append(' ');
+ break;
+
+
+ case (char)(Token.CASE):
+ result.Append("case ");
+ break;
+
+
+ case (char)(Token.DEFAULT):
+ result.Append("default");
+ break;
+
+
+ case (char)(Token.RETURN):
+ result.Append("return");
+ if (Token.SEMI != GetNext(source, length, i2))
+ result.Append(' ');
+ break;
+
+
+ case (char)(Token.VAR):
+ result.Append("var ");
+ break;
+
+
+ case (char)(Token.SEMI):
+ result.Append(';');
+ if (Token.EOL != GetNext(source, length, i2))
+ {
+ // separators in FOR
+ result.Append(' ');
+ }
+ break;
+
+
+ case (char)(Token.ASSIGN):
+ result.Append(" = ");
+ break;
+
+
+ case (char)(Token.ASSIGN_ADD):
+ result.Append(" += ");
+ break;
+
+
+ case (char)(Token.ASSIGN_SUB):
+ result.Append(" -= ");
+ break;
+
+
+ case (char)(Token.ASSIGN_MUL):
+ result.Append(" *= ");
+ break;
+
+
+ case (char)(Token.ASSIGN_DIV):
+ result.Append(" /= ");
+ break;
+
+
+ case (char)(Token.ASSIGN_MOD):
+ result.Append(" %= ");
+ break;
+
+
+ case (char)(Token.ASSIGN_BITOR):
+ result.Append(" |= ");
+ break;
+
+
+ case (char)(Token.ASSIGN_BITXOR):
+ result.Append(" ^= ");
+ break;
+
+
+ case (char)(Token.ASSIGN_BITAND):
+ result.Append(" &= ");
+ break;
+
+
+ case (char)(Token.ASSIGN_LSH):
+ result.Append(" <<= ");
+ break;
+
+
+ case (char)(Token.ASSIGN_RSH):
+ result.Append(" >>= ");
+ break;
+
+
+ case (char)(Token.ASSIGN_URSH):
+ result.Append(" >>>= ");
+ break;
+
+
+ case (char)(Token.HOOK):
+ result.Append(" ? ");
+ break;
+
+
+ case (char)(Token.OBJECTLIT):
+ // pun OBJECTLIT to mean colon in objlit property
+ // initialization.
+ // This needs to be distinct from COLON in the general case
+ // to distinguish from the colon in a ternary... which needs
+ // different spacing.
+ result.Append(':');
+ break;
+
+
+ case (char)(Token.COLON):
+ if (Token.EOL == GetNext(source, length, i2))
+ // it's the end of a label
+ result.Append(':');
+ // it's the middle part of a ternary
+ else
+ result.Append(" : ");
+ break;
+
+
+ case (char)(Token.OR):
+ result.Append(" || ");
+ break;
+
+
+ case (char)(Token.AND):
+ result.Append(" && ");
+ break;
+
+
+ case (char)(Token.BITOR):
+ result.Append(" | ");
+ break;
+
+
+ case (char)(Token.BITXOR):
+ result.Append(" ^ ");
+ break;
+
+
+ case (char)(Token.BITAND):
+ result.Append(" & ");
+ break;
+
+
+ case (char)(Token.SHEQ):
+ result.Append(" === ");
+ break;
+
+
+ case (char)(Token.SHNE):
+ result.Append(" !== ");
+ break;
+
+
+ case (char)(Token.EQ):
+ result.Append(" == ");
+ break;
+
+
+ case (char)(Token.NE):
+ result.Append(" != ");
+ break;
+
+
+ case (char)(Token.LE):
+ result.Append(" <= ");
+ break;
+
+
+ case (char)(Token.LT):
+ result.Append(" < ");
+ break;
+
+
+ case (char)(Token.GE):
+ result.Append(" >= ");
+ break;
+
+
+ case (char)(Token.GT):
+ result.Append(" > ");
+ break;
+
+
+ case (char)(Token.INSTANCEOF):
+ result.Append(" instanceof ");
+ break;
+
+
+ case (char)(Token.LSH):
+ result.Append(" << ");
+ break;
+
+
+ case (char)(Token.RSH):
+ result.Append(" >> ");
+ break;
+
+
+ case (char)(Token.URSH):
+ result.Append(" >>> ");
+ break;
+
+
+ case (char)(Token.TYPEOF):
+ result.Append("typeof ");
+ break;
+
+
+ case (char)(Token.VOID):
+ result.Append("void ");
+ break;
+
+
+ case (char)(Token.NOT):
+ result.Append('!');
+ break;
+
+
+ case (char)(Token.BITNOT):
+ result.Append('~');
+ break;
+
+
+ case (char)(Token.POS):
+ result.Append('+');
+ break;
+
+
+ case (char)(Token.NEG):
+ result.Append('-');
+ break;
+
+
+ case (char)(Token.INC):
+ result.Append("++");
+ break;
+
+
+ case (char)(Token.DEC):
+ result.Append("--");
+ break;
+
+
+ case (char)(Token.ADD):
+ result.Append(" + ");
+ break;
+
+
+ case (char)(Token.SUB):
+ result.Append(" - ");
+ break;
+
+
+ case (char)(Token.MUL):
+ result.Append(" * ");
+ break;
+
+
+ case (char)(Token.DIV):
+ result.Append(" / ");
+ break;
+
+
+ case (char)(Token.MOD):
+ result.Append(" % ");
+ break;
+
+
+ case (char)(Token.COLONCOLON):
+ result.Append("::");
+ break;
+
+
+ case (char)(Token.DOTDOT):
+ result.Append("..");
+ break;
+
+
+ case (char)(Token.DOTQUERY):
+ result.Append(".(");
+ break;
+
+
+ case (char)(Token.XMLATTR):
+ result.Append('@');
+ break;
+
+
+ default:
+ // If we don't know how to decompile it, raise an exception.
+ throw new Exception();
+
+ }
+ ++i2;
+ }
+
+ if (!toSource)
+ {
+ // add that trailing newline if it's an outermost function.
+ if (!justFunctionBody && !toString)
+ result.Append('\n');
+ }
+ else
+ {
+ if (topFunctionType == FunctionNode.FUNCTION_EXPRESSION)
+ {
+ result.Append(')');
+ }
+ }
+
+ return result.ToString();
+ }
+
+ private static int GetNext(string source, int length, int i)
+ {
+ return (i + 1 < length) ? source[i + 1] : Token.EOF;
+ }
+
+ private static int GetSourceStringEnd(string source, int offset)
+ {
+ return PrintSourceString(source, offset, false, null);
+ }
+
+ private static int PrintSourceString(string source, int offset, bool asQuotedString, System.Text.StringBuilder sb)
+ {
+ int length = source[offset];
+ ++offset;
+ if ((0x8000 & length) != 0)
+ {
+ length = ((0x7FFF & length) << 16) | source[offset];
+ ++offset;
+ }
+ if (sb != null)
+ {
+ string str = source.Substring(offset, (offset + length) - (offset));
+ if (!asQuotedString)
+ {
+ sb.Append(str);
+ }
+ else
+ {
+ sb.Append('"');
+ sb.Append(ScriptRuntime.escapeString(str));
+ sb.Append('"');
+ }
+ }
+ return offset + length;
+ }
+
+ private static int PrintSourceNumber(string source, int offset, System.Text.StringBuilder sb)
+ {
+ double number = 0.0;
+ char type = source[offset];
+ ++offset;
+ if (type == 'S')
+ {
+ if (sb != null)
+ {
+ int ival = source[offset];
+ number = ival;
+ }
+ ++offset;
+ }
+ else if (type == 'J' || type == 'D')
+ {
+ if (sb != null)
+ {
+ long lbits;
+ lbits = (long)source[offset] << 48;
+ lbits |= (long)source[offset + 1] << 32;
+ lbits |= (long)source[offset + 2] << 16;
+ lbits |= (long)source[offset + 3];
+ if (type == 'J')
+ {
+ number = lbits;
+ }
+ else
+ {
+ number = BitConverter.Int64BitsToDouble(lbits);
+ }
+ }
+ offset += 4;
+ }
+ else
+ {
+ // Bad source
+ throw new Exception();
+ }
+ if (sb != null)
+ {
+ sb.Append(ScriptConvert.ToString(number, 10));
+ }
+ return offset;
+ }
+
+ private char[] sourceBuffer = new char[128];
+
+ // Per script/function source buffer top: parent source does not include a
+ // nested functions source and uses function index as a reference instead.
+ private int sourceTop;
+
+ // whether to do a debug print of the source information, when decompiling.
+ private static bool printSource = false; // TODO: make preprocessor directive
+
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/DefaultErrorReporter.cs b/src/EcmaScript.NET/DefaultErrorReporter.cs
similarity index 97%
rename from Code/EcmaScript.NET/DefaultErrorReporter.cs
rename to src/EcmaScript.NET/DefaultErrorReporter.cs
index 6e5fbc3..db2979a 100644
--- a/Code/EcmaScript.NET/DefaultErrorReporter.cs
+++ b/src/EcmaScript.NET/DefaultErrorReporter.cs
@@ -1,74 +1,74 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-namespace EcmaScript.NET
-{
-
- /// This is the default error reporter for JavaScript.
- ///
- ///
- class DefaultErrorReporter : ErrorReporter
- {
- internal static readonly DefaultErrorReporter instance = new DefaultErrorReporter ();
-
- private bool forEval;
- private ErrorReporter chainedReporter;
-
- private DefaultErrorReporter ()
- {
- }
-
- internal static ErrorReporter ForEval (ErrorReporter reporter)
- {
- DefaultErrorReporter r = new DefaultErrorReporter ();
- r.forEval = true;
- r.chainedReporter = reporter;
- return r;
- }
-
- public virtual void Warning (string message, string sourceURI, int line, string lineText, int lineOffset)
- {
- if (chainedReporter != null) {
- chainedReporter.Warning (message, sourceURI, line, lineText, lineOffset);
- }
- else {
- Console.Error.WriteLine ("strict warning: " + message);
- }
- }
-
- public virtual void Error (string message, string sourceURI, int line, string lineText, int lineOffset)
- {
- if (forEval) {
- throw ScriptRuntime.ConstructError ("SyntaxError", message, sourceURI, line, lineText, lineOffset);
- }
- if (chainedReporter != null) {
- chainedReporter.Error (message, sourceURI, line, lineText, lineOffset);
- }
- else {
- throw RuntimeError (message, sourceURI, line, lineText, lineOffset);
- }
- }
-
- public virtual EcmaScriptRuntimeException RuntimeError (string message, string sourceURI, int line, string lineText, int lineOffset)
- {
- if (chainedReporter != null) {
- return chainedReporter.RuntimeError (message, sourceURI, line, lineText, lineOffset);
- }
- else {
- return new EcmaScriptRuntimeException (message, sourceURI, line, lineText, lineOffset);
- }
- }
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+namespace EcmaScript.NET
+{
+
+ /// This is the default error reporter for JavaScript.
+ ///
+ ///
+ class DefaultErrorReporter : ErrorReporter
+ {
+ internal static readonly DefaultErrorReporter instance = new DefaultErrorReporter ();
+
+ private bool forEval;
+ private ErrorReporter chainedReporter;
+
+ private DefaultErrorReporter ()
+ {
+ }
+
+ internal static ErrorReporter ForEval (ErrorReporter reporter)
+ {
+ DefaultErrorReporter r = new DefaultErrorReporter ();
+ r.forEval = true;
+ r.chainedReporter = reporter;
+ return r;
+ }
+
+ public virtual void Warning (string message, string sourceURI, int line, string lineText, int lineOffset)
+ {
+ if (chainedReporter != null) {
+ chainedReporter.Warning (message, sourceURI, line, lineText, lineOffset);
+ }
+ else {
+ Console.Error.WriteLine ("strict warning: " + message);
+ }
+ }
+
+ public virtual void Error (string message, string sourceURI, int line, string lineText, int lineOffset)
+ {
+ if (forEval) {
+ throw ScriptRuntime.ConstructError ("SyntaxError", message, sourceURI, line, lineText, lineOffset);
+ }
+ if (chainedReporter != null) {
+ chainedReporter.Error (message, sourceURI, line, lineText, lineOffset);
+ }
+ else {
+ throw RuntimeError (message, sourceURI, line, lineText, lineOffset);
+ }
+ }
+
+ public virtual EcmaScriptRuntimeException RuntimeError (string message, string sourceURI, int line, string lineText, int lineOffset)
+ {
+ if (chainedReporter != null) {
+ return chainedReporter.RuntimeError (message, sourceURI, line, lineText, lineOffset);
+ }
+ else {
+ return new EcmaScriptRuntimeException (message, sourceURI, line, lineText, lineOffset);
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/Delegator.cs b/src/EcmaScript.NET/Delegator.cs
similarity index 96%
rename from Code/EcmaScript.NET/Delegator.cs
rename to src/EcmaScript.NET/Delegator.cs
index 3c10496..021fff4 100644
--- a/Code/EcmaScript.NET/Delegator.cs
+++ b/src/EcmaScript.NET/Delegator.cs
@@ -1,243 +1,243 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-using EcmaScript.NET.Types;
-
-namespace EcmaScript.NET
-{
-
- /// This is a helper class for implementing wrappers around Scriptable
- /// objects. It implements the Function interface and delegates all
- /// invocations to a delegee Scriptable object. The normal use of this
- /// class involves creating a sub-class and overriding one or more of
- /// the methods.
- ///
- /// A useful application is the implementation of interceptors,
- /// pre/post conditions, debugging.
- ///
- ///
- public class Delegator : IFunction
- {
-
- /// Retrieve the delegee.
- ///
- ///
- /// the delegee
- ///
- /// Set the delegee.
- ///
- ///
- /// the delegee
- ///
- virtual public IScriptable Delegee
- {
- get
- {
- return obj;
- }
-
- set
- {
- this.obj = value;
- }
-
- }
-
- virtual public string ClassName
- {
- get
- {
- return obj.ClassName;
- }
-
- }
-
-
- virtual public IScriptable ParentScope
- {
- get
- {
- return obj.ParentScope;
- }
-
- set
- {
- obj.ParentScope = value;
- }
-
- }
-
- protected internal IScriptable obj = null;
-
- /// Create a Delegator prototype.
- ///
- /// This constructor should only be used for creating prototype
- /// objects of Delegator.
- ///
- ///
-
- public Delegator ()
- {
- }
-
- /// Create a new Delegator that forwards requests to a delegee
- /// Scriptable object.
- ///
- ///
- /// the delegee
- ///
- public Delegator (IScriptable obj)
- {
- this.obj = obj;
- }
-
- /// Crete new Delegator instance.
- /// The default implementation calls this.getClass().newInstance().
- ///
- ///
- protected internal virtual Delegator NewInstance ()
- {
- try {
- return (Delegator)System.Activator.CreateInstance (this.GetType ());
- }
- catch (Exception ex) {
- throw Context.ThrowAsScriptRuntimeEx (ex);
- }
- }
-
- public virtual object Get (string name, IScriptable start)
- {
- return obj.Get (name, start);
- }
-
- public virtual object Get (int index, IScriptable start)
- {
- return obj.Get (index, start);
- }
-
- public virtual bool Has (string name, IScriptable start)
- {
- return obj.Has (name, start);
- }
-
- public virtual bool Has (int index, IScriptable start)
- {
- return obj.Has (index, start);
- }
-
- public virtual object Put (string name, IScriptable start, object value)
- {
- return obj.Put (name, start, value);
- }
-
- public virtual object Put (int index, IScriptable start, object value)
- {
- return obj.Put (index, start, value);
- }
-
- public virtual void Delete (string name)
- {
- obj.Delete (name);
- }
-
- public virtual void Delete (int index)
- {
- obj.Delete (index);
- }
-
- public virtual IScriptable GetPrototype ()
- {
- return obj.GetPrototype ();
- }
-
- public virtual void SetPrototype (IScriptable prototype)
- {
- obj.SetPrototype (prototype);
- }
-
- public virtual object [] GetIds ()
- {
- return obj.GetIds ();
- }
- /// Note that this method does not get forwarded to the delegee if
- /// the hint parameter is null,
- /// typeof(Scriptable) or
- /// typeof(Function). Instead the object
- /// itself is returned.
- ///
- ///
- /// the type hint
- ///
- /// the default value
- ///
- ///
- public virtual object GetDefaultValue (Type hint)
- {
- return (hint == null
- || hint == typeof (IScriptable)
- || hint == typeof (IFunction))
- ? this : obj.GetDefaultValue (hint);
- }
-
- public virtual bool HasInstance (IScriptable instance)
- {
- return obj.HasInstance (instance);
- }
-
- public virtual object Call (Context cx, IScriptable scope, IScriptable thisObj, object [] args)
- {
- return ((IFunction)obj).Call (cx, scope, thisObj, args);
- }
-
- /// Note that if the delegee is null,
- /// this method creates a new instance of the Delegator itself
- /// rathert than forwarding the call to the
- /// delegee. This permits the use of Delegator
- /// prototypes.
- ///
- ///
- /// the current Context for this thread
- ///
- /// an enclosing scope of the caller except
- /// when the function is called from a closure.
- ///
- /// the array of arguments
- ///
- /// the allocated object
- ///
- ///
-
- public virtual IScriptable Construct (Context cx, IScriptable scope, object [] args)
- {
- if (obj == null) {
- //this little trick allows us to declare prototype objects for
- //Delegators
- Delegator n = NewInstance ();
- IScriptable delegee;
- if (args.Length == 0) {
- delegee = new BuiltinObject ();
- }
- else {
- delegee = ScriptConvert.ToObject (cx, scope, args [0]);
- }
- n.Delegee = delegee;
- return n;
- }
- else {
- return ((IFunction)obj).Construct (cx, scope, args);
- }
- }
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+using EcmaScript.NET.Types;
+
+namespace EcmaScript.NET
+{
+
+ /// This is a helper class for implementing wrappers around Scriptable
+ /// objects. It implements the Function interface and delegates all
+ /// invocations to a delegee Scriptable object. The normal use of this
+ /// class involves creating a sub-class and overriding one or more of
+ /// the methods.
+ ///
+ /// A useful application is the implementation of interceptors,
+ /// pre/post conditions, debugging.
+ ///
+ ///
+ public class Delegator : IFunction
+ {
+
+ /// Retrieve the delegee.
+ ///
+ ///
+ /// the delegee
+ ///
+ /// Set the delegee.
+ ///
+ ///
+ /// the delegee
+ ///
+ virtual public IScriptable Delegee
+ {
+ get
+ {
+ return obj;
+ }
+
+ set
+ {
+ this.obj = value;
+ }
+
+ }
+
+ virtual public string ClassName
+ {
+ get
+ {
+ return obj.ClassName;
+ }
+
+ }
+
+
+ virtual public IScriptable ParentScope
+ {
+ get
+ {
+ return obj.ParentScope;
+ }
+
+ set
+ {
+ obj.ParentScope = value;
+ }
+
+ }
+
+ protected internal IScriptable obj = null;
+
+ /// Create a Delegator prototype.
+ ///
+ /// This constructor should only be used for creating prototype
+ /// objects of Delegator.
+ ///
+ ///
+
+ public Delegator ()
+ {
+ }
+
+ /// Create a new Delegator that forwards requests to a delegee
+ /// Scriptable object.
+ ///
+ ///
+ /// the delegee
+ ///
+ public Delegator (IScriptable obj)
+ {
+ this.obj = obj;
+ }
+
+ /// Crete new Delegator instance.
+ /// The default implementation calls this.getClass().newInstance().
+ ///
+ ///
+ protected internal virtual Delegator NewInstance ()
+ {
+ try {
+ return (Delegator)System.Activator.CreateInstance (this.GetType ());
+ }
+ catch (Exception ex) {
+ throw Context.ThrowAsScriptRuntimeEx (ex);
+ }
+ }
+
+ public virtual object Get (string name, IScriptable start)
+ {
+ return obj.Get (name, start);
+ }
+
+ public virtual object Get (int index, IScriptable start)
+ {
+ return obj.Get (index, start);
+ }
+
+ public virtual bool Has (string name, IScriptable start)
+ {
+ return obj.Has (name, start);
+ }
+
+ public virtual bool Has (int index, IScriptable start)
+ {
+ return obj.Has (index, start);
+ }
+
+ public virtual object Put (string name, IScriptable start, object value)
+ {
+ return obj.Put (name, start, value);
+ }
+
+ public virtual object Put (int index, IScriptable start, object value)
+ {
+ return obj.Put (index, start, value);
+ }
+
+ public virtual void Delete (string name)
+ {
+ obj.Delete (name);
+ }
+
+ public virtual void Delete (int index)
+ {
+ obj.Delete (index);
+ }
+
+ public virtual IScriptable GetPrototype ()
+ {
+ return obj.GetPrototype ();
+ }
+
+ public virtual void SetPrototype (IScriptable prototype)
+ {
+ obj.SetPrototype (prototype);
+ }
+
+ public virtual object [] GetIds ()
+ {
+ return obj.GetIds ();
+ }
+ /// Note that this method does not get forwarded to the delegee if
+ /// the hint parameter is null,
+ /// typeof(Scriptable) or
+ /// typeof(Function). Instead the object
+ /// itself is returned.
+ ///
+ ///
+ /// the type hint
+ ///
+ /// the default value
+ ///
+ ///
+ public virtual object GetDefaultValue (Type hint)
+ {
+ return (hint == null
+ || hint == typeof (IScriptable)
+ || hint == typeof (IFunction))
+ ? this : obj.GetDefaultValue (hint);
+ }
+
+ public virtual bool HasInstance (IScriptable instance)
+ {
+ return obj.HasInstance (instance);
+ }
+
+ public virtual object Call (Context cx, IScriptable scope, IScriptable thisObj, object [] args)
+ {
+ return ((IFunction)obj).Call (cx, scope, thisObj, args);
+ }
+
+ /// Note that if the delegee is null,
+ /// this method creates a new instance of the Delegator itself
+ /// rathert than forwarding the call to the
+ /// delegee. This permits the use of Delegator
+ /// prototypes.
+ ///
+ ///
+ /// the current Context for this thread
+ ///
+ /// an enclosing scope of the caller except
+ /// when the function is called from a closure.
+ ///
+ /// the array of arguments
+ ///
+ /// the allocated object
+ ///
+ ///
+
+ public virtual IScriptable Construct (Context cx, IScriptable scope, object [] args)
+ {
+ if (obj == null) {
+ //this little trick allows us to declare prototype objects for
+ //Delegators
+ Delegator n = NewInstance ();
+ IScriptable delegee;
+ if (args.Length == 0) {
+ delegee = new BuiltinObject ();
+ }
+ else {
+ delegee = ScriptConvert.ToObject (cx, scope, args [0]);
+ }
+ n.Delegee = delegee;
+ return n;
+ }
+ else {
+ return ((IFunction)obj).Construct (cx, scope, args);
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/EcmaScript.NET/EcmaScript.NET.csproj b/src/EcmaScript.NET/EcmaScript.NET.csproj
new file mode 100644
index 0000000..1fb4d0a
--- /dev/null
+++ b/src/EcmaScript.NET/EcmaScript.NET.csproj
@@ -0,0 +1,21 @@
+
+
+
+ netstandard2.0;net45
+ 0.0.0
+ Pure Krome
+ World Domination Technologies
+ This is a custom modified version of the EcmaScript code, mainly created for YUICompressor.NET.
+ 2011
+ https://github.com/PureKrome/EcmaScript.NET/blob/master/License.txt
+ https://github.com/PureKrome/EcmaScript.NET
+ https://github.com/PureKrome/EcmaScript.NET
+ .net c#
+ ecmascript, javascript
+
+
+
+
+
+
+
diff --git a/Code/EcmaScript.NET/EcmaScriptError.cs b/src/EcmaScript.NET/EcmaScriptError.cs
similarity index 97%
rename from Code/EcmaScript.NET/EcmaScriptError.cs
rename to src/EcmaScript.NET/EcmaScriptError.cs
index ebe0713..aa71673 100644
--- a/Code/EcmaScript.NET/EcmaScriptError.cs
+++ b/src/EcmaScript.NET/EcmaScriptError.cs
@@ -1,99 +1,99 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-namespace EcmaScript.NET
-{
-
- /// The class of exceptions raised by the engine as described in
- /// ECMA edition 3. See section 15.11.6 in particular.
- ///
- public class EcmaScriptError : EcmaScriptException
- {
- /// Gets the name of the error.
- ///
- /// ECMA edition 3 defines the following
- /// errors: EvalError, RangeError, ReferenceError,
- /// SyntaxError, TypeError, and URIError. Additional error names
- /// may be added in the future.
- ///
- /// See ECMA edition 3, 15.11.7.9.
- ///
- ///
- /// the name of the error.
- ///
- public virtual string Name
- {
- get
- {
- return m_ErrorName;
- }
-
- }
-
- public override string Message
- {
- get
- {
- return string.Format (
- "\"{0}\", {1} at line {2}: {3}",
- base.SourceName, Name, base.LineNumber, ErrorMessage);
- }
- }
-
- /// Gets the message corresponding to the error.
- ///
- /// See ECMA edition 3, 15.11.7.10.
- ///
- ///
- /// an implemenation-defined string describing the error.
- ///
- public virtual string ErrorMessage
- {
- get
- {
- return m_ErrorMessage;
- }
-
- }
-
- string m_ErrorName;
- string m_ErrorMessage;
-
- /// Create an exception with the specified detail message.
- ///
- /// Errors internal to the JavaScript engine will simply throw a
- /// RuntimeException.
- ///
- ///
- /// the name of the source reponsible for the error
- ///
- /// the line number of the source
- ///
- /// the columnNumber of the source (may be zero if
- /// unknown)
- ///
- /// the source of the line containing the error (may be
- /// null if unknown)
- ///
- internal EcmaScriptError (string errorName, string errorMessage, string sourceName, int lineNumber, string lineSource, int columnNumber)
- {
- RecordErrorOrigin (sourceName, lineNumber, lineSource, columnNumber);
- this.m_ErrorName = errorName;
- this.m_ErrorMessage = errorMessage;
- }
-
- }
-
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+namespace EcmaScript.NET
+{
+
+ /// The class of exceptions raised by the engine as described in
+ /// ECMA edition 3. See section 15.11.6 in particular.
+ ///
+ public class EcmaScriptError : EcmaScriptException
+ {
+ /// Gets the name of the error.
+ ///
+ /// ECMA edition 3 defines the following
+ /// errors: EvalError, RangeError, ReferenceError,
+ /// SyntaxError, TypeError, and URIError. Additional error names
+ /// may be added in the future.
+ ///
+ /// See ECMA edition 3, 15.11.7.9.
+ ///
+ ///
+ /// the name of the error.
+ ///
+ public virtual string Name
+ {
+ get
+ {
+ return m_ErrorName;
+ }
+
+ }
+
+ public override string Message
+ {
+ get
+ {
+ return string.Format (
+ "\"{0}\", {1} at line {2}: {3}",
+ base.SourceName, Name, base.LineNumber, ErrorMessage);
+ }
+ }
+
+ /// Gets the message corresponding to the error.
+ ///
+ /// See ECMA edition 3, 15.11.7.10.
+ ///
+ ///
+ /// an implemenation-defined string describing the error.
+ ///
+ public virtual string ErrorMessage
+ {
+ get
+ {
+ return m_ErrorMessage;
+ }
+
+ }
+
+ string m_ErrorName;
+ string m_ErrorMessage;
+
+ /// Create an exception with the specified detail message.
+ ///
+ /// Errors internal to the JavaScript engine will simply throw a
+ /// RuntimeException.
+ ///
+ ///
+ /// the name of the source reponsible for the error
+ ///
+ /// the line number of the source
+ ///
+ /// the columnNumber of the source (may be zero if
+ /// unknown)
+ ///
+ /// the source of the line containing the error (may be
+ /// null if unknown)
+ ///
+ internal EcmaScriptError (string errorName, string errorMessage, string sourceName, int lineNumber, string lineSource, int columnNumber)
+ {
+ RecordErrorOrigin (sourceName, lineNumber, lineSource, columnNumber);
+ this.m_ErrorName = errorName;
+ this.m_ErrorMessage = errorMessage;
+ }
+
+ }
+
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/EcmaScriptException.cs b/src/EcmaScript.NET/EcmaScriptException.cs
similarity index 94%
rename from Code/EcmaScript.NET/EcmaScriptException.cs
rename to src/EcmaScript.NET/EcmaScriptException.cs
index 7b42740..bb75e19 100644
--- a/Code/EcmaScript.NET/EcmaScriptException.cs
+++ b/src/EcmaScript.NET/EcmaScriptException.cs
@@ -1,221 +1,220 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-using System.IO;
-using System.Text;
-
-namespace EcmaScript.NET
-{
-
- ///
- /// The class of exceptions thrown by the JavaScript engine.
- ///
- public abstract class EcmaScriptException : ApplicationException
- {
-
- public override string Message
- {
- get
- {
- string details = base.Message;
- if (m_SourceName == null || m_LineNumber <= 0) {
- return details;
- }
- StringBuilder buf = new StringBuilder (details);
- buf.Append (" (");
- if (m_SourceName != null) {
- buf.Append (m_SourceName);
- }
- if (m_LineNumber > 0) {
- buf.Append ('#');
- buf.Append (m_LineNumber);
- }
- buf.Append (')');
- return buf.ToString ();
- }
-
- }
-
- internal EcmaScriptException ()
- {
- Interpreter.captureInterpreterStackInfo (this);
- }
-
- internal EcmaScriptException (string details)
- : base (details)
- {
- Interpreter.captureInterpreterStackInfo (this);
- }
-
-
- internal EcmaScriptException (string details, Exception innerException)
- : base (details, innerException)
- {
- Interpreter.captureInterpreterStackInfo (this);
- }
- /// Get the uri of the script source containing the error, or null
- /// if that information is not available.
- ///
- public virtual string SourceName
- {
- get
- {
- return m_SourceName;
- }
- }
-
- /// Initialize the uri of the script source containing the error.
- ///
- ///
- /// the uri of the script source reponsible for the error.
- /// It should not be null.
- ///
- ///
- /// IllegalStateException if the method is called more then once.
- public void InitSourceName (string sourceName)
- {
- if (sourceName == null)
- throw new ArgumentException ();
- if (this.m_SourceName != null)
- throw new ApplicationException ();
- this.m_SourceName = sourceName;
- }
-
- /// Returns the line number of the statement causing the error,
- /// or zero if not available.
- ///
- public int LineNumber
- {
- get
- {
- return m_LineNumber;
- }
- }
-
- /// Initialize the line number of the script statement causing the error.
- ///
- ///
- /// the line number in the script source.
- /// It should be positive number.
- ///
- ///
- /// IllegalStateException if the method is called more then once.
- public void InitLineNumber (int lineNumber)
- {
- if (lineNumber <= 0)
- throw new ArgumentException (Convert.ToString (lineNumber));
- if (this.m_LineNumber > 0)
- throw new ApplicationException ();
- this.m_LineNumber = lineNumber;
- }
-
- /// The column number of the location of the error, or zero if unknown.
- public int ColumnNumber
- {
- get
- {
- return m_ColumnNumber;
- }
- }
-
- /// Initialize the column number of the script statement causing the error.
- ///
- ///
- /// the column number in the script source.
- /// It should be positive number.
- ///
- ///
- /// IllegalStateException if the method is called more then once.
- public void InitColumnNumber (int columnNumber)
- {
- if (columnNumber <= 0)
- throw new ArgumentException (Convert.ToString (columnNumber));
- if (this.m_ColumnNumber > 0)
- throw new ApplicationException ();
- this.m_ColumnNumber = columnNumber;
- }
-
- /// The source text of the line causing the error, or null if unknown.
- public string LineSource
- {
- get
- {
- return m_LineSource;
- }
- }
-
- /// Initialize the text of the source line containing the error.
- ///
- ///
- /// the text of the source line reponsible for the error.
- /// It should not be null.
- ///
- ///
- /// IllegalStateException if the method is called more then once.
- public void InitLineSource (string lineSource)
- {
- if (lineSource == null)
- throw new ArgumentException ();
- if (this.m_LineSource != null)
- throw new ApplicationException ();
- this.m_LineSource = lineSource;
- }
-
- internal void RecordErrorOrigin (string sourceName, int lineNumber, string lineSource, int columnNumber)
- {
- if (sourceName != null) {
- InitSourceName (sourceName);
- }
- if (lineNumber != 0) {
- InitLineNumber (lineNumber);
- }
- if (lineSource != null) {
- InitLineSource (lineSource);
- }
- if (columnNumber != 0) {
- InitColumnNumber (columnNumber);
- }
- InitScriptStackTrace ();
- }
-
- private string m_SourceName;
- private int m_LineNumber;
- private string m_LineSource;
- private int m_ColumnNumber;
-
- internal object m_InterpreterStackInfo;
- internal int [] m_InterpreterLineData;
-
- private void InitScriptStackTrace () {
- m_ScriptStackTrace = Interpreter.GetStack (this);
- }
- private string m_ScriptStackTrace = null;
- public string ScriptStackTrace
- {
- get
- {
-
- return m_ScriptStackTrace;
- }
- }
-
- public override string ToString ()
- {
- if (this.StackTrace != null)
- return Interpreter.getPatchedStack (this, this.StackTrace.ToString ());
- return ScriptStackTrace;
- }
-
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+using System.Text;
+
+namespace EcmaScript.NET
+{
+
+ ///
+ /// The class of exceptions thrown by the JavaScript engine.
+ ///
+ public abstract class EcmaScriptException : Exception
+ {
+
+ public override string Message
+ {
+ get
+ {
+ string details = base.Message;
+ if (m_SourceName == null || m_LineNumber <= 0) {
+ return details;
+ }
+ StringBuilder buf = new StringBuilder (details);
+ buf.Append (" (");
+ if (m_SourceName != null) {
+ buf.Append (m_SourceName);
+ }
+ if (m_LineNumber > 0) {
+ buf.Append ('#');
+ buf.Append (m_LineNumber);
+ }
+ buf.Append (')');
+ return buf.ToString ();
+ }
+
+ }
+
+ internal EcmaScriptException ()
+ {
+ Interpreter.captureInterpreterStackInfo (this);
+ }
+
+ internal EcmaScriptException (string details)
+ : base (details)
+ {
+ Interpreter.captureInterpreterStackInfo (this);
+ }
+
+
+ internal EcmaScriptException (string details, Exception innerException)
+ : base (details, innerException)
+ {
+ Interpreter.captureInterpreterStackInfo (this);
+ }
+ /// Get the uri of the script source containing the error, or null
+ /// if that information is not available.
+ ///
+ public virtual string SourceName
+ {
+ get
+ {
+ return m_SourceName;
+ }
+ }
+
+ /// Initialize the uri of the script source containing the error.
+ ///
+ ///
+ /// the uri of the script source reponsible for the error.
+ /// It should not be null.
+ ///
+ ///
+ /// IllegalStateException if the method is called more then once.
+ public void InitSourceName (string sourceName)
+ {
+ if (sourceName == null)
+ throw new ArgumentException ();
+ if (this.m_SourceName != null)
+ throw new Exception ();
+ this.m_SourceName = sourceName;
+ }
+
+ /// Returns the line number of the statement causing the error,
+ /// or zero if not available.
+ ///
+ public int LineNumber
+ {
+ get
+ {
+ return m_LineNumber;
+ }
+ }
+
+ /// Initialize the line number of the script statement causing the error.
+ ///
+ ///
+ /// the line number in the script source.
+ /// It should be positive number.
+ ///
+ ///
+ /// IllegalStateException if the method is called more then once.
+ public void InitLineNumber (int lineNumber)
+ {
+ if (lineNumber <= 0)
+ throw new ArgumentException (Convert.ToString (lineNumber));
+ if (this.m_LineNumber > 0)
+ throw new Exception ();
+ this.m_LineNumber = lineNumber;
+ }
+
+ /// The column number of the location of the error, or zero if unknown.
+ public int ColumnNumber
+ {
+ get
+ {
+ return m_ColumnNumber;
+ }
+ }
+
+ /// Initialize the column number of the script statement causing the error.
+ ///
+ ///
+ /// the column number in the script source.
+ /// It should be positive number.
+ ///
+ ///
+ /// IllegalStateException if the method is called more then once.
+ public void InitColumnNumber (int columnNumber)
+ {
+ if (columnNumber <= 0)
+ throw new ArgumentException (Convert.ToString (columnNumber));
+ if (this.m_ColumnNumber > 0)
+ throw new Exception ();
+ this.m_ColumnNumber = columnNumber;
+ }
+
+ /// The source text of the line causing the error, or null if unknown.
+ public string LineSource
+ {
+ get
+ {
+ return m_LineSource;
+ }
+ }
+
+ /// Initialize the text of the source line containing the error.
+ ///
+ ///
+ /// the text of the source line reponsible for the error.
+ /// It should not be null.
+ ///
+ ///
+ /// IllegalStateException if the method is called more then once.
+ public void InitLineSource (string lineSource)
+ {
+ if (lineSource == null)
+ throw new ArgumentException ();
+ if (this.m_LineSource != null)
+ throw new Exception ();
+ this.m_LineSource = lineSource;
+ }
+
+ internal void RecordErrorOrigin (string sourceName, int lineNumber, string lineSource, int columnNumber)
+ {
+ if (sourceName != null) {
+ InitSourceName (sourceName);
+ }
+ if (lineNumber != 0) {
+ InitLineNumber (lineNumber);
+ }
+ if (lineSource != null) {
+ InitLineSource (lineSource);
+ }
+ if (columnNumber != 0) {
+ InitColumnNumber (columnNumber);
+ }
+ InitScriptStackTrace ();
+ }
+
+ private string m_SourceName;
+ private int m_LineNumber;
+ private string m_LineSource;
+ private int m_ColumnNumber;
+
+ internal object m_InterpreterStackInfo;
+ internal int [] m_InterpreterLineData;
+
+ private void InitScriptStackTrace () {
+ m_ScriptStackTrace = Interpreter.GetStack (this);
+ }
+ private string m_ScriptStackTrace = null;
+ public string ScriptStackTrace
+ {
+ get
+ {
+
+ return m_ScriptStackTrace;
+ }
+ }
+
+ public override string ToString ()
+ {
+ if (this.StackTrace != null)
+ return Interpreter.getPatchedStack (this, this.StackTrace.ToString ());
+ return ScriptStackTrace;
+ }
+
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/EcmaScriptRuntimeException.cs b/src/EcmaScript.NET/EcmaScriptRuntimeException.cs
similarity index 97%
rename from Code/EcmaScript.NET/EcmaScriptRuntimeException.cs
rename to src/EcmaScript.NET/EcmaScriptRuntimeException.cs
index 6ff1f34..a67999a 100644
--- a/Code/EcmaScript.NET/EcmaScriptRuntimeException.cs
+++ b/src/EcmaScript.NET/EcmaScriptRuntimeException.cs
@@ -1,84 +1,84 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-namespace EcmaScript.NET
-{
-
- /// The class of exceptions thrown by the JavaScript engine.
-
- public class EcmaScriptRuntimeException : EcmaScriptException
- {
-
- public EcmaScriptRuntimeException (Exception innerException)
- : base (innerException.Message, innerException)
- {
- int [] linep = new int [] { 0 };
- string sourceName = Context.GetSourcePositionFromStack (linep);
- int lineNumber = linep [0];
- if (sourceName != null) {
- InitSourceName (sourceName);
- }
- if (lineNumber != 0) {
- InitLineNumber (lineNumber);
- }
- }
-
- public EcmaScriptRuntimeException (string detail)
- : base (detail)
- {
- }
-
- /// Create an exception with the specified detail message.
- ///
- /// Errors internal to the JavaScript engine will simply throw a
- /// RuntimeException.
- ///
- ///
- /// the error message
- ///
- /// the name of the source reponsible for the error
- ///
- /// the line number of the source
- ///
- public EcmaScriptRuntimeException (string detail, string sourceName, int lineNumber)
- : this (detail, sourceName, lineNumber, null, 0)
- {
- }
-
- /// Create an exception with the specified detail message.
- ///
- /// Errors internal to the JavaScript engine will simply throw a
- /// RuntimeException.
- ///
- ///
- /// the error message
- ///
- /// the name of the source reponsible for the error
- ///
- /// the line number of the source
- ///
- /// the columnNumber of the source (may be zero if
- /// unknown)
- ///
- /// the source of the line containing the error (may be
- /// null if unknown)
- ///
- public EcmaScriptRuntimeException (string detail, string sourceName, int lineNumber, string lineSource, int columnNumber)
- : base (detail)
- {
- RecordErrorOrigin (sourceName, lineNumber, lineSource, columnNumber);
- }
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+namespace EcmaScript.NET
+{
+
+ /// The class of exceptions thrown by the JavaScript engine.
+
+ public class EcmaScriptRuntimeException : EcmaScriptException
+ {
+
+ public EcmaScriptRuntimeException (Exception innerException)
+ : base (innerException.Message, innerException)
+ {
+ int [] linep = new int [] { 0 };
+ string sourceName = Context.GetSourcePositionFromStack (linep);
+ int lineNumber = linep [0];
+ if (sourceName != null) {
+ InitSourceName (sourceName);
+ }
+ if (lineNumber != 0) {
+ InitLineNumber (lineNumber);
+ }
+ }
+
+ public EcmaScriptRuntimeException (string detail)
+ : base (detail)
+ {
+ }
+
+ /// Create an exception with the specified detail message.
+ ///
+ /// Errors internal to the JavaScript engine will simply throw a
+ /// RuntimeException.
+ ///
+ ///
+ /// the error message
+ ///
+ /// the name of the source reponsible for the error
+ ///
+ /// the line number of the source
+ ///
+ public EcmaScriptRuntimeException (string detail, string sourceName, int lineNumber)
+ : this (detail, sourceName, lineNumber, null, 0)
+ {
+ }
+
+ /// Create an exception with the specified detail message.
+ ///
+ /// Errors internal to the JavaScript engine will simply throw a
+ /// RuntimeException.
+ ///
+ ///
+ /// the error message
+ ///
+ /// the name of the source reponsible for the error
+ ///
+ /// the line number of the source
+ ///
+ /// the columnNumber of the source (may be zero if
+ /// unknown)
+ ///
+ /// the source of the line containing the error (may be
+ /// null if unknown)
+ ///
+ public EcmaScriptRuntimeException (string detail, string sourceName, int lineNumber, string lineSource, int columnNumber)
+ : base (detail)
+ {
+ RecordErrorOrigin (sourceName, lineNumber, lineSource, columnNumber);
+ }
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/EcmaScriptThrow.cs b/src/EcmaScript.NET/EcmaScriptThrow.cs
similarity index 96%
rename from Code/EcmaScript.NET/EcmaScriptThrow.cs
rename to src/EcmaScript.NET/EcmaScriptThrow.cs
index a52b857..451c147 100644
--- a/Code/EcmaScript.NET/EcmaScriptThrow.cs
+++ b/src/EcmaScript.NET/EcmaScriptThrow.cs
@@ -1,63 +1,63 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-namespace EcmaScript.NET
-{
-
- /// Java reflection of JavaScript exceptions.
- /// Instances of this class are thrown by the JavaScript 'throw' keyword.
- ///
- ///
-
- public class EcmaScriptThrow : EcmaScriptException
- {
-
- /// the value wrapped by this exception
- ///
- public virtual object Value
- {
- get
- {
- return value;
- }
-
- }
-
- ///
- /// Create a JavaScript exception wrapping the given JavaScript value
- ///
- /// the JavaScript value thrown.
- public EcmaScriptThrow (object value, string sourceName, int lineNumber)
- {
- RecordErrorOrigin (sourceName, lineNumber, null, 0);
- this.value = value;
- }
-
- public override string Message
- {
- get
- {
- IScriptable scriptable = (value as IScriptable);
- if (scriptable != null) {
- // to prevent potential of evaluation and throwing more exceptions
- return ScriptRuntime.DefaultObjectToString (scriptable);
- }
- return ScriptConvert.ToString (value);
- }
- }
-
- private object value;
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+namespace EcmaScript.NET
+{
+
+ /// Java reflection of JavaScript exceptions.
+ /// Instances of this class are thrown by the JavaScript 'throw' keyword.
+ ///
+ ///
+
+ public class EcmaScriptThrow : EcmaScriptException
+ {
+
+ /// the value wrapped by this exception
+ ///
+ public virtual object Value
+ {
+ get
+ {
+ return value;
+ }
+
+ }
+
+ ///
+ /// Create a JavaScript exception wrapping the given JavaScript value
+ ///
+ /// the JavaScript value thrown.
+ public EcmaScriptThrow (object value, string sourceName, int lineNumber)
+ {
+ RecordErrorOrigin (sourceName, lineNumber, null, 0);
+ this.value = value;
+ }
+
+ public override string Message
+ {
+ get
+ {
+ IScriptable scriptable = (value as IScriptable);
+ if (scriptable != null) {
+ // to prevent potential of evaluation and throwing more exceptions
+ return ScriptRuntime.DefaultObjectToString (scriptable);
+ }
+ return ScriptConvert.ToString (value);
+ }
+ }
+
+ private object value;
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/ErrorReporter.cs b/src/EcmaScript.NET/ErrorReporter.cs
similarity index 97%
rename from Code/EcmaScript.NET/ErrorReporter.cs
rename to src/EcmaScript.NET/ErrorReporter.cs
index 608442c..a8a9d45 100644
--- a/Code/EcmaScript.NET/ErrorReporter.cs
+++ b/src/EcmaScript.NET/ErrorReporter.cs
@@ -1,91 +1,91 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-namespace EcmaScript.NET
-{
-
- /// This is interface defines a protocol for the reporting of
- /// errors during JavaScript translation or execution.
- ///
- ///
-
- public interface ErrorReporter
- {
-
- /// Report a warning.
- ///
- /// The implementing class may choose to ignore the warning
- /// if it desires.
- ///
- ///
- /// a String describing the warning
- ///
- /// a String describing the JavaScript source
- /// where the warning occured; typically a filename or URL
- ///
- /// the line number associated with the warning
- ///
- /// the text of the line (may be null)
- ///
- /// the offset into lineSource where problem was detected
- ///
- void Warning (string message, string sourceName, int line, string lineSource, int lineOffset);
-
- /// Report an error.
- ///
- /// The implementing class is free to throw an exception if
- /// it desires.
- ///
- /// If execution has not yet begun, the JavaScript engine is
- /// free to find additional errors rather than terminating
- /// the translation. It will not execute a script that had
- /// errors, however.
- ///
- ///
- /// a String describing the error
- ///
- /// a String describing the JavaScript source
- /// where the error occured; typically a filename or URL
- ///
- /// the line number associated with the error
- ///
- /// the text of the line (may be null)
- ///
- /// the offset into lineSource where problem was detected
- ///
- void Error (string message, string sourceName, int line, string lineSource, int lineOffset);
-
- /// Creates an EvaluatorException that may be thrown.
- ///
- /// runtimeErrors, unlike errors, will always terminate the
- /// current script.
- ///
- ///
- /// a String describing the error
- ///
- /// a String describing the JavaScript source
- /// where the error occured; typically a filename or URL
- ///
- /// the line number associated with the error
- ///
- /// the text of the line (may be null)
- ///
- /// the offset into lineSource where problem was detected
- ///
- /// an EvaluatorException that will be thrown.
- ///
- EcmaScriptRuntimeException RuntimeError (string message, string sourceName, int line, string lineSource, int lineOffset);
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+namespace EcmaScript.NET
+{
+
+ /// This is interface defines a protocol for the reporting of
+ /// errors during JavaScript translation or execution.
+ ///
+ ///
+
+ public interface ErrorReporter
+ {
+
+ /// Report a warning.
+ ///
+ /// The implementing class may choose to ignore the warning
+ /// if it desires.
+ ///
+ ///
+ /// a String describing the warning
+ ///
+ /// a String describing the JavaScript source
+ /// where the warning occured; typically a filename or URL
+ ///
+ /// the line number associated with the warning
+ ///
+ /// the text of the line (may be null)
+ ///
+ /// the offset into lineSource where problem was detected
+ ///
+ void Warning (string message, string sourceName, int line, string lineSource, int lineOffset);
+
+ /// Report an error.
+ ///
+ /// The implementing class is free to throw an exception if
+ /// it desires.
+ ///
+ /// If execution has not yet begun, the JavaScript engine is
+ /// free to find additional errors rather than terminating
+ /// the translation. It will not execute a script that had
+ /// errors, however.
+ ///
+ ///
+ /// a String describing the error
+ ///
+ /// a String describing the JavaScript source
+ /// where the error occured; typically a filename or URL
+ ///
+ /// the line number associated with the error
+ ///
+ /// the text of the line (may be null)
+ ///
+ /// the offset into lineSource where problem was detected
+ ///
+ void Error (string message, string sourceName, int line, string lineSource, int lineOffset);
+
+ /// Creates an EvaluatorException that may be thrown.
+ ///
+ /// runtimeErrors, unlike errors, will always terminate the
+ /// current script.
+ ///
+ ///
+ /// a String describing the error
+ ///
+ /// a String describing the JavaScript source
+ /// where the error occured; typically a filename or URL
+ ///
+ /// the line number associated with the error
+ ///
+ /// the text of the line (may be null)
+ ///
+ /// the offset into lineSource where problem was detected
+ ///
+ /// an EvaluatorException that will be thrown.
+ ///
+ EcmaScriptRuntimeException RuntimeError (string message, string sourceName, int line, string lineSource, int lineOffset);
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/FunctionNode.cs b/src/EcmaScript.NET/FunctionNode.cs
similarity index 96%
rename from Code/EcmaScript.NET/FunctionNode.cs
rename to src/EcmaScript.NET/FunctionNode.cs
index 0861b42..74bee4b 100644
--- a/Code/EcmaScript.NET/FunctionNode.cs
+++ b/src/EcmaScript.NET/FunctionNode.cs
@@ -1,85 +1,85 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-namespace EcmaScript.NET
-{
-
- public class FunctionNode : ScriptOrFnNode
- {
- virtual public string FunctionName
- {
- get
- {
- return functionName;
- }
-
- }
- virtual public bool IgnoreDynamicScope
- {
- get
- {
- return itsIgnoreDynamicScope;
- }
-
- }
- virtual public int FunctionType
- {
- get
- {
- return itsFunctionType;
- }
-
- }
-
- public FunctionNode (string name)
- : base (Token.FUNCTION)
- {
- functionName = name;
- }
-
- public virtual bool RequiresActivation
- {
-
- get
- {
- return itsNeedsActivation;
- }
- }
-
- ///
- /// There are three types of functions that can be defined. The first
- /// is a function statement. This is a function appearing as a top-level
- /// statement (i.e., not nested inside some other statement) in either a
- /// script or a function.
- ///
- /// The second is a function expression, which is a function appearing in
- /// an expression except for the third type, which is...
- ///
- /// The third type is a function expression where the expression is the
- /// top-level expression in an expression statement.
- ///
- /// The three types of functions have different treatment and must be
- /// distinquished.
- ///
- public const int FUNCTION_STATEMENT = 1;
- public const int FUNCTION_EXPRESSION = 2;
- public const int FUNCTION_EXPRESSION_STATEMENT = 3;
-
- internal string functionName;
- internal bool itsNeedsActivation;
- internal int itsFunctionType;
- internal bool itsIgnoreDynamicScope;
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+namespace EcmaScript.NET
+{
+
+ public class FunctionNode : ScriptOrFnNode
+ {
+ virtual public string FunctionName
+ {
+ get
+ {
+ return functionName;
+ }
+
+ }
+ virtual public bool IgnoreDynamicScope
+ {
+ get
+ {
+ return itsIgnoreDynamicScope;
+ }
+
+ }
+ virtual public int FunctionType
+ {
+ get
+ {
+ return itsFunctionType;
+ }
+
+ }
+
+ public FunctionNode (string name)
+ : base (Token.FUNCTION)
+ {
+ functionName = name;
+ }
+
+ public virtual bool RequiresActivation
+ {
+
+ get
+ {
+ return itsNeedsActivation;
+ }
+ }
+
+ ///
+ /// There are three types of functions that can be defined. The first
+ /// is a function statement. This is a function appearing as a top-level
+ /// statement (i.e., not nested inside some other statement) in either a
+ /// script or a function.
+ ///
+ /// The second is a function expression, which is a function appearing in
+ /// an expression except for the third type, which is...
+ ///
+ /// The third type is a function expression where the expression is the
+ /// top-level expression in an expression statement.
+ ///
+ /// The three types of functions have different treatment and must be
+ /// distinquished.
+ ///
+ public const int FUNCTION_STATEMENT = 1;
+ public const int FUNCTION_EXPRESSION = 2;
+ public const int FUNCTION_EXPRESSION_STATEMENT = 3;
+
+ internal string functionName;
+ internal bool itsNeedsActivation;
+ internal int itsFunctionType;
+ internal bool itsIgnoreDynamicScope;
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/Helpers/CliHelper.cs b/src/EcmaScript.NET/Helpers/CliHelper.cs
similarity index 96%
rename from Code/EcmaScript.NET/Helpers/CliHelper.cs
rename to src/EcmaScript.NET/Helpers/CliHelper.cs
index f743f93..71238c0 100644
--- a/Code/EcmaScript.NET/Helpers/CliHelper.cs
+++ b/src/EcmaScript.NET/Helpers/CliHelper.cs
@@ -1,286 +1,286 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-using System.Text;
-using System.Reflection;
-using System.Collections;
-using System.Runtime.InteropServices;
-
-namespace EcmaScript.NET
-{
-
- sealed class CliHelper
- {
-
- private CliHelper ()
- {
- ;
- }
-
- internal static Type GetType (string className)
- {
- try {
- return Type.GetType (className);
- }
- catch {
- ;
- }
- return null;
- }
-
- internal static bool IsNegativeZero (double d)
- {
- if (double.IsNaN (d))
- return false;
- if (d != 0.0)
- return false;
- return (double.PositiveInfinity / d) == double.NegativeInfinity;
- }
-
- internal static bool IsPositiveZero (double d)
- {
- if (double.IsNaN (d))
- return false;
- if (d != 0.0)
- return false;
- return (double.PositiveInfinity / d) == double.PositiveInfinity;
- }
-
- internal static new bool Equals (object o1, object o2)
- {
- if (o1 == null && o2 == null)
- return true;
- if (o1 == null || o2 == null)
- return false;
- return o1.Equals (o2);
- }
-
- internal static string ToSignature (ConstructorInfo ci)
- {
- StringBuilder sb = new StringBuilder ();
- sb.Append (ToSignature (ci.DeclaringType));
- sb.Append (ToSignature ('(', ci.GetParameters (), ')'));
- return sb.ToString ();
- }
- internal static string ToSignature (PropertyInfo pi)
- {
- StringBuilder sb = new StringBuilder ();
- sb.Append (ToSignature (pi.PropertyType));
- sb.Append (" ");
- sb.Append (ToSignature (pi.DeclaringType));
- sb.Append (".");
- sb.Append (pi.Name);
- sb.Append (ToSignature ('[', pi.GetIndexParameters (), ']'));
- return sb.ToString ();
- }
-
- internal static string ToSignature (FieldInfo fi)
- {
- StringBuilder sb = new StringBuilder ();
- sb.Append (ToSignature (fi.FieldType));
- sb.Append (" ");
- sb.Append (ToSignature (fi.DeclaringType));
- sb.Append (".");
- sb.Append (fi.Name);
- return sb.ToString ();
- }
-
- internal static string ToSignature (object [] args)
- {
- StringBuilder sb = new StringBuilder ();
- for (int i = 0; i < args.Length; i++) {
- if (i > 0)
- sb.Append (", ");
- sb.Append (ToSignature (args [0].GetType ()));
- }
- return sb.ToString ();
- }
-
- internal static string ToSignature (MemberInfo mi)
- {
- if (mi is PropertyInfo)
- return ToSignature ((PropertyInfo)mi);
- if (mi is FieldInfo)
- return ToSignature ((FieldInfo)mi);
- if (mi is ConstructorInfo)
- return ToSignature ((ConstructorInfo)mi);
- if (mi is MethodInfo)
- return ToSignature ((MethodInfo)mi);
- return "[unknown: " + mi.GetType ().FullName + "]";
- }
-
- internal static string ToSignature (char parenOpen, ParameterInfo [] pi, char parenClose)
- {
- StringBuilder sb = new StringBuilder ();
- sb.Append (parenOpen);
- for (int i = 0; i < pi.Length; i++) {
- if (i > 0)
- sb.Append (", ");
- if (pi [i].IsOut)
- sb.Append ("out ");
- if (pi [i].IsIn)
- sb.Append ("in ");
- if (IsParamsParameter (pi [i]))
- sb.Append ("params ");
- sb.Append (ToSignature (pi [i].ParameterType));
- sb.Append (" ");
- sb.Append (pi [i].Name);
- }
- sb.Append (parenClose);
- return sb.ToString ();
- }
-
-
- internal static string ToSignature (MethodInfo mi)
- {
- StringBuilder sb = new StringBuilder ();
- sb.Append (ToSignature (mi.ReturnType));
- sb.Append (" ");
- sb.Append (ToSignature (mi.DeclaringType));
- sb.Append (".");
- sb.Append (mi.Name);
- sb.Append (ToSignature ('(', mi.GetParameters (), ')'));
- return sb.ToString ();
- }
-
- internal static bool HasParamsParameter (MethodBase mb)
- {
- return HasParamsParameter (mb.GetParameters ());
- }
-
- internal static bool HasParamsParameter (ParameterInfo [] pis)
- {
- for (int i = 0; i < pis.Length; i++)
- if (IsParamsParameter (pis [i]))
- return true;
- return false;
- }
-
- internal static bool IsParamsParameter (ParameterInfo pi)
- {
- ParamArrayAttribute attr = (ParamArrayAttribute)
- CliHelper.GetCustomAttribute (typeof (ParamArrayAttribute), pi);
- return (attr != null);
- }
-
-
- internal static string ToSignature (Type type)
- {
- if (type.IsArray) {
- string ret = ToSignature (type.GetElementType ());
- for (int i = 0; i < type.GetArrayRank (); i++)
- ret += "[]";
- return ret;
- }
- if (type == typeof (short))
- return "short";
- if (type == typeof (ushort))
- return "ushort";
- if (type == typeof (int))
- return "int";
- if (type == typeof (uint))
- return "uint";
- if (type == typeof (ulong))
- return "ulong";
- if (type == typeof (long))
- return "long";
- if (type == typeof (void))
- return "void";
- if (type == typeof (bool))
- return "bool";
- if (type == typeof (double))
- return "double";
- if (type == typeof (decimal))
- return "decimal";
- if (type == typeof (object))
- return "object";
- return type.FullName;
- }
-
- internal static bool IsNumberType (Type type)
- {
- return (
- type == typeof (Int16)
- || type == typeof (UInt16)
- || type == typeof (Int32)
- || type == typeof (UInt32)
- || type == typeof (Int64)
- || type == typeof (UInt64)
- || type == typeof (Single)
- || type == typeof (Double)
- || type == typeof (Decimal));
- }
-
- internal static bool IsNumber (object value)
- {
- return (
- value is Int16
- || value is UInt16
- || value is Int32
- || value is UInt32
- || value is Int64
- || value is UInt64
- || value is Single
- || value is Double
- || value is Decimal);
- }
-
- internal static object CreateInstance (Type cl)
- {
- try {
- return System.Activator.CreateInstance (cl);
- }
- catch {
- ;
- }
- return null;
- }
-
- internal static object GetCustomAttribute (Type type, Type attribute)
- {
- object [] attributes = type.GetCustomAttributes (attribute, true);
- if (attributes.Length < 1)
- return null;
- return attributes [0];
- }
-
- internal static object GetCustomAttribute (Type type, MemberInfo mi)
- {
- object attribute = null;
- object [] attributes = mi.GetCustomAttributes (type, true);
- if (attributes.Length > 0)
- attribute = attributes [0];
- return attribute;
- }
-
- internal static object GetCustomAttribute (Type type, ParameterInfo pi)
- {
- object [] attributes = pi.GetCustomAttributes (type, true);
- if (attributes.Length < 1)
- return null;
- return attributes [0];
- }
-
- internal static Type [] GetParameterTypes (ParameterInfo [] parameters)
- {
- Type [] types = new Type [parameters.Length];
- for (int i = 0; i < types.Length; i++) {
- types [i] = parameters [i].ParameterType;
- }
- return types;
- }
-
- }
-
-}
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+using System.Text;
+using System.Reflection;
+using System.Collections;
+using System.Runtime.InteropServices;
+
+namespace EcmaScript.NET
+{
+
+ sealed class CliHelper
+ {
+
+ private CliHelper ()
+ {
+ ;
+ }
+
+ internal static Type GetType (string className)
+ {
+ try {
+ return Type.GetType (className);
+ }
+ catch {
+ ;
+ }
+ return null;
+ }
+
+ internal static bool IsNegativeZero (double d)
+ {
+ if (double.IsNaN (d))
+ return false;
+ if (d != 0.0)
+ return false;
+ return (double.PositiveInfinity / d) == double.NegativeInfinity;
+ }
+
+ internal static bool IsPositiveZero (double d)
+ {
+ if (double.IsNaN (d))
+ return false;
+ if (d != 0.0)
+ return false;
+ return (double.PositiveInfinity / d) == double.PositiveInfinity;
+ }
+
+ internal static new bool Equals (object o1, object o2)
+ {
+ if (o1 == null && o2 == null)
+ return true;
+ if (o1 == null || o2 == null)
+ return false;
+ return o1.Equals (o2);
+ }
+
+ internal static string ToSignature (ConstructorInfo ci)
+ {
+ StringBuilder sb = new StringBuilder ();
+ sb.Append (ToSignature (ci.DeclaringType));
+ sb.Append (ToSignature ('(', ci.GetParameters (), ')'));
+ return sb.ToString ();
+ }
+ internal static string ToSignature (PropertyInfo pi)
+ {
+ StringBuilder sb = new StringBuilder ();
+ sb.Append (ToSignature (pi.PropertyType));
+ sb.Append (" ");
+ sb.Append (ToSignature (pi.DeclaringType));
+ sb.Append (".");
+ sb.Append (pi.Name);
+ sb.Append (ToSignature ('[', pi.GetIndexParameters (), ']'));
+ return sb.ToString ();
+ }
+
+ internal static string ToSignature (FieldInfo fi)
+ {
+ StringBuilder sb = new StringBuilder ();
+ sb.Append (ToSignature (fi.FieldType));
+ sb.Append (" ");
+ sb.Append (ToSignature (fi.DeclaringType));
+ sb.Append (".");
+ sb.Append (fi.Name);
+ return sb.ToString ();
+ }
+
+ internal static string ToSignature (object [] args)
+ {
+ StringBuilder sb = new StringBuilder ();
+ for (int i = 0; i < args.Length; i++) {
+ if (i > 0)
+ sb.Append (", ");
+ sb.Append (ToSignature (args [0].GetType ()));
+ }
+ return sb.ToString ();
+ }
+
+ internal static string ToSignature (MemberInfo mi)
+ {
+ if (mi is PropertyInfo)
+ return ToSignature ((PropertyInfo)mi);
+ if (mi is FieldInfo)
+ return ToSignature ((FieldInfo)mi);
+ if (mi is ConstructorInfo)
+ return ToSignature ((ConstructorInfo)mi);
+ if (mi is MethodInfo)
+ return ToSignature ((MethodInfo)mi);
+ return "[unknown: " + mi.GetType ().FullName + "]";
+ }
+
+ internal static string ToSignature (char parenOpen, ParameterInfo [] pi, char parenClose)
+ {
+ StringBuilder sb = new StringBuilder ();
+ sb.Append (parenOpen);
+ for (int i = 0; i < pi.Length; i++) {
+ if (i > 0)
+ sb.Append (", ");
+ if (pi [i].IsOut)
+ sb.Append ("out ");
+ if (pi [i].IsIn)
+ sb.Append ("in ");
+ if (IsParamsParameter (pi [i]))
+ sb.Append ("params ");
+ sb.Append (ToSignature (pi [i].ParameterType));
+ sb.Append (" ");
+ sb.Append (pi [i].Name);
+ }
+ sb.Append (parenClose);
+ return sb.ToString ();
+ }
+
+
+ internal static string ToSignature (MethodInfo mi)
+ {
+ StringBuilder sb = new StringBuilder ();
+ sb.Append (ToSignature (mi.ReturnType));
+ sb.Append (" ");
+ sb.Append (ToSignature (mi.DeclaringType));
+ sb.Append (".");
+ sb.Append (mi.Name);
+ sb.Append (ToSignature ('(', mi.GetParameters (), ')'));
+ return sb.ToString ();
+ }
+
+ internal static bool HasParamsParameter (MethodBase mb)
+ {
+ return HasParamsParameter (mb.GetParameters ());
+ }
+
+ internal static bool HasParamsParameter (ParameterInfo [] pis)
+ {
+ for (int i = 0; i < pis.Length; i++)
+ if (IsParamsParameter (pis [i]))
+ return true;
+ return false;
+ }
+
+ internal static bool IsParamsParameter (ParameterInfo pi)
+ {
+ ParamArrayAttribute attr = (ParamArrayAttribute)
+ CliHelper.GetCustomAttribute (typeof (ParamArrayAttribute), pi);
+ return (attr != null);
+ }
+
+
+ internal static string ToSignature (Type type)
+ {
+ if (type.IsArray) {
+ string ret = ToSignature (type.GetElementType ());
+ for (int i = 0; i < type.GetArrayRank (); i++)
+ ret += "[]";
+ return ret;
+ }
+ if (type == typeof (short))
+ return "short";
+ if (type == typeof (ushort))
+ return "ushort";
+ if (type == typeof (int))
+ return "int";
+ if (type == typeof (uint))
+ return "uint";
+ if (type == typeof (ulong))
+ return "ulong";
+ if (type == typeof (long))
+ return "long";
+ if (type == typeof (void))
+ return "void";
+ if (type == typeof (bool))
+ return "bool";
+ if (type == typeof (double))
+ return "double";
+ if (type == typeof (decimal))
+ return "decimal";
+ if (type == typeof (object))
+ return "object";
+ return type.FullName;
+ }
+
+ internal static bool IsNumberType (Type type)
+ {
+ return (
+ type == typeof (Int16)
+ || type == typeof (UInt16)
+ || type == typeof (Int32)
+ || type == typeof (UInt32)
+ || type == typeof (Int64)
+ || type == typeof (UInt64)
+ || type == typeof (Single)
+ || type == typeof (Double)
+ || type == typeof (Decimal));
+ }
+
+ internal static bool IsNumber (object value)
+ {
+ return (
+ value is Int16
+ || value is UInt16
+ || value is Int32
+ || value is UInt32
+ || value is Int64
+ || value is UInt64
+ || value is Single
+ || value is Double
+ || value is Decimal);
+ }
+
+ internal static object CreateInstance (Type cl)
+ {
+ try {
+ return System.Activator.CreateInstance (cl);
+ }
+ catch {
+ ;
+ }
+ return null;
+ }
+
+ internal static object GetCustomAttribute (Type type, Type attribute)
+ {
+ object [] attributes = type.GetCustomAttributes (attribute, true);
+ if (attributes.Length < 1)
+ return null;
+ return attributes [0];
+ }
+
+ internal static object GetCustomAttribute (Type type, MemberInfo mi)
+ {
+ object attribute = null;
+ object [] attributes = mi.GetCustomAttributes (type, true);
+ if (attributes.Length > 0)
+ attribute = attributes [0];
+ return attribute;
+ }
+
+ internal static object GetCustomAttribute (Type type, ParameterInfo pi)
+ {
+ object [] attributes = pi.GetCustomAttributes (type, true);
+ if (attributes.Length < 1)
+ return null;
+ return attributes [0];
+ }
+
+ internal static Type [] GetParameterTypes (ParameterInfo [] parameters)
+ {
+ Type [] types = new Type [parameters.Length];
+ for (int i = 0; i < types.Length; i++) {
+ types [i] = parameters [i].ParameterType;
+ }
+ return types;
+ }
+
+ }
+
+}
diff --git a/Code/EcmaScript.NET/Helpers/StackOverflowVerifier.cs b/src/EcmaScript.NET/Helpers/StackOverflowVerifier.cs
similarity index 95%
rename from Code/EcmaScript.NET/Helpers/StackOverflowVerifier.cs
rename to src/EcmaScript.NET/Helpers/StackOverflowVerifier.cs
index 3ae9a6f..a28a48f 100644
--- a/Code/EcmaScript.NET/Helpers/StackOverflowVerifier.cs
+++ b/src/EcmaScript.NET/Helpers/StackOverflowVerifier.cs
@@ -1,39 +1,39 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace EcmaScript.NET.Helpers
-{
-
- public class StackOverflowVerifier : IDisposable
- {
-
- [ThreadStatic]
- private static long m_Counter = long.MinValue;
-
- private int m_MaxStackSize = 0;
-
- public StackOverflowVerifier (int maxStackSize)
- {
- m_MaxStackSize = maxStackSize;
-
- ChangeStackDepth (+1);
- }
-
- public void Dispose ()
- {
- ChangeStackDepth (-1);
- }
-
- void ChangeStackDepth (int offset)
- {
- if (m_Counter == long.MinValue)
- m_Counter = 0;
- m_Counter += offset;
- if (m_Counter > m_MaxStackSize)
- throw new StackOverflowVerifierException ();
- }
-
- }
-
-}
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace EcmaScript.NET.Helpers
+{
+
+ public class StackOverflowVerifier : IDisposable
+ {
+
+ [ThreadStatic]
+ private static long m_Counter = long.MinValue;
+
+ private int m_MaxStackSize = 0;
+
+ public StackOverflowVerifier (int maxStackSize)
+ {
+ m_MaxStackSize = maxStackSize;
+
+ ChangeStackDepth (+1);
+ }
+
+ public void Dispose ()
+ {
+ ChangeStackDepth (-1);
+ }
+
+ void ChangeStackDepth (int offset)
+ {
+ if (m_Counter == long.MinValue)
+ m_Counter = 0;
+ m_Counter += offset;
+ if (m_Counter > m_MaxStackSize)
+ throw new StackOverflowVerifierException ();
+ }
+
+ }
+
+}
diff --git a/Code/EcmaScript.NET/Helpers/StackOverflowVerifierException.cs b/src/EcmaScript.NET/Helpers/StackOverflowVerifierException.cs
similarity index 64%
rename from Code/EcmaScript.NET/Helpers/StackOverflowVerifierException.cs
rename to src/EcmaScript.NET/Helpers/StackOverflowVerifierException.cs
index e7fdbe6..adc29ec 100644
--- a/Code/EcmaScript.NET/Helpers/StackOverflowVerifierException.cs
+++ b/src/EcmaScript.NET/Helpers/StackOverflowVerifierException.cs
@@ -1,10 +1,10 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace EcmaScript.NET.Helpers
-{
- class StackOverflowVerifierException : ApplicationException
- {
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace EcmaScript.NET.Helpers
+{
+ class StackOverflowVerifierException : Exception
+ {
+ }
+}
diff --git a/Code/EcmaScript.NET/ICallable.cs b/src/EcmaScript.NET/ICallable.cs
similarity index 97%
rename from Code/EcmaScript.NET/ICallable.cs
rename to src/EcmaScript.NET/ICallable.cs
index ce66138..81ae0c8 100644
--- a/Code/EcmaScript.NET/ICallable.cs
+++ b/src/EcmaScript.NET/ICallable.cs
@@ -1,39 +1,39 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-namespace EcmaScript.NET
-{
-
- /// Generic notion of callable object that can execute some script-related code
- /// upon request with specified values for script scope and this objects.
- ///
- public interface ICallable
- {
- /// Perform the call.
- ///
- ///
- /// the current Context for this thread
- ///
- /// the scope to use to resolve properties.
- ///
- /// the JavaScript this object
- ///
- /// the array of arguments
- ///
- /// the result of the call
- ///
- object Call (Context cx, IScriptable scope, IScriptable thisObj, object [] args);
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+namespace EcmaScript.NET
+{
+
+ /// Generic notion of callable object that can execute some script-related code
+ /// upon request with specified values for script scope and this objects.
+ ///
+ public interface ICallable
+ {
+ /// Perform the call.
+ ///
+ ///
+ /// the current Context for this thread
+ ///
+ /// the scope to use to resolve properties.
+ ///
+ /// the JavaScript this object
+ ///
+ /// the array of arguments
+ ///
+ /// the result of the call
+ ///
+ object Call (Context cx, IScriptable scope, IScriptable thisObj, object [] args);
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/IFunction.cs b/src/EcmaScript.NET/IFunction.cs
similarity index 97%
rename from Code/EcmaScript.NET/IFunction.cs
rename to src/EcmaScript.NET/IFunction.cs
index 6060edb..bf14607 100644
--- a/Code/EcmaScript.NET/IFunction.cs
+++ b/src/EcmaScript.NET/IFunction.cs
@@ -1,44 +1,44 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-namespace EcmaScript.NET
-{
-
- /// This is interface that all functions in JavaScript must implement.
- /// The interface provides for calling functions and constructors.
- ///
- ///
- public interface IFunction : IScriptable, ICallable
- {
-
- /// Call the function as a constructor.
- ///
- /// This method is invoked by the runtime in order to satisfy a use
- /// of the JavaScript new operator. This method is
- /// expected to create a new object and return it.
- ///
- ///
- /// the current Context for this thread
- ///
- /// an enclosing scope of the caller except
- /// when the function is called from a closure.
- ///
- /// the array of arguments
- ///
- /// the allocated object
- ///
- IScriptable Construct (Context cx, IScriptable scope, object [] args);
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+namespace EcmaScript.NET
+{
+
+ /// This is interface that all functions in JavaScript must implement.
+ /// The interface provides for calling functions and constructors.
+ ///
+ ///
+ public interface IFunction : IScriptable, ICallable
+ {
+
+ /// Call the function as a constructor.
+ ///
+ /// This method is invoked by the runtime in order to satisfy a use
+ /// of the JavaScript new operator. This method is
+ /// expected to create a new object and return it.
+ ///
+ ///
+ /// the current Context for this thread
+ ///
+ /// an enclosing scope of the caller except
+ /// when the function is called from a closure.
+ ///
+ /// the array of arguments
+ ///
+ /// the allocated object
+ ///
+ IScriptable Construct (Context cx, IScriptable scope, object [] args);
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/IIdEnumerable.cs b/src/EcmaScript.NET/IIdEnumerable.cs
similarity index 96%
rename from Code/EcmaScript.NET/IIdEnumerable.cs
rename to src/EcmaScript.NET/IIdEnumerable.cs
index a841d2a..7261c9b 100644
--- a/Code/EcmaScript.NET/IIdEnumerable.cs
+++ b/src/EcmaScript.NET/IIdEnumerable.cs
@@ -1,27 +1,27 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-using System;
-
-namespace EcmaScript.NET
-{
-
- ///
- /// Summary description for IdEnumerable.
- ///
- internal interface IIdEnumerable
- {
-
- IdEnumeration GetEnumeration (Context cx, bool enumValues);
-
- }
-}
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+using System;
+
+namespace EcmaScript.NET
+{
+
+ ///
+ /// Summary description for IdEnumerable.
+ ///
+ internal interface IIdEnumerable
+ {
+
+ IdEnumeration GetEnumeration (Context cx, bool enumValues);
+
+ }
+}
diff --git a/Code/EcmaScript.NET/IIdFunctionCall.cs b/src/EcmaScript.NET/IIdFunctionCall.cs
similarity index 97%
rename from Code/EcmaScript.NET/IIdFunctionCall.cs
rename to src/EcmaScript.NET/IIdFunctionCall.cs
index ff07c09..93736f9 100644
--- a/Code/EcmaScript.NET/IIdFunctionCall.cs
+++ b/src/EcmaScript.NET/IIdFunctionCall.cs
@@ -1,34 +1,34 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-namespace EcmaScript.NET
-{
-
- ///
- /// Master for id-based functions that knows their properties and how to
- /// execute them.
- ///
- public interface IIdFunctionCall
- {
-
- ///
- /// 'thisObj' will be null if invoked as constructor, in which case
- /// instance of Scriptable should be returned
- ///
- object ExecIdCall (IdFunctionObject f, Context cx, IScriptable scope, IScriptable thisObj, object [] args);
-
- }
-
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+namespace EcmaScript.NET
+{
+
+ ///
+ /// Master for id-based functions that knows their properties and how to
+ /// execute them.
+ ///
+ public interface IIdFunctionCall
+ {
+
+ ///
+ /// 'thisObj' will be null if invoked as constructor, in which case
+ /// instance of Scriptable should be returned
+ ///
+ object ExecIdCall (IdFunctionObject f, Context cx, IScriptable scope, IScriptable thisObj, object [] args);
+
+ }
+
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/IRef.cs b/src/EcmaScript.NET/IRef.cs
similarity index 96%
rename from Code/EcmaScript.NET/IRef.cs
rename to src/EcmaScript.NET/IRef.cs
index 3729177..36f0510 100644
--- a/Code/EcmaScript.NET/IRef.cs
+++ b/src/EcmaScript.NET/IRef.cs
@@ -1,34 +1,34 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-namespace EcmaScript.NET
-{
-
- /// Generic notion of reference object that know how to query/modify the
- /// target objects based on some property/index.
- ///
-
- public interface IRef
- {
- bool Has (Context cx);
-
- object Get (Context cx);
-
- object Set (Context cx, object value);
-
- bool Delete (Context cx);
-
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+namespace EcmaScript.NET
+{
+
+ /// Generic notion of reference object that know how to query/modify the
+ /// target objects based on some property/index.
+ ///
+
+ public interface IRef
+ {
+ bool Has (Context cx);
+
+ object Get (Context cx);
+
+ object Set (Context cx, object value);
+
+ bool Delete (Context cx);
+
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/IRefCallable.cs b/src/EcmaScript.NET/IRefCallable.cs
similarity index 97%
rename from Code/EcmaScript.NET/IRefCallable.cs
rename to src/EcmaScript.NET/IRefCallable.cs
index 7300ca0..2e676e1 100644
--- a/Code/EcmaScript.NET/IRefCallable.cs
+++ b/src/EcmaScript.NET/IRefCallable.cs
@@ -1,39 +1,39 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-namespace EcmaScript.NET
-{
-
- ///
- /// Object that can allows assignments to the result of function calls.
- ///
- public interface IRefCallable : ICallable
- {
- /// Perform function call in reference context.
- /// The args array reference should not be stored in any object that is
- /// can be GC-reachable after this method returns. If this is necessary,
- /// for example, to implement {@link Ref} methods, then store args.clone(),
- /// not args array itself.
- ///
- ///
- /// the current Context for this thread
- ///
- /// the JavaScript this object
- ///
- /// the array of arguments
- ///
- IRef RefCall (Context cx, IScriptable thisObj, object [] args);
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+namespace EcmaScript.NET
+{
+
+ ///
+ /// Object that can allows assignments to the result of function calls.
+ ///
+ public interface IRefCallable : ICallable
+ {
+ /// Perform function call in reference context.
+ /// The args array reference should not be stored in any object that is
+ /// can be GC-reachable after this method returns. If this is necessary,
+ /// for example, to implement {@link Ref} methods, then store args.clone(),
+ /// not args array itself.
+ ///
+ ///
+ /// the current Context for this thread
+ ///
+ /// the JavaScript this object
+ ///
+ /// the array of arguments
+ ///
+ IRef RefCall (Context cx, IScriptable thisObj, object [] args);
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/IScript.cs b/src/EcmaScript.NET/IScript.cs
similarity index 97%
rename from Code/EcmaScript.NET/IScript.cs
rename to src/EcmaScript.NET/IScript.cs
index bab0195..124b23c 100644
--- a/Code/EcmaScript.NET/IScript.cs
+++ b/src/EcmaScript.NET/IScript.cs
@@ -1,47 +1,47 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-namespace EcmaScript.NET
-{
-
- /// All compiled scripts implement this interface.
- ///
- /// This class encapsulates script execution relative to an
- /// object scope.
- ///
- public interface IScript
- {
-
- /// Execute the script.
- ///
- /// The script is executed in a particular runtime Context, which
- /// must be associated with the current thread.
- /// The script is executed relative to a scope--definitions and
- /// uses of global top-level variables and functions will access
- /// properties of the scope object. For compliant ECMA
- /// programs, the scope must be an object that has been initialized
- /// as a global object using Context.initStandardObjects.
- ///
- ///
- ///
- /// the Context associated with the current thread
- ///
- /// the scope to execute relative to
- ///
- /// the result of executing the script
- ///
- object Exec (Context cx, IScriptable scope);
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+namespace EcmaScript.NET
+{
+
+ /// All compiled scripts implement this interface.
+ ///
+ /// This class encapsulates script execution relative to an
+ /// object scope.
+ ///
+ public interface IScript
+ {
+
+ /// Execute the script.
+ ///
+ /// The script is executed in a particular runtime Context, which
+ /// must be associated with the current thread.
+ /// The script is executed relative to a scope--definitions and
+ /// uses of global top-level variables and functions will access
+ /// properties of the scope object. For compliant ECMA
+ /// programs, the scope must be an object that has been initialized
+ /// as a global object using Context.initStandardObjects.
+ ///
+ ///
+ ///
+ /// the Context associated with the current thread
+ ///
+ /// the scope to execute relative to
+ ///
+ /// the result of executing the script
+ ///
+ object Exec (Context cx, IScriptable scope);
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/IScriptable.cs b/src/EcmaScript.NET/IScriptable.cs
similarity index 97%
rename from Code/EcmaScript.NET/IScriptable.cs
rename to src/EcmaScript.NET/IScriptable.cs
index 5ec92d8..5523082 100644
--- a/Code/EcmaScript.NET/IScriptable.cs
+++ b/src/EcmaScript.NET/IScriptable.cs
@@ -1,306 +1,306 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-// API class
-using System;
-
-namespace EcmaScript.NET
-{
-
- ///
- /// This is interface that all objects in JavaScript must implement.
- /// The interface provides for the management of properties and for
- /// performing conversions.
- ///
- /// Host system implementors may find it easier to extend the ScriptableObject
- /// class rather than implementing Scriptable when writing host objects.
- ///
- /// There are many static methods defined in ScriptableObject that perform
- /// the multiple calls to the Scriptable interface needed in order to
- /// manipulate properties in prototype chains.
- ///
- ///
- ///
- public interface IScriptable
- {
-
- /// Get the name of the set of objects implemented by this Java class.
- /// This corresponds to the [[Class]] operation in ECMA and is used
- /// by Object.prototype.toString() in ECMA.
- /// See ECMA 8.6.2 and 15.2.4.2.
- ///
- string ClassName
- {
- get;
-
- }
-
- /// Get the parent scope of the object.
- /// the parent scope
- ///
- /// Set the parent scope of the object.
- /// the parent scope to set
- ///
- IScriptable ParentScope
- {
- get;
- set;
- }
-
- /// Get a named property from the object.
- ///
- /// Looks property up in this object and returns the associated value
- /// if found. Returns NOT_FOUND if not found.
- /// Note that this method is not expected to traverse the prototype
- /// chain. This is different from the ECMA [[Get]] operation.
- ///
- /// Depending on the property selector, the runtime will call
- /// this method or the form of get that takes an
- /// integer:
- ///
- /// | JavaScript code | Java code |
- /// | a.b | a.get("b", a) |
- /// | a["foo"] | a.get("foo", a) |
- /// | a[3] | a.get(3, a) |
- /// | a["3"] | a.get(3, a) |
- /// | a[3.0] | a.get(3, a) |
- /// | a["3.0"] | a.get("3.0", a) |
- /// | a[1.1] | a.get("1.1", a) |
- /// | a[-4] | a.get(-4, a) |
- ///
- ///
- /// The values that may be returned are limited to the following:
- ///
- /// - java.lang.Boolean objects
- /// - java.lang.String objects
- /// - java.lang.Number objects
- /// - EcmaScript.NET.Scriptable objects
- /// - null
- /// - The value returned by Context.getUndefinedValue()
- /// - NOT_FOUND
- ///
- ///
- /// the name of the property
- ///
- /// the object in which the lookup began
- ///
- /// the value of the property (may be null), or NOT_FOUND
- ///
- object Get (string name, IScriptable start);
-
- /// Get a property from the object selected by an integral index.
- ///
- /// Identical to get(String, Scriptable) except that
- /// an integral index is used to select the property.
- ///
- ///
- /// the numeric index for the property
- ///
- /// the object in which the lookup began
- ///
- /// the value of the property (may be null), or NOT_FOUND
- ///
- object Get (int index, IScriptable start);
-
- /// Indicates whether or not a named property is defined in an object.
- ///
- /// Does not traverse the prototype chain.
- ///
- /// The property is specified by a String name
- /// as defined for the get method.
- ///
- ///
- /// the name of the property
- ///
- /// the object in which the lookup began
- ///
- /// true if and only if the named property is found in the object
- ///
- bool Has (string name, IScriptable start);
-
- /// Indicates whether or not an indexed property is defined in an object.
- ///
- /// Does not traverse the prototype chain.
- ///
- /// The property is specified by an integral index
- /// as defined for the get method.
- ///
- ///
- /// the numeric index for the property
- ///
- /// the object in which the lookup began
- ///
- /// true if and only if the indexed property is found in the object
- ///
- bool Has (int index, IScriptable start);
-
- /// Sets a named property in this object.
- ///
- /// The property is specified by a string name
- /// as defined for get.
- ///
- /// The possible values that may be passed in are as defined for
- /// get. A class that implements this method may choose
- /// to ignore calls to set certain properties, in which case those
- /// properties are effectively read-only.
- /// For properties defined in a prototype chain,
- /// use putProperty in ScriptableObject.
- /// Note that if a property a is defined in the prototype p
- /// of an object o, then evaluating o.a = 23 will cause
- /// set to be called on the prototype p with
- /// o as the start parameter.
- /// To preserve JavaScript semantics, it is the Scriptable
- /// object's responsibility to modify o.
- /// This design allows properties to be defined in prototypes and implemented
- /// in terms of getters and setters of Java values without consuming slots
- /// in each instance.
- ///
- /// The values that may be set are limited to the following:
- ///
- /// - java.lang.Boolean objects
- /// - java.lang.String objects
- /// - java.lang.Number objects
- /// - EcmaScript.NET.Scriptable objects
- /// - null
- /// - The value returned by Context.getUndefinedValue()
- ///
- /// Arbitrary Java objects may be wrapped in a Scriptable by first calling
- /// Context.toObject. This allows the property of a JavaScript
- /// object to contain an arbitrary Java object as a value.
- /// Note that has will be called by the runtime first before
- /// set is called to determine in which object the
- /// property is defined.
- /// Note that this method is not expected to traverse the prototype chain,
- /// which is different from the ECMA [[Put]] operation.
- ///
- /// the name of the property
- ///
- /// the object whose property is being set
- ///
- /// value to set the property to
- ///
- object Put (string name, IScriptable start, object value);
-
- /// Sets an indexed property in this object.
- ///
- /// The property is specified by an integral index
- /// as defined for get.
- ///
- /// Identical to put(String, Scriptable, Object) except that
- /// an integral index is used to select the property.
- ///
- ///
- /// the numeric index for the property
- ///
- /// the object whose property is being set
- ///
- /// value to set the property to
- ///
- object Put (int index, IScriptable start, object value);
-
- /// Removes a property from this object.
- /// This operation corresponds to the ECMA [[Delete]] except that
- /// the no result is returned. The runtime will guarantee that this
- /// method is called only if the property exists. After this method
- /// is called, the runtime will call Scriptable.has to see if the
- /// property has been removed in order to determine the boolean
- /// result of the delete operator as defined by ECMA 11.4.1.
- ///
- /// A property can be made permanent by ignoring calls to remove
- /// it.
- /// The property is specified by a String name
- /// as defined for get.
- ///
- /// To delete properties defined in a prototype chain,
- /// see deleteProperty in ScriptableObject.
- ///
- /// the identifier for the property
- ///
- void Delete (string name);
-
- /// Removes a property from this object.
- ///
- /// The property is specified by an integral index
- /// as defined for get.
- ///
- /// To delete properties defined in a prototype chain,
- /// see deleteProperty in ScriptableObject.
- ///
- /// Identical to delete(String) except that
- /// an integral index is used to select the property.
- ///
- ///
- /// the numeric index for the property
- ///
- void Delete (int index);
-
- /// Get the prototype of the object.
- /// the prototype
- ///
- IScriptable GetPrototype ();
-
- /// Set the prototype of the object.
- /// the prototype to set
- ///
- void SetPrototype (IScriptable prototype);
-
- /// Get an array of property ids.
- ///
- /// Not all property ids need be returned. Those properties
- /// whose ids are not returned are considered non-enumerable.
- ///
- ///
- /// an array of Objects. Each entry in the array is either
- /// a java.lang.String or a java.lang.Number
- ///
- object [] GetIds ();
-
- /// Get the default value of the object with a given hint.
- /// The hints are String.class for type String, Number.class for type
- /// Number, Scriptable.class for type Object, and Boolean.class for
- /// type Boolean.
- ///
- /// A hint of null means "no hint".
- ///
- /// See ECMA 8.6.2.6.
- ///
- ///
- /// the type hint
- ///
- /// the default value
- ///
- object GetDefaultValue (Type hint);
-
- /// The instanceof operator.
- ///
- ///
- /// The JavaScript code "lhs instanceof rhs" causes rhs.hasInstance(lhs) to
- /// be called.
- ///
- ///
- /// The return value is implementation dependent so that embedded host objects can
- /// return an appropriate value. See the JS 1.3 language documentation for more
- /// detail.
- ///
- ///
This operator corresponds to the proposed EMCA [[HasInstance]] operator.
- ///
- ///
- /// The value that appeared on the LHS of the instanceof
- /// operator
- ///
- ///
- /// an implementation dependent value
- ///
- bool HasInstance (IScriptable instance);
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+// API class
+using System;
+
+namespace EcmaScript.NET
+{
+
+ ///
+ /// This is interface that all objects in JavaScript must implement.
+ /// The interface provides for the management of properties and for
+ /// performing conversions.
+ ///
+ /// Host system implementors may find it easier to extend the ScriptableObject
+ /// class rather than implementing Scriptable when writing host objects.
+ ///
+ /// There are many static methods defined in ScriptableObject that perform
+ /// the multiple calls to the Scriptable interface needed in order to
+ /// manipulate properties in prototype chains.
+ ///
+ ///
+ ///
+ public interface IScriptable
+ {
+
+ /// Get the name of the set of objects implemented by this Java class.
+ /// This corresponds to the [[Class]] operation in ECMA and is used
+ /// by Object.prototype.toString() in ECMA.
+ /// See ECMA 8.6.2 and 15.2.4.2.
+ ///
+ string ClassName
+ {
+ get;
+
+ }
+
+ /// Get the parent scope of the object.
+ /// the parent scope
+ ///
+ /// Set the parent scope of the object.
+ /// the parent scope to set
+ ///
+ IScriptable ParentScope
+ {
+ get;
+ set;
+ }
+
+ /// Get a named property from the object.
+ ///
+ /// Looks property up in this object and returns the associated value
+ /// if found. Returns NOT_FOUND if not found.
+ /// Note that this method is not expected to traverse the prototype
+ /// chain. This is different from the ECMA [[Get]] operation.
+ ///
+ /// Depending on the property selector, the runtime will call
+ /// this method or the form of get that takes an
+ /// integer:
+ ///
+ /// | JavaScript code | Java code |
+ /// | a.b | a.get("b", a) |
+ /// | a["foo"] | a.get("foo", a) |
+ /// | a[3] | a.get(3, a) |
+ /// | a["3"] | a.get(3, a) |
+ /// | a[3.0] | a.get(3, a) |
+ /// | a["3.0"] | a.get("3.0", a) |
+ /// | a[1.1] | a.get("1.1", a) |
+ /// | a[-4] | a.get(-4, a) |
+ ///
+ ///
+ /// The values that may be returned are limited to the following:
+ ///
+ /// - java.lang.Boolean objects
+ /// - java.lang.String objects
+ /// - java.lang.Number objects
+ /// - EcmaScript.NET.Scriptable objects
+ /// - null
+ /// - The value returned by Context.getUndefinedValue()
+ /// - NOT_FOUND
+ ///
+ ///
+ /// the name of the property
+ ///
+ /// the object in which the lookup began
+ ///
+ /// the value of the property (may be null), or NOT_FOUND
+ ///
+ object Get (string name, IScriptable start);
+
+ /// Get a property from the object selected by an integral index.
+ ///
+ /// Identical to get(String, Scriptable) except that
+ /// an integral index is used to select the property.
+ ///
+ ///
+ /// the numeric index for the property
+ ///
+ /// the object in which the lookup began
+ ///
+ /// the value of the property (may be null), or NOT_FOUND
+ ///
+ object Get (int index, IScriptable start);
+
+ /// Indicates whether or not a named property is defined in an object.
+ ///
+ /// Does not traverse the prototype chain.
+ ///
+ /// The property is specified by a String name
+ /// as defined for the get method.
+ ///
+ ///
+ /// the name of the property
+ ///
+ /// the object in which the lookup began
+ ///
+ /// true if and only if the named property is found in the object
+ ///
+ bool Has (string name, IScriptable start);
+
+ /// Indicates whether or not an indexed property is defined in an object.
+ ///
+ /// Does not traverse the prototype chain.
+ ///
+ /// The property is specified by an integral index
+ /// as defined for the get method.
+ ///
+ ///
+ /// the numeric index for the property
+ ///
+ /// the object in which the lookup began
+ ///
+ /// true if and only if the indexed property is found in the object
+ ///
+ bool Has (int index, IScriptable start);
+
+ /// Sets a named property in this object.
+ ///
+ /// The property is specified by a string name
+ /// as defined for get.
+ ///
+ /// The possible values that may be passed in are as defined for
+ /// get. A class that implements this method may choose
+ /// to ignore calls to set certain properties, in which case those
+ /// properties are effectively read-only.
+ /// For properties defined in a prototype chain,
+ /// use putProperty in ScriptableObject.
+ /// Note that if a property a is defined in the prototype p
+ /// of an object o, then evaluating o.a = 23 will cause
+ /// set to be called on the prototype p with
+ /// o as the start parameter.
+ /// To preserve JavaScript semantics, it is the Scriptable
+ /// object's responsibility to modify o.
+ /// This design allows properties to be defined in prototypes and implemented
+ /// in terms of getters and setters of Java values without consuming slots
+ /// in each instance.
+ ///
+ /// The values that may be set are limited to the following:
+ ///
+ /// - java.lang.Boolean objects
+ /// - java.lang.String objects
+ /// - java.lang.Number objects
+ /// - EcmaScript.NET.Scriptable objects
+ /// - null
+ /// - The value returned by Context.getUndefinedValue()
+ ///
+ /// Arbitrary Java objects may be wrapped in a Scriptable by first calling
+ /// Context.toObject. This allows the property of a JavaScript
+ /// object to contain an arbitrary Java object as a value.
+ /// Note that has will be called by the runtime first before
+ /// set is called to determine in which object the
+ /// property is defined.
+ /// Note that this method is not expected to traverse the prototype chain,
+ /// which is different from the ECMA [[Put]] operation.
+ ///
+ /// the name of the property
+ ///
+ /// the object whose property is being set
+ ///
+ /// value to set the property to
+ ///
+ object Put (string name, IScriptable start, object value);
+
+ /// Sets an indexed property in this object.
+ ///
+ /// The property is specified by an integral index
+ /// as defined for get.
+ ///
+ /// Identical to put(String, Scriptable, Object) except that
+ /// an integral index is used to select the property.
+ ///
+ ///
+ /// the numeric index for the property
+ ///
+ /// the object whose property is being set
+ ///
+ /// value to set the property to
+ ///
+ object Put (int index, IScriptable start, object value);
+
+ /// Removes a property from this object.
+ /// This operation corresponds to the ECMA [[Delete]] except that
+ /// the no result is returned. The runtime will guarantee that this
+ /// method is called only if the property exists. After this method
+ /// is called, the runtime will call Scriptable.has to see if the
+ /// property has been removed in order to determine the boolean
+ /// result of the delete operator as defined by ECMA 11.4.1.
+ ///
+ /// A property can be made permanent by ignoring calls to remove
+ /// it.
+ /// The property is specified by a String name
+ /// as defined for get.
+ ///
+ /// To delete properties defined in a prototype chain,
+ /// see deleteProperty in ScriptableObject.
+ ///
+ /// the identifier for the property
+ ///
+ void Delete (string name);
+
+ /// Removes a property from this object.
+ ///
+ /// The property is specified by an integral index
+ /// as defined for get.
+ ///
+ /// To delete properties defined in a prototype chain,
+ /// see deleteProperty in ScriptableObject.
+ ///
+ /// Identical to delete(String) except that
+ /// an integral index is used to select the property.
+ ///
+ ///
+ /// the numeric index for the property
+ ///
+ void Delete (int index);
+
+ /// Get the prototype of the object.
+ /// the prototype
+ ///
+ IScriptable GetPrototype ();
+
+ /// Set the prototype of the object.
+ /// the prototype to set
+ ///
+ void SetPrototype (IScriptable prototype);
+
+ /// Get an array of property ids.
+ ///
+ /// Not all property ids need be returned. Those properties
+ /// whose ids are not returned are considered non-enumerable.
+ ///
+ ///
+ /// an array of Objects. Each entry in the array is either
+ /// a java.lang.String or a java.lang.Number
+ ///
+ object [] GetIds ();
+
+ /// Get the default value of the object with a given hint.
+ /// The hints are String.class for type String, Number.class for type
+ /// Number, Scriptable.class for type Object, and Boolean.class for
+ /// type Boolean.
+ ///
+ /// A hint of null means "no hint".
+ ///
+ /// See ECMA 8.6.2.6.
+ ///
+ ///
+ /// the type hint
+ ///
+ /// the default value
+ ///
+ object GetDefaultValue (Type hint);
+
+ /// The instanceof operator.
+ ///
+ ///
+ /// The JavaScript code "lhs instanceof rhs" causes rhs.hasInstance(lhs) to
+ /// be called.
+ ///
+ ///
+ /// The return value is implementation dependent so that embedded host objects can
+ /// return an appropriate value. See the JS 1.3 language documentation for more
+ /// detail.
+ ///
+ ///
This operator corresponds to the proposed EMCA [[HasInstance]] operator.
+ ///
+ ///
+ /// The value that appeared on the LHS of the instanceof
+ /// operator
+ ///
+ ///
+ /// an implementation dependent value
+ ///
+ bool HasInstance (IScriptable instance);
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/IdEnumeration.cs b/src/EcmaScript.NET/IdEnumeration.cs
similarity index 96%
rename from Code/EcmaScript.NET/IdEnumeration.cs
rename to src/EcmaScript.NET/IdEnumeration.cs
index e80f5e2..2f069a4 100644
--- a/Code/EcmaScript.NET/IdEnumeration.cs
+++ b/src/EcmaScript.NET/IdEnumeration.cs
@@ -1,144 +1,144 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-using System;
-
-using EcmaScript.NET.Collections;
-
-namespace EcmaScript.NET
-{
-
- ///
- /// This is the enumeration needed by the for..in statement.
- ///
- /// See ECMA 12.6.3.
- ///
- /// IdEnumeration maintains a ObjToIntMap to make sure a given
- /// id is enumerated only once across multiple objects in a
- /// prototype chain.
- ///
- /// ECMA delete doesn't hide properties in the prototype,
- /// but js/ref does. This means that the js/ref for..in can
- /// avoid maintaining a hash table and instead perform lookups
- /// to see if a given property has already been enumerated.
- ///
- ///
- public class IdEnumeration
- {
-
- protected IdEnumeration ()
- {
- ;
- }
-
- public IdEnumeration (object value, Context cx, bool enumValues)
- {
- obj = ScriptConvert.ToObjectOrNull (cx, value);
- if (obj != null) {
- // null or undefined do not cause errors but rather lead to empty
- // "for in" loop
- this.enumValues = enumValues;
-
- // enumInit should read all initial ids before returning
- // or "for (a.i in a)" would wrongly enumerate i in a as well
- ChangeObject ();
- }
- }
-
- private IScriptable obj;
- private object [] ids;
- private int index;
- private ObjToIntMap used;
- private string currentId;
- private bool enumValues;
-
- public virtual bool MoveNext ()
- {
- // OPT this could be more efficient
- bool result;
- for (; ; ) {
- if (obj == null) {
- result = false;
- break;
- }
- if (index == ids.Length) {
- obj = obj.GetPrototype ();
- this.ChangeObject ();
- continue;
- }
- object id = ids [index++];
- if (used != null && used.has (id)) {
- continue;
- }
- if (id is string) {
- string strId = (string)id;
- if (!obj.Has (strId, obj))
- continue; // must have been deleted
- currentId = strId;
- }
- else {
- int intId = Convert.ToInt32 (id);
- if (!obj.Has (intId, obj))
- continue; // must have been deleted
- currentId = Convert.ToString (intId);
- }
- result = true;
- break;
- }
- return result;
- }
-
- public virtual object Current (Context cx)
- {
- if (!enumValues)
- return currentId;
-
- object result;
-
- string s = ScriptRuntime.ToStringIdOrIndex (cx, currentId);
- if (s == null) {
- int index = ScriptRuntime.lastIndexResult (cx);
- result = obj.Get (index, obj);
- }
- else {
- result = obj.Get (s, obj);
- }
-
- return result;
- }
-
- private void ChangeObject ()
- {
- object [] ids = null;
- while (obj != null) {
- ids = obj.GetIds ();
- if (ids.Length != 0) {
- break;
- }
- obj = obj.GetPrototype ();
- }
- if (obj != null && this.ids != null) {
- object [] previous = this.ids;
- int L = previous.Length;
- if (used == null) {
- used = new ObjToIntMap (L);
- }
- for (int i = 0; i != L; ++i) {
- used.intern (previous [i]);
- }
- }
- this.ids = ids;
- this.index = 0;
- }
-
- }
-}
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+using System;
+
+using EcmaScript.NET.Collections;
+
+namespace EcmaScript.NET
+{
+
+ ///
+ /// This is the enumeration needed by the for..in statement.
+ ///
+ /// See ECMA 12.6.3.
+ ///
+ /// IdEnumeration maintains a ObjToIntMap to make sure a given
+ /// id is enumerated only once across multiple objects in a
+ /// prototype chain.
+ ///
+ /// ECMA delete doesn't hide properties in the prototype,
+ /// but js/ref does. This means that the js/ref for..in can
+ /// avoid maintaining a hash table and instead perform lookups
+ /// to see if a given property has already been enumerated.
+ ///
+ ///
+ public class IdEnumeration
+ {
+
+ protected IdEnumeration ()
+ {
+ ;
+ }
+
+ public IdEnumeration (object value, Context cx, bool enumValues)
+ {
+ obj = ScriptConvert.ToObjectOrNull (cx, value);
+ if (obj != null) {
+ // null or undefined do not cause errors but rather lead to empty
+ // "for in" loop
+ this.enumValues = enumValues;
+
+ // enumInit should read all initial ids before returning
+ // or "for (a.i in a)" would wrongly enumerate i in a as well
+ ChangeObject ();
+ }
+ }
+
+ private IScriptable obj;
+ private object [] ids;
+ private int index;
+ private ObjToIntMap used;
+ private string currentId;
+ private bool enumValues;
+
+ public virtual bool MoveNext ()
+ {
+ // OPT this could be more efficient
+ bool result;
+ for (; ; ) {
+ if (obj == null) {
+ result = false;
+ break;
+ }
+ if (index == ids.Length) {
+ obj = obj.GetPrototype ();
+ this.ChangeObject ();
+ continue;
+ }
+ object id = ids [index++];
+ if (used != null && used.has (id)) {
+ continue;
+ }
+ if (id is string) {
+ string strId = (string)id;
+ if (!obj.Has (strId, obj))
+ continue; // must have been deleted
+ currentId = strId;
+ }
+ else {
+ int intId = Convert.ToInt32 (id);
+ if (!obj.Has (intId, obj))
+ continue; // must have been deleted
+ currentId = Convert.ToString (intId);
+ }
+ result = true;
+ break;
+ }
+ return result;
+ }
+
+ public virtual object Current (Context cx)
+ {
+ if (!enumValues)
+ return currentId;
+
+ object result;
+
+ string s = ScriptRuntime.ToStringIdOrIndex (cx, currentId);
+ if (s == null) {
+ int index = ScriptRuntime.lastIndexResult (cx);
+ result = obj.Get (index, obj);
+ }
+ else {
+ result = obj.Get (s, obj);
+ }
+
+ return result;
+ }
+
+ private void ChangeObject ()
+ {
+ object [] ids = null;
+ while (obj != null) {
+ ids = obj.GetIds ();
+ if (ids.Length != 0) {
+ break;
+ }
+ obj = obj.GetPrototype ();
+ }
+ if (obj != null && this.ids != null) {
+ object [] previous = this.ids;
+ int L = previous.Length;
+ if (used == null) {
+ used = new ObjToIntMap (L);
+ }
+ for (int i = 0; i != L; ++i) {
+ used.intern (previous [i]);
+ }
+ }
+ this.ids = ids;
+ this.index = 0;
+ }
+
+ }
+}
diff --git a/Code/EcmaScript.NET/IdFunctionObject.cs b/src/EcmaScript.NET/IdFunctionObject.cs
similarity index 94%
rename from Code/EcmaScript.NET/IdFunctionObject.cs
rename to src/EcmaScript.NET/IdFunctionObject.cs
index 96def15..ba33259 100644
--- a/Code/EcmaScript.NET/IdFunctionObject.cs
+++ b/src/EcmaScript.NET/IdFunctionObject.cs
@@ -1,196 +1,196 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-namespace EcmaScript.NET
-{
-
-
- public class IdFunctionObject : BaseFunction
- {
-
- public IdFunctionObject ()
- {
- ;
- }
-
- override public int Arity
- {
- get
- {
- return arity;
- }
-
- }
- override public int Length
- {
- get
- {
- return Arity;
- }
-
- }
- override public string FunctionName
- {
- get
- {
- return (functionName == null) ? "" : functionName;
- }
- }
-
- public IdFunctionObject (IIdFunctionCall idcall, object tag, int id, int arity)
- {
- if (arity < 0)
- throw new ArgumentException ();
-
- this.idcall = idcall;
- this.tag = tag;
- this.m_MethodId = id;
- this.arity = arity;
- if (arity < 0)
- throw new ArgumentException ();
- }
-
- public IdFunctionObject (IIdFunctionCall idcall, object tag, int id, string name, int arity, IScriptable scope)
- : base (scope, null)
- {
-
- if (arity < 0)
- throw new ArgumentException ();
- if (name == null)
- throw new ArgumentException ();
-
- this.idcall = idcall;
- this.tag = tag;
- this.m_MethodId = id;
- this.arity = arity;
- this.functionName = name;
- }
-
- public virtual void InitFunction (string name, IScriptable scope)
- {
- if (name == null)
- throw new ArgumentException ();
- if (scope == null)
- throw new ArgumentException ();
- this.functionName = name;
- ParentScope = scope;
- }
-
- public bool HasTag (object tag)
- {
- return this.tag == tag;
- }
-
- public int MethodId
- {
- get
- {
- return m_MethodId;
- }
- }
-
- public void MarkAsConstructor (IScriptable prototypeProperty)
- {
- useCallAsConstructor = true;
- ImmunePrototypeProperty = prototypeProperty;
- }
-
- public void AddAsProperty (IScriptable target)
- {
- AddAsProperty (target, ScriptableObject.DONTENUM);
- }
-
- public void AddAsProperty (IScriptable target, int attributes)
- {
- ScriptableObject.DefineProperty (target, functionName, this, attributes);
- }
-
- public virtual void ExportAsScopeProperty ()
- {
- AddAsProperty (ParentScope);
- }
-
- public virtual void ExportAsScopeProperty (int attributes)
- {
- AddAsProperty (ParentScope, attributes);
- }
-
- public override IScriptable GetPrototype ()
- {
- // Lazy initialization of prototype: for native functions this
- // may not be called at all
- IScriptable proto = base.GetPrototype ();
- if (proto == null) {
- proto = GetFunctionPrototype (ParentScope);
- SetPrototype (proto);
- }
- return proto;
- }
-
- public override object Call (Context cx, IScriptable scope, IScriptable thisObj, object [] args)
- {
- return idcall.ExecIdCall (this, cx, scope, thisObj, args);
- }
-
- public override IScriptable CreateObject (Context cx, IScriptable scope)
- {
- if (useCallAsConstructor) {
- return null;
- }
- // Throw error if not explicitly coded to be used as constructor,
- // to satisfy ECMAScript standard (see bugzilla 202019).
- // To follow current (2003-05-01) SpiderMonkey behavior, change it to:
- // return super.createObject(cx, scope);
- throw ScriptRuntime.TypeErrorById ("msg.not.ctor", functionName);
- }
-
- internal override string Decompile (int indent, int flags)
- {
- System.Text.StringBuilder sb = new System.Text.StringBuilder ();
- bool justbody = (0 != (flags & Decompiler.ONLY_BODY_FLAG));
- if (!justbody) {
- sb.Append ("function ");
- sb.Append (FunctionName);
- sb.Append ("() { ");
- }
- sb.Append ("[native code for ");
- if (idcall is IScriptable) {
- IScriptable sobj = (IScriptable)idcall;
- sb.Append (sobj.ClassName);
- sb.Append ('.');
- }
- sb.Append (FunctionName);
- sb.Append (", arity=");
- sb.Append (Arity);
- sb.Append (justbody ? "]\n" : "] }\n");
- return sb.ToString ();
- }
-
- public ApplicationException Unknown ()
- {
- // It is program error to call id-like methods for unknown function
- return new ApplicationException ("BAD FUNCTION ID=" + m_MethodId + " MASTER=" + idcall);
- }
-
- private IIdFunctionCall idcall;
- private object tag;
- private int m_MethodId;
- private int arity;
- private bool useCallAsConstructor;
- private string functionName;
-
-
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+namespace EcmaScript.NET
+{
+
+
+ public class IdFunctionObject : BaseFunction
+ {
+
+ public IdFunctionObject ()
+ {
+ ;
+ }
+
+ override public int Arity
+ {
+ get
+ {
+ return arity;
+ }
+
+ }
+ override public int Length
+ {
+ get
+ {
+ return Arity;
+ }
+
+ }
+ override public string FunctionName
+ {
+ get
+ {
+ return (functionName == null) ? "" : functionName;
+ }
+ }
+
+ public IdFunctionObject (IIdFunctionCall idcall, object tag, int id, int arity)
+ {
+ if (arity < 0)
+ throw new ArgumentException ();
+
+ this.idcall = idcall;
+ this.tag = tag;
+ this.m_MethodId = id;
+ this.arity = arity;
+ if (arity < 0)
+ throw new ArgumentException ();
+ }
+
+ public IdFunctionObject (IIdFunctionCall idcall, object tag, int id, string name, int arity, IScriptable scope)
+ : base (scope, null)
+ {
+
+ if (arity < 0)
+ throw new ArgumentException ();
+ if (name == null)
+ throw new ArgumentException ();
+
+ this.idcall = idcall;
+ this.tag = tag;
+ this.m_MethodId = id;
+ this.arity = arity;
+ this.functionName = name;
+ }
+
+ public virtual void InitFunction (string name, IScriptable scope)
+ {
+ if (name == null)
+ throw new ArgumentException ();
+ if (scope == null)
+ throw new ArgumentException ();
+ this.functionName = name;
+ ParentScope = scope;
+ }
+
+ public bool HasTag (object tag)
+ {
+ return this.tag == tag;
+ }
+
+ public int MethodId
+ {
+ get
+ {
+ return m_MethodId;
+ }
+ }
+
+ public void MarkAsConstructor (IScriptable prototypeProperty)
+ {
+ useCallAsConstructor = true;
+ ImmunePrototypeProperty = prototypeProperty;
+ }
+
+ public void AddAsProperty (IScriptable target)
+ {
+ AddAsProperty (target, ScriptableObject.DONTENUM);
+ }
+
+ public void AddAsProperty (IScriptable target, int attributes)
+ {
+ ScriptableObject.DefineProperty (target, functionName, this, attributes);
+ }
+
+ public virtual void ExportAsScopeProperty ()
+ {
+ AddAsProperty (ParentScope);
+ }
+
+ public virtual void ExportAsScopeProperty (int attributes)
+ {
+ AddAsProperty (ParentScope, attributes);
+ }
+
+ public override IScriptable GetPrototype ()
+ {
+ // Lazy initialization of prototype: for native functions this
+ // may not be called at all
+ IScriptable proto = base.GetPrototype ();
+ if (proto == null) {
+ proto = GetFunctionPrototype (ParentScope);
+ SetPrototype (proto);
+ }
+ return proto;
+ }
+
+ public override object Call (Context cx, IScriptable scope, IScriptable thisObj, object [] args)
+ {
+ return idcall.ExecIdCall (this, cx, scope, thisObj, args);
+ }
+
+ public override IScriptable CreateObject (Context cx, IScriptable scope)
+ {
+ if (useCallAsConstructor) {
+ return null;
+ }
+ // Throw error if not explicitly coded to be used as constructor,
+ // to satisfy ECMAScript standard (see bugzilla 202019).
+ // To follow current (2003-05-01) SpiderMonkey behavior, change it to:
+ // return super.createObject(cx, scope);
+ throw ScriptRuntime.TypeErrorById ("msg.not.ctor", functionName);
+ }
+
+ internal override string Decompile (int indent, int flags)
+ {
+ System.Text.StringBuilder sb = new System.Text.StringBuilder ();
+ bool justbody = (0 != (flags & Decompiler.ONLY_BODY_FLAG));
+ if (!justbody) {
+ sb.Append ("function ");
+ sb.Append (FunctionName);
+ sb.Append ("() { ");
+ }
+ sb.Append ("[native code for ");
+ if (idcall is IScriptable) {
+ IScriptable sobj = (IScriptable)idcall;
+ sb.Append (sobj.ClassName);
+ sb.Append ('.');
+ }
+ sb.Append (FunctionName);
+ sb.Append (", arity=");
+ sb.Append (Arity);
+ sb.Append (justbody ? "]\n" : "] }\n");
+ return sb.ToString ();
+ }
+
+ public Exception Unknown ()
+ {
+ // It is program error to call id-like methods for unknown function
+ return new Exception ("BAD FUNCTION ID=" + m_MethodId + " MASTER=" + idcall);
+ }
+
+ private IIdFunctionCall idcall;
+ private object tag;
+ private int m_MethodId;
+ private int arity;
+ private bool useCallAsConstructor;
+ private string functionName;
+
+
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/IdScriptableObject.cs b/src/EcmaScript.NET/IdScriptableObject.cs
similarity index 94%
rename from Code/EcmaScript.NET/IdScriptableObject.cs
rename to src/EcmaScript.NET/IdScriptableObject.cs
index c4b332d..7162271 100644
--- a/Code/EcmaScript.NET/IdScriptableObject.cs
+++ b/src/EcmaScript.NET/IdScriptableObject.cs
@@ -1,694 +1,694 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-using System.Runtime.InteropServices;
-
-namespace EcmaScript.NET
-{
-
- ///
- /// Base class for native object implementation that uses IdFunctionObject to export its methods to script via .prototype object.
- /// Any descendant should implement at least the following methods:
- /// findInstanceIdInfo
- /// getInstanceIdName
- /// execIdCall
- /// methodArity
- /// To define non-function properties, the descendant should override
- /// getInstanceIdValue
- /// setInstanceIdValue
- /// to get/set property value and provide its default attributes.
- /// To customize initializition of constructor and protype objects, descendant
- /// may override scopeInit or fillConstructorProperties methods.
- ///
- public abstract class IdScriptableObject : ScriptableObject, IIdFunctionCall
- {
-
- ///
- /// Get maximum id findInstanceIdInfo can generate.
- ///
- protected virtual internal int MaxInstanceId
- {
- get
- {
- return 0;
- }
- }
-
- private volatile PrototypeValues prototypeValues;
-
- private sealed class PrototypeValues
- {
-
- internal int MaxId
- {
- get
- {
- return maxId;
- }
-
- }
-
- private const int VALUE_SLOT = 0;
- private const int NAME_SLOT = 1;
- private const int SLOT_SPAN = 2;
-
- private IdScriptableObject obj;
- private int maxId;
- private volatile object [] valueArray;
- private volatile short [] attributeArray;
- private volatile int lastFoundId = 1;
-
- // The following helps to avoid creation of valueArray during runtime
- // initialization for common case of "constructor" property
- internal int constructorId;
- private IdFunctionObject constructor;
- private short constructorAttrs;
-
- internal PrototypeValues (IdScriptableObject obj, int maxId)
- {
- if (obj == null)
- throw new ArgumentNullException ("obj");
- if (maxId < 1)
- throw new ArgumentException ("maxId may not lower than 1");
- this.obj = obj;
- this.maxId = maxId;
- }
-
- internal void InitValue (int id, string name, object value, int attributes)
- {
- if (!(1 <= id && id <= maxId))
- throw new ArgumentException ();
- if (name == null)
- throw new ArgumentException ();
- if (value == UniqueTag.NotFound)
- throw new ArgumentException ();
- ScriptableObject.CheckValidAttributes (attributes);
- if (obj.FindPrototypeId (name) != id)
- throw new ArgumentException (name);
-
- if (id == constructorId) {
- if (!(value is IdFunctionObject)) {
- throw new ArgumentException ("consructor should be initialized with IdFunctionObject");
- }
- constructor = (IdFunctionObject)value;
- constructorAttrs = (short)attributes;
- return;
- }
-
- InitSlot (id, name, value, attributes);
- }
-
- private void InitSlot (int id, string name, object value, int attributes)
- {
- object [] array = valueArray;
- if (array == null)
- throw new ArgumentNullException ("array");
-
- if (value == null) {
- value = UniqueTag.NullValue;
- }
- int index = (id - 1) * SLOT_SPAN;
- lock (this) {
- object value2 = array [index + VALUE_SLOT];
- if (value2 == null) {
- array [index + VALUE_SLOT] = value;
- array [index + NAME_SLOT] = name;
- attributeArray [id - 1] = (short)attributes;
- }
- else {
- if (!name.Equals (array [index + NAME_SLOT]))
- throw new ApplicationException ();
- }
- }
- }
-
- internal IdFunctionObject createPrecachedConstructor ()
- {
- if (constructorId != 0)
- throw new ApplicationException ();
- constructorId = obj.FindPrototypeId ("constructor");
- if (constructorId == 0) {
- throw new ApplicationException ("No id for constructor property");
- }
- obj.InitPrototypeId (constructorId);
- if (constructor == null) {
- throw new ApplicationException (obj.GetType ().FullName + ".initPrototypeId() did not " + "initialize id=" + constructorId);
- }
- constructor.InitFunction (obj.ClassName, ScriptableObject.GetTopLevelScope (obj));
- constructor.MarkAsConstructor (obj);
- return constructor;
- }
-
- internal int FindId (string name)
- {
- object [] array = valueArray;
- if (array == null) {
- return obj.FindPrototypeId (name);
- }
- int id = lastFoundId;
- if ((object)name == array [(id - 1) * SLOT_SPAN + NAME_SLOT]) {
- return id;
- }
- id = obj.FindPrototypeId (name);
- if (id != 0) {
- int nameSlot = (id - 1) * SLOT_SPAN + NAME_SLOT;
- // Make cache to work!
- array [nameSlot] = name;
- lastFoundId = id;
- }
- return id;
- }
-
- internal bool Has (int id)
- {
- object [] array = valueArray;
- if (array == null) {
- // Not yet initialized, assume all exists
- return true;
- }
- int valueSlot = (id - 1) * SLOT_SPAN + VALUE_SLOT;
- object value = array [valueSlot];
- if (value == null) {
- // The particular entry has not been yet initialized
- return true;
- }
- return value != UniqueTag.NotFound;
- }
-
- internal object Get (int id)
- {
- object value = EnsureId (id);
- if (value == UniqueTag.NullValue) {
- value = null;
- }
- return value;
- }
-
- internal void Set (int id, IScriptable start, object value)
- {
- if (value == UniqueTag.NotFound)
- throw new ArgumentException ();
- EnsureId (id);
- int attr = attributeArray [id - 1];
- if ((attr & ScriptableObject.READONLY) == 0) {
- if (start == obj) {
- if (value == null) {
- value = UniqueTag.NullValue;
- }
- int valueSlot = (id - 1) * SLOT_SPAN + VALUE_SLOT;
- lock (this) {
- valueArray [valueSlot] = value;
- }
- }
- else {
- int nameSlot = (id - 1) * SLOT_SPAN + NAME_SLOT;
- string name = (string)valueArray [nameSlot];
- start.Put (name, start, value);
- }
- }
- }
-
- internal void Delete (int id)
- {
- EnsureId (id);
- int attr = attributeArray [id - 1];
- if ((attr & ScriptableObject.PERMANENT) == 0) {
- int valueSlot = (id - 1) * SLOT_SPAN + VALUE_SLOT;
- lock (this) {
- valueArray [valueSlot] = UniqueTag.NotFound;
- attributeArray [id - 1] = (short)(ScriptableObject.EMPTY);
- }
- }
- }
-
- internal int GetAttributes (int id)
- {
- EnsureId (id);
- return attributeArray [id - 1];
- }
-
- internal void SetAttributes (int id, int attributes)
- {
- ScriptableObject.CheckValidAttributes (attributes);
- EnsureId (id);
- lock (this) {
- attributeArray [id - 1] = (short)attributes;
- }
- }
-
- internal object [] GetNames (bool getAll, object [] extraEntries)
- {
- object [] names = null;
- int count = 0;
-
- for (int id = 1; id <= maxId; ++id) {
-
- object value = EnsureId (id);
- if (getAll || (attributeArray [id - 1] & ScriptableObject.DONTENUM) == 0) {
- if (value != UniqueTag.NotFound) {
- int nameSlot = (id - 1) * SLOT_SPAN + NAME_SLOT;
- string name = (string)valueArray [nameSlot];
- if (names == null) {
- names = new object [maxId];
- }
- names [count++] = name;
- }
- }
- }
- if (count == 0) {
- return extraEntries;
- }
- else if (extraEntries == null || extraEntries.Length == 0) {
- if (count != names.Length) {
- object [] tmp = new object [count];
- Array.Copy (names, 0, tmp, 0, count);
- names = tmp;
- }
- return names;
- }
- else {
- int extra = extraEntries.Length;
- object [] tmp = new object [extra + count];
- Array.Copy (extraEntries, 0, tmp, 0, extra);
- Array.Copy (names, 0, tmp, extra, count);
- return tmp;
- }
- }
-
- private object EnsureId (int id)
- {
- object [] array = valueArray;
- if (array == null) {
- lock (this) {
- array = valueArray;
- if (array == null) {
- array = new object [maxId * SLOT_SPAN];
- valueArray = array;
- attributeArray = new short [maxId];
- }
- }
- }
- int valueSlot = (id - 1) * SLOT_SPAN + VALUE_SLOT;
- object value = array [valueSlot];
-
- if (value == null) {
- if (id == constructorId) {
- InitSlot (constructorId, "constructor", constructor, constructorAttrs);
- constructor = null; // no need to refer it any longer
- }
- else {
- obj.InitPrototypeId (id);
- }
- value = array [valueSlot];
- if (value == null) {
- throw new ApplicationException (obj.GetType ().FullName + ".initPrototypeId(int id) " + "did not initialize id=" + id);
- }
- }
- return value;
- }
- }
-
- public IdScriptableObject ()
- {
- ;
- }
-
- public IdScriptableObject (IScriptable scope, IScriptable prototype)
- : base (scope, prototype)
- {
- ;
- }
-
- protected internal object DefaultGet (string name)
- {
- return base.Get (name, this);
- }
-
- protected internal void DefaultPut (string name, object value)
- {
- base.Put (name, this, value);
- }
-
- public override bool Has (string name, IScriptable start)
- {
- int info = FindInstanceIdInfo (name);
- if (info != 0) {
- int attr = (int)((uint)info >> 16);
- if ((attr & PERMANENT) != 0) {
- return true;
- }
- int id = (info & 0xFFFF);
- return UniqueTag.NotFound != GetInstanceIdValue (id);
- }
- if (prototypeValues != null) {
- int id = prototypeValues.FindId (name);
- if (id != 0) {
- return prototypeValues.Has (id);
- }
- }
- return base.Has (name, start);
- }
-
- public override object Get (string name, IScriptable start)
- {
- int info = FindInstanceIdInfo (name);
- if (info != 0) {
- int id = (info & 0xFFFF);
- return GetInstanceIdValue (id);
- }
- if (prototypeValues != null) {
- int id = prototypeValues.FindId (name);
- if (id != 0) {
- return prototypeValues.Get (id);
- }
- }
- return base.Get (name, start);
- }
-
- public override object Put (string name, IScriptable start, object value)
- {
- int info = FindInstanceIdInfo (name);
- if (info != 0) {
- if (start == this && Sealed) {
- throw Context.ReportRuntimeErrorById ("msg.modify.sealed", name);
- }
- int attr = (int)((uint)info >> 16);
- if ((attr & READONLY) == 0) {
- if (start == this) {
- int id = (info & 0xFFFF);
- SetInstanceIdValue (id, value);
- }
- else {
- return start.Put (name, start, value);
- }
- }
- return value;
- }
- if (prototypeValues != null) {
- int id = prototypeValues.FindId (name);
- if (id != 0) {
- if (start == this && Sealed) {
- throw Context.ReportRuntimeErrorById ("msg.modify.sealed", name);
- }
- prototypeValues.Set (id, start, value);
- return value;
- }
- }
- return base.Put (name, start, value);
- }
-
- public override void Delete (string name)
- {
- int info = FindInstanceIdInfo (name);
- if (info != 0) {
- // Let the super class to throw exceptions for sealed objects
- if (!Sealed) {
- int attr = (int)((uint)info >> 16);
- if ((attr & PERMANENT) == 0) {
- int id = (info & 0xFFFF);
- SetInstanceIdValue (id, UniqueTag.NotFound);
- }
- return;
- }
- }
- if (prototypeValues != null) {
- int id = prototypeValues.FindId (name);
- if (id != 0) {
- if (!Sealed) {
- prototypeValues.Delete (id);
- }
- return;
- }
- }
- base.Delete (name);
- }
-
- public override int GetAttributes (string name)
- {
- int info = FindInstanceIdInfo (name);
- if (info != 0) {
- int attr = (int)((uint)info >> 16);
- return attr;
- }
- if (prototypeValues != null) {
- int id = prototypeValues.FindId (name);
- if (id != 0) {
- return prototypeValues.GetAttributes (id);
- }
- }
- return base.GetAttributes (name);
- }
-
- public override void SetAttributes (string name, int attributes)
- {
- ScriptableObject.CheckValidAttributes (attributes);
- int info = FindInstanceIdInfo (name);
- if (info != 0) {
- int currentAttributes = (int)((uint)info >> 16);
- if (attributes != currentAttributes) {
- throw new ApplicationException ("Change of attributes for this id is not supported");
- }
- return;
- }
- if (prototypeValues != null) {
- int id = prototypeValues.FindId (name);
- if (id != 0) {
- prototypeValues.SetAttributes (id, attributes);
- return;
- }
- }
- base.SetAttributes (name, attributes);
- }
-
- internal override object [] GetIds (bool getAll)
- {
- object [] result = base.GetIds (getAll);
-
- if (prototypeValues != null) {
- result = prototypeValues.GetNames (getAll, result);
- }
-
- int maxInstanceId = MaxInstanceId;
- if (maxInstanceId != 0) {
- object [] ids = null;
- int count = 0;
-
- for (int id = maxInstanceId; id != 0; --id) {
- string name = GetInstanceIdName (id);
- int info = FindInstanceIdInfo (name);
- if (info != 0) {
- int attr = (int)((uint)info >> 16);
- if ((attr & PERMANENT) == 0) {
- if (UniqueTag.NotFound == GetInstanceIdValue (id)) {
- continue;
- }
- }
- if (getAll || (attr & DONTENUM) == 0) {
- if (count == 0) {
- // Need extra room for no more then [1..id] names
- ids = new object [id];
- }
- ids [count++] = name;
- }
- }
- }
- if (count != 0) {
- if (result.Length == 0 && ids.Length == count) {
- result = ids;
- }
- else {
- object [] tmp = new object [result.Length + count];
- Array.Copy (result, 0, tmp, 0, result.Length);
- Array.Copy (ids, 0, tmp, result.Length, count);
- result = tmp;
- }
- }
- }
- return result;
- }
-
- protected internal static int InstanceIdInfo (int attributes, int id)
- {
- return (attributes << 16) | id;
- }
-
- ///
- /// Map name to id of instance property.
- /// Should return 0 if not found or the result of
- /// {@link #instanceIdInfo(int, int)}.
- ///
- protected internal virtual int FindInstanceIdInfo (string name)
- {
- return 0;
- }
-
- ///
- /// Map id back to property name it defines.
- ///
- protected internal virtual string GetInstanceIdName (int id)
- {
- throw new ArgumentException (Convert.ToString (id));
- }
-
- ///
- /// Get id value.
- /// * If id value is constant, descendant can call cacheIdValue to store
- /// * value in the permanent cache.
- /// * Default implementation creates IdFunctionObject instance for given id
- /// * and cache its value
- ///
- protected internal virtual object GetInstanceIdValue (int id)
- {
- throw new ApplicationException (Convert.ToString (id));
- }
-
- ///
- /// Set or delete id value. If value == NOT_FOUND , the implementation
- /// should make sure that the following getInstanceIdValue return NOT_FOUND.
- ///
- protected internal virtual void SetInstanceIdValue (int id, object value)
- {
- throw new ApplicationException (Convert.ToString (id));
- }
-
- /// 'thisObj' will be null if invoked as constructor, in which case
- /// * instance of Scriptable should be returned.
- ///
- public virtual object ExecIdCall (IdFunctionObject f, Context cx, IScriptable scope, IScriptable thisObj, object [] args)
- {
- throw f.Unknown ();
- }
-
- public IdFunctionObject ExportAsJSClass (int maxPrototypeId, IScriptable scope, bool zealed)
- {
- return ExportAsJSClass (maxPrototypeId, scope, zealed, ScriptableObject.DONTENUM);
- }
-
- public IdFunctionObject ExportAsJSClass (int maxPrototypeId, IScriptable scope, bool zealed, int attributes)
- {
- // Set scope and prototype unless this is top level scope itself
- if (scope != this && scope != null) {
- ParentScope = scope;
- SetPrototype (GetObjectPrototype (scope));
- }
-
- ActivatePrototypeMap (maxPrototypeId);
- IdFunctionObject ctor = prototypeValues.createPrecachedConstructor ();
- if (zealed) {
- SealObject ();
- }
- FillConstructorProperties (ctor);
- if (zealed) {
- ctor.SealObject ();
- }
- ctor.ExportAsScopeProperty (attributes);
- return ctor;
- }
-
- public void ActivatePrototypeMap (int maxPrototypeId)
- {
- PrototypeValues values = new PrototypeValues (this, maxPrototypeId);
- lock (this) {
- if (prototypeValues != null)
- throw new ApplicationException ();
- prototypeValues = values;
- }
- }
-
- public void InitPrototypeMethod (object tag, int id, string name, int arity)
- {
- IScriptable scope = ScriptableObject.GetTopLevelScope (this);
- IdFunctionObject f = NewIdFunction (tag, id, name, arity, scope);
- prototypeValues.InitValue (id, name, f, DONTENUM);
- }
-
- public void InitPrototypeConstructor (IdFunctionObject f)
- {
- int id = prototypeValues.constructorId;
- if (id == 0)
- throw new ApplicationException ();
- if (f.MethodId != id)
- throw new ArgumentException ();
- if (Sealed) {
- f.SealObject ();
- }
- prototypeValues.InitValue (id, "constructor", f, DONTENUM);
- }
-
- public void InitPrototypeValue (int id, string name, object value, int attributes)
- {
- prototypeValues.InitValue (id, name, value, attributes);
- }
-
- protected internal virtual void InitPrototypeId (int id)
- {
- throw new ApplicationException (Convert.ToString (id));
- }
-
- protected internal virtual int FindPrototypeId (string name)
- {
- throw new ApplicationException (name);
- }
-
- protected internal virtual void FillConstructorProperties (IdFunctionObject ctor)
- {
- }
-
- protected internal virtual void AddIdFunctionProperty (IScriptable obj, object tag, int id, string name, int arity)
- {
- IScriptable scope = ScriptableObject.GetTopLevelScope (obj);
- IdFunctionObject f = NewIdFunction (tag, id, name, arity, scope);
- f.AddAsProperty (obj);
- }
-
- ///
- /// Utility method to construct type error to indicate incompatible call
- /// when converting script thisObj to a particular type is not possible.
- /// Possible usage would be to have a private function like realThis:
- ///
- /// private static NativeSomething realThis(Scriptable thisObj,
- /// IdFunctionObject f)
- /// {
- /// if (!(thisObj instanceof NativeSomething))
- /// throw incompatibleCallError(f);
- /// return (NativeSomething)thisObj;
- /// }
- ///
- /// Note that although such function can be implemented universally via
- /// java.lang.Class.isInstance(), it would be much more slower.
- ///
- /// specify if the function f does not change state of
- /// object.
- ///
- /// Scriptable object suitable for a check by the instanceof
- /// operator.
- ///
- /// RuntimeException if no more instanceof target can be found
- protected internal static EcmaScriptError IncompatibleCallError (IdFunctionObject f)
- {
- throw ScriptRuntime.TypeErrorById ("msg.incompat.call", f.FunctionName);
- }
-
- private IdFunctionObject NewIdFunction (object tag, int id, string name, int arity, IScriptable scope)
- {
- IdFunctionObject f = new IdFunctionObject (this, tag, id, name, arity, scope);
- if (Sealed) {
- f.SealObject ();
- }
- return f;
- }
-
-
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace EcmaScript.NET
+{
+
+ ///
+ /// Base class for native object implementation that uses IdFunctionObject to export its methods to script via .prototype object.
+ /// Any descendant should implement at least the following methods:
+ /// findInstanceIdInfo
+ /// getInstanceIdName
+ /// execIdCall
+ /// methodArity
+ /// To define non-function properties, the descendant should override
+ /// getInstanceIdValue
+ /// setInstanceIdValue
+ /// to get/set property value and provide its default attributes.
+ /// To customize initializition of constructor and protype objects, descendant
+ /// may override scopeInit or fillConstructorProperties methods.
+ ///
+ public abstract class IdScriptableObject : ScriptableObject, IIdFunctionCall
+ {
+
+ ///
+ /// Get maximum id findInstanceIdInfo can generate.
+ ///
+ protected virtual internal int MaxInstanceId
+ {
+ get
+ {
+ return 0;
+ }
+ }
+
+ private volatile PrototypeValues prototypeValues;
+
+ private sealed class PrototypeValues
+ {
+
+ internal int MaxId
+ {
+ get
+ {
+ return maxId;
+ }
+
+ }
+
+ private const int VALUE_SLOT = 0;
+ private const int NAME_SLOT = 1;
+ private const int SLOT_SPAN = 2;
+
+ private IdScriptableObject obj;
+ private int maxId;
+ private volatile object [] valueArray;
+ private volatile short [] attributeArray;
+ private volatile int lastFoundId = 1;
+
+ // The following helps to avoid creation of valueArray during runtime
+ // initialization for common case of "constructor" property
+ internal int constructorId;
+ private IdFunctionObject constructor;
+ private short constructorAttrs;
+
+ internal PrototypeValues (IdScriptableObject obj, int maxId)
+ {
+ if (obj == null)
+ throw new ArgumentNullException ("obj");
+ if (maxId < 1)
+ throw new ArgumentException ("maxId may not lower than 1");
+ this.obj = obj;
+ this.maxId = maxId;
+ }
+
+ internal void InitValue (int id, string name, object value, int attributes)
+ {
+ if (!(1 <= id && id <= maxId))
+ throw new ArgumentException ();
+ if (name == null)
+ throw new ArgumentException ();
+ if (value == UniqueTag.NotFound)
+ throw new ArgumentException ();
+ ScriptableObject.CheckValidAttributes (attributes);
+ if (obj.FindPrototypeId (name) != id)
+ throw new ArgumentException (name);
+
+ if (id == constructorId) {
+ if (!(value is IdFunctionObject)) {
+ throw new ArgumentException ("consructor should be initialized with IdFunctionObject");
+ }
+ constructor = (IdFunctionObject)value;
+ constructorAttrs = (short)attributes;
+ return;
+ }
+
+ InitSlot (id, name, value, attributes);
+ }
+
+ private void InitSlot (int id, string name, object value, int attributes)
+ {
+ object [] array = valueArray;
+ if (array == null)
+ throw new ArgumentNullException ("array");
+
+ if (value == null) {
+ value = UniqueTag.NullValue;
+ }
+ int index = (id - 1) * SLOT_SPAN;
+ lock (this) {
+ object value2 = array [index + VALUE_SLOT];
+ if (value2 == null) {
+ array [index + VALUE_SLOT] = value;
+ array [index + NAME_SLOT] = name;
+ attributeArray [id - 1] = (short)attributes;
+ }
+ else {
+ if (!name.Equals (array [index + NAME_SLOT]))
+ throw new Exception ();
+ }
+ }
+ }
+
+ internal IdFunctionObject createPrecachedConstructor ()
+ {
+ if (constructorId != 0)
+ throw new Exception ();
+ constructorId = obj.FindPrototypeId ("constructor");
+ if (constructorId == 0) {
+ throw new Exception ("No id for constructor property");
+ }
+ obj.InitPrototypeId (constructorId);
+ if (constructor == null) {
+ throw new Exception (obj.GetType ().FullName + ".initPrototypeId() did not " + "initialize id=" + constructorId);
+ }
+ constructor.InitFunction (obj.ClassName, ScriptableObject.GetTopLevelScope (obj));
+ constructor.MarkAsConstructor (obj);
+ return constructor;
+ }
+
+ internal int FindId (string name)
+ {
+ object [] array = valueArray;
+ if (array == null) {
+ return obj.FindPrototypeId (name);
+ }
+ int id = lastFoundId;
+ if ((object)name == array [(id - 1) * SLOT_SPAN + NAME_SLOT]) {
+ return id;
+ }
+ id = obj.FindPrototypeId (name);
+ if (id != 0) {
+ int nameSlot = (id - 1) * SLOT_SPAN + NAME_SLOT;
+ // Make cache to work!
+ array [nameSlot] = name;
+ lastFoundId = id;
+ }
+ return id;
+ }
+
+ internal bool Has (int id)
+ {
+ object [] array = valueArray;
+ if (array == null) {
+ // Not yet initialized, assume all exists
+ return true;
+ }
+ int valueSlot = (id - 1) * SLOT_SPAN + VALUE_SLOT;
+ object value = array [valueSlot];
+ if (value == null) {
+ // The particular entry has not been yet initialized
+ return true;
+ }
+ return value != UniqueTag.NotFound;
+ }
+
+ internal object Get (int id)
+ {
+ object value = EnsureId (id);
+ if (value == UniqueTag.NullValue) {
+ value = null;
+ }
+ return value;
+ }
+
+ internal void Set (int id, IScriptable start, object value)
+ {
+ if (value == UniqueTag.NotFound)
+ throw new ArgumentException ();
+ EnsureId (id);
+ int attr = attributeArray [id - 1];
+ if ((attr & ScriptableObject.READONLY) == 0) {
+ if (start == obj) {
+ if (value == null) {
+ value = UniqueTag.NullValue;
+ }
+ int valueSlot = (id - 1) * SLOT_SPAN + VALUE_SLOT;
+ lock (this) {
+ valueArray [valueSlot] = value;
+ }
+ }
+ else {
+ int nameSlot = (id - 1) * SLOT_SPAN + NAME_SLOT;
+ string name = (string)valueArray [nameSlot];
+ start.Put (name, start, value);
+ }
+ }
+ }
+
+ internal void Delete (int id)
+ {
+ EnsureId (id);
+ int attr = attributeArray [id - 1];
+ if ((attr & ScriptableObject.PERMANENT) == 0) {
+ int valueSlot = (id - 1) * SLOT_SPAN + VALUE_SLOT;
+ lock (this) {
+ valueArray [valueSlot] = UniqueTag.NotFound;
+ attributeArray [id - 1] = (short)(ScriptableObject.EMPTY);
+ }
+ }
+ }
+
+ internal int GetAttributes (int id)
+ {
+ EnsureId (id);
+ return attributeArray [id - 1];
+ }
+
+ internal void SetAttributes (int id, int attributes)
+ {
+ ScriptableObject.CheckValidAttributes (attributes);
+ EnsureId (id);
+ lock (this) {
+ attributeArray [id - 1] = (short)attributes;
+ }
+ }
+
+ internal object [] GetNames (bool getAll, object [] extraEntries)
+ {
+ object [] names = null;
+ int count = 0;
+
+ for (int id = 1; id <= maxId; ++id) {
+
+ object value = EnsureId (id);
+ if (getAll || (attributeArray [id - 1] & ScriptableObject.DONTENUM) == 0) {
+ if (value != UniqueTag.NotFound) {
+ int nameSlot = (id - 1) * SLOT_SPAN + NAME_SLOT;
+ string name = (string)valueArray [nameSlot];
+ if (names == null) {
+ names = new object [maxId];
+ }
+ names [count++] = name;
+ }
+ }
+ }
+ if (count == 0) {
+ return extraEntries;
+ }
+ else if (extraEntries == null || extraEntries.Length == 0) {
+ if (count != names.Length) {
+ object [] tmp = new object [count];
+ Array.Copy (names, 0, tmp, 0, count);
+ names = tmp;
+ }
+ return names;
+ }
+ else {
+ int extra = extraEntries.Length;
+ object [] tmp = new object [extra + count];
+ Array.Copy (extraEntries, 0, tmp, 0, extra);
+ Array.Copy (names, 0, tmp, extra, count);
+ return tmp;
+ }
+ }
+
+ private object EnsureId (int id)
+ {
+ object [] array = valueArray;
+ if (array == null) {
+ lock (this) {
+ array = valueArray;
+ if (array == null) {
+ array = new object [maxId * SLOT_SPAN];
+ valueArray = array;
+ attributeArray = new short [maxId];
+ }
+ }
+ }
+ int valueSlot = (id - 1) * SLOT_SPAN + VALUE_SLOT;
+ object value = array [valueSlot];
+
+ if (value == null) {
+ if (id == constructorId) {
+ InitSlot (constructorId, "constructor", constructor, constructorAttrs);
+ constructor = null; // no need to refer it any longer
+ }
+ else {
+ obj.InitPrototypeId (id);
+ }
+ value = array [valueSlot];
+ if (value == null) {
+ throw new Exception (obj.GetType ().FullName + ".initPrototypeId(int id) " + "did not initialize id=" + id);
+ }
+ }
+ return value;
+ }
+ }
+
+ public IdScriptableObject ()
+ {
+ ;
+ }
+
+ public IdScriptableObject (IScriptable scope, IScriptable prototype)
+ : base (scope, prototype)
+ {
+ ;
+ }
+
+ protected internal object DefaultGet (string name)
+ {
+ return base.Get (name, this);
+ }
+
+ protected internal void DefaultPut (string name, object value)
+ {
+ base.Put (name, this, value);
+ }
+
+ public override bool Has (string name, IScriptable start)
+ {
+ int info = FindInstanceIdInfo (name);
+ if (info != 0) {
+ int attr = (int)((uint)info >> 16);
+ if ((attr & PERMANENT) != 0) {
+ return true;
+ }
+ int id = (info & 0xFFFF);
+ return UniqueTag.NotFound != GetInstanceIdValue (id);
+ }
+ if (prototypeValues != null) {
+ int id = prototypeValues.FindId (name);
+ if (id != 0) {
+ return prototypeValues.Has (id);
+ }
+ }
+ return base.Has (name, start);
+ }
+
+ public override object Get (string name, IScriptable start)
+ {
+ int info = FindInstanceIdInfo (name);
+ if (info != 0) {
+ int id = (info & 0xFFFF);
+ return GetInstanceIdValue (id);
+ }
+ if (prototypeValues != null) {
+ int id = prototypeValues.FindId (name);
+ if (id != 0) {
+ return prototypeValues.Get (id);
+ }
+ }
+ return base.Get (name, start);
+ }
+
+ public override object Put (string name, IScriptable start, object value)
+ {
+ int info = FindInstanceIdInfo (name);
+ if (info != 0) {
+ if (start == this && Sealed) {
+ throw Context.ReportRuntimeErrorById ("msg.modify.sealed", name);
+ }
+ int attr = (int)((uint)info >> 16);
+ if ((attr & READONLY) == 0) {
+ if (start == this) {
+ int id = (info & 0xFFFF);
+ SetInstanceIdValue (id, value);
+ }
+ else {
+ return start.Put (name, start, value);
+ }
+ }
+ return value;
+ }
+ if (prototypeValues != null) {
+ int id = prototypeValues.FindId (name);
+ if (id != 0) {
+ if (start == this && Sealed) {
+ throw Context.ReportRuntimeErrorById ("msg.modify.sealed", name);
+ }
+ prototypeValues.Set (id, start, value);
+ return value;
+ }
+ }
+ return base.Put (name, start, value);
+ }
+
+ public override void Delete (string name)
+ {
+ int info = FindInstanceIdInfo (name);
+ if (info != 0) {
+ // Let the super class to throw exceptions for sealed objects
+ if (!Sealed) {
+ int attr = (int)((uint)info >> 16);
+ if ((attr & PERMANENT) == 0) {
+ int id = (info & 0xFFFF);
+ SetInstanceIdValue (id, UniqueTag.NotFound);
+ }
+ return;
+ }
+ }
+ if (prototypeValues != null) {
+ int id = prototypeValues.FindId (name);
+ if (id != 0) {
+ if (!Sealed) {
+ prototypeValues.Delete (id);
+ }
+ return;
+ }
+ }
+ base.Delete (name);
+ }
+
+ public override int GetAttributes (string name)
+ {
+ int info = FindInstanceIdInfo (name);
+ if (info != 0) {
+ int attr = (int)((uint)info >> 16);
+ return attr;
+ }
+ if (prototypeValues != null) {
+ int id = prototypeValues.FindId (name);
+ if (id != 0) {
+ return prototypeValues.GetAttributes (id);
+ }
+ }
+ return base.GetAttributes (name);
+ }
+
+ public override void SetAttributes (string name, int attributes)
+ {
+ ScriptableObject.CheckValidAttributes (attributes);
+ int info = FindInstanceIdInfo (name);
+ if (info != 0) {
+ int currentAttributes = (int)((uint)info >> 16);
+ if (attributes != currentAttributes) {
+ throw new Exception ("Change of attributes for this id is not supported");
+ }
+ return;
+ }
+ if (prototypeValues != null) {
+ int id = prototypeValues.FindId (name);
+ if (id != 0) {
+ prototypeValues.SetAttributes (id, attributes);
+ return;
+ }
+ }
+ base.SetAttributes (name, attributes);
+ }
+
+ internal override object [] GetIds (bool getAll)
+ {
+ object [] result = base.GetIds (getAll);
+
+ if (prototypeValues != null) {
+ result = prototypeValues.GetNames (getAll, result);
+ }
+
+ int maxInstanceId = MaxInstanceId;
+ if (maxInstanceId != 0) {
+ object [] ids = null;
+ int count = 0;
+
+ for (int id = maxInstanceId; id != 0; --id) {
+ string name = GetInstanceIdName (id);
+ int info = FindInstanceIdInfo (name);
+ if (info != 0) {
+ int attr = (int)((uint)info >> 16);
+ if ((attr & PERMANENT) == 0) {
+ if (UniqueTag.NotFound == GetInstanceIdValue (id)) {
+ continue;
+ }
+ }
+ if (getAll || (attr & DONTENUM) == 0) {
+ if (count == 0) {
+ // Need extra room for no more then [1..id] names
+ ids = new object [id];
+ }
+ ids [count++] = name;
+ }
+ }
+ }
+ if (count != 0) {
+ if (result.Length == 0 && ids.Length == count) {
+ result = ids;
+ }
+ else {
+ object [] tmp = new object [result.Length + count];
+ Array.Copy (result, 0, tmp, 0, result.Length);
+ Array.Copy (ids, 0, tmp, result.Length, count);
+ result = tmp;
+ }
+ }
+ }
+ return result;
+ }
+
+ protected internal static int InstanceIdInfo (int attributes, int id)
+ {
+ return (attributes << 16) | id;
+ }
+
+ ///
+ /// Map name to id of instance property.
+ /// Should return 0 if not found or the result of
+ /// {@link #instanceIdInfo(int, int)}.
+ ///
+ protected internal virtual int FindInstanceIdInfo (string name)
+ {
+ return 0;
+ }
+
+ ///
+ /// Map id back to property name it defines.
+ ///
+ protected internal virtual string GetInstanceIdName (int id)
+ {
+ throw new ArgumentException (Convert.ToString (id));
+ }
+
+ ///
+ /// Get id value.
+ /// * If id value is constant, descendant can call cacheIdValue to store
+ /// * value in the permanent cache.
+ /// * Default implementation creates IdFunctionObject instance for given id
+ /// * and cache its value
+ ///
+ protected internal virtual object GetInstanceIdValue (int id)
+ {
+ throw new Exception (Convert.ToString (id));
+ }
+
+ ///
+ /// Set or delete id value. If value == NOT_FOUND , the implementation
+ /// should make sure that the following getInstanceIdValue return NOT_FOUND.
+ ///
+ protected internal virtual void SetInstanceIdValue (int id, object value)
+ {
+ throw new Exception (Convert.ToString (id));
+ }
+
+ /// 'thisObj' will be null if invoked as constructor, in which case
+ /// * instance of Scriptable should be returned.
+ ///
+ public virtual object ExecIdCall (IdFunctionObject f, Context cx, IScriptable scope, IScriptable thisObj, object [] args)
+ {
+ throw f.Unknown ();
+ }
+
+ public IdFunctionObject ExportAsJSClass (int maxPrototypeId, IScriptable scope, bool zealed)
+ {
+ return ExportAsJSClass (maxPrototypeId, scope, zealed, ScriptableObject.DONTENUM);
+ }
+
+ public IdFunctionObject ExportAsJSClass (int maxPrototypeId, IScriptable scope, bool zealed, int attributes)
+ {
+ // Set scope and prototype unless this is top level scope itself
+ if (scope != this && scope != null) {
+ ParentScope = scope;
+ SetPrototype (GetObjectPrototype (scope));
+ }
+
+ ActivatePrototypeMap (maxPrototypeId);
+ IdFunctionObject ctor = prototypeValues.createPrecachedConstructor ();
+ if (zealed) {
+ SealObject ();
+ }
+ FillConstructorProperties (ctor);
+ if (zealed) {
+ ctor.SealObject ();
+ }
+ ctor.ExportAsScopeProperty (attributes);
+ return ctor;
+ }
+
+ public void ActivatePrototypeMap (int maxPrototypeId)
+ {
+ PrototypeValues values = new PrototypeValues (this, maxPrototypeId);
+ lock (this) {
+ if (prototypeValues != null)
+ throw new Exception ();
+ prototypeValues = values;
+ }
+ }
+
+ public void InitPrototypeMethod (object tag, int id, string name, int arity)
+ {
+ IScriptable scope = ScriptableObject.GetTopLevelScope (this);
+ IdFunctionObject f = NewIdFunction (tag, id, name, arity, scope);
+ prototypeValues.InitValue (id, name, f, DONTENUM);
+ }
+
+ public void InitPrototypeConstructor (IdFunctionObject f)
+ {
+ int id = prototypeValues.constructorId;
+ if (id == 0)
+ throw new Exception ();
+ if (f.MethodId != id)
+ throw new ArgumentException ();
+ if (Sealed) {
+ f.SealObject ();
+ }
+ prototypeValues.InitValue (id, "constructor", f, DONTENUM);
+ }
+
+ public void InitPrototypeValue (int id, string name, object value, int attributes)
+ {
+ prototypeValues.InitValue (id, name, value, attributes);
+ }
+
+ protected internal virtual void InitPrototypeId (int id)
+ {
+ throw new Exception (Convert.ToString (id));
+ }
+
+ protected internal virtual int FindPrototypeId (string name)
+ {
+ throw new Exception (name);
+ }
+
+ protected internal virtual void FillConstructorProperties (IdFunctionObject ctor)
+ {
+ }
+
+ protected internal virtual void AddIdFunctionProperty (IScriptable obj, object tag, int id, string name, int arity)
+ {
+ IScriptable scope = ScriptableObject.GetTopLevelScope (obj);
+ IdFunctionObject f = NewIdFunction (tag, id, name, arity, scope);
+ f.AddAsProperty (obj);
+ }
+
+ ///
+ /// Utility method to construct type error to indicate incompatible call
+ /// when converting script thisObj to a particular type is not possible.
+ /// Possible usage would be to have a private function like realThis:
+ ///
+ /// private static NativeSomething realThis(Scriptable thisObj,
+ /// IdFunctionObject f)
+ /// {
+ /// if (!(thisObj instanceof NativeSomething))
+ /// throw incompatibleCallError(f);
+ /// return (NativeSomething)thisObj;
+ /// }
+ ///
+ /// Note that although such function can be implemented universally via
+ /// java.lang.Class.isInstance(), it would be much more slower.
+ ///
+ /// specify if the function f does not change state of
+ /// object.
+ ///
+ /// Scriptable object suitable for a check by the instanceof
+ /// operator.
+ ///
+ /// RuntimeException if no more instanceof target can be found
+ protected internal static EcmaScriptError IncompatibleCallError (IdFunctionObject f)
+ {
+ throw ScriptRuntime.TypeErrorById ("msg.incompat.call", f.FunctionName);
+ }
+
+ private IdFunctionObject NewIdFunction (object tag, int id, string name, int arity, IScriptable scope)
+ {
+ IdFunctionObject f = new IdFunctionObject (this, tag, id, name, arity, scope);
+ if (Sealed) {
+ f.SealObject ();
+ }
+ return f;
+ }
+
+
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/InterpretedFunction.cs b/src/EcmaScript.NET/InterpretedFunction.cs
similarity index 96%
rename from Code/EcmaScript.NET/InterpretedFunction.cs
rename to src/EcmaScript.NET/InterpretedFunction.cs
index f966257..f48c36a 100644
--- a/Code/EcmaScript.NET/InterpretedFunction.cs
+++ b/src/EcmaScript.NET/InterpretedFunction.cs
@@ -1,186 +1,186 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-using EcmaScript.NET.Debugging;
-using EcmaScript.NET.Types;
-
-namespace EcmaScript.NET
-{
-
-
- sealed class InterpretedFunction : BuiltinFunction, IScript
- {
- override public string FunctionName
- {
- get
- {
- return (idata.itsName == null) ? "" : idata.itsName;
- }
-
- }
-
- override public string EncodedSource
- {
- get
- {
- return Interpreter.GetEncodedSource (idata);
- }
-
- }
- override public DebuggableScript DebuggableView
- {
- get
- {
- return idata;
- }
-
- }
- override protected internal Context.Versions LanguageVersion
- {
- get
- {
- return idata.languageVersion;
- }
-
- }
- override protected internal int ParamCount
- {
- get
- {
- return idata.argCount;
- }
-
- }
- override protected internal int ParamAndVarCount
- {
- get
- {
- return idata.argNames.Length;
- }
-
- }
-
- internal InterpreterData idata;
- internal SecurityController securityController;
- internal object securityDomain;
- internal IScriptable [] functionRegExps;
-
- private InterpretedFunction (InterpreterData idata, object staticSecurityDomain)
- {
- this.idata = idata;
-
- // Always get Context from the current thread to
- // avoid security breaches via passing mangled Context instances
- // with bogus SecurityController
- Context cx = Context.CurrentContext;
- SecurityController sc = cx.SecurityController;
- object dynamicDomain;
- if (sc != null) {
- dynamicDomain = sc.getDynamicSecurityDomain (staticSecurityDomain);
- }
- else {
- if (staticSecurityDomain != null) {
- throw new ArgumentException ();
- }
- dynamicDomain = null;
- }
-
- this.securityController = sc;
- this.securityDomain = dynamicDomain;
- }
-
- private InterpretedFunction (InterpretedFunction parent, int index)
- {
- this.idata = parent.idata.itsNestedFunctions [index];
- this.securityController = parent.securityController;
- this.securityDomain = parent.securityDomain;
- }
-
- /// Create script from compiled bytecode.
- internal static InterpretedFunction createScript (InterpreterData idata, object staticSecurityDomain)
- {
- InterpretedFunction f;
- f = new InterpretedFunction (idata, staticSecurityDomain);
- return f;
- }
-
- /// Create function compiled from Function(...) constructor.
- internal static InterpretedFunction createFunction (Context cx, IScriptable scope, InterpreterData idata, object staticSecurityDomain)
- {
- InterpretedFunction f;
- f = new InterpretedFunction (idata, staticSecurityDomain);
- f.initInterpretedFunction (cx, scope);
- return f;
- }
-
- /// Create function embedded in script or another function.
- internal static InterpretedFunction createFunction (Context cx, IScriptable scope, InterpretedFunction parent, int index)
- {
- InterpretedFunction f = new InterpretedFunction (parent, index);
- f.initInterpretedFunction (cx, scope);
- return f;
- }
-
- internal IScriptable [] createRegExpWraps (Context cx, IScriptable scope)
- {
- if (idata.itsRegExpLiterals == null)
- Context.CodeBug ();
-
- RegExpProxy rep = cx.RegExpProxy;
- int N = idata.itsRegExpLiterals.Length;
- IScriptable [] array = new IScriptable [N];
- for (int i = 0; i != N; ++i) {
- array [i] = rep.Wrap (cx, scope, idata.itsRegExpLiterals [i]);
- }
- return array;
- }
-
- private void initInterpretedFunction (Context cx, IScriptable scope)
- {
- initScriptFunction (cx, scope);
- if (idata.itsRegExpLiterals != null) {
- functionRegExps = createRegExpWraps (cx, scope);
- }
- }
-
- public override object Call (Context cx, IScriptable scope, IScriptable thisObj, object [] args)
- {
- if (!ScriptRuntime.hasTopCall (cx)) {
- return ScriptRuntime.DoTopCall (this, cx, scope, thisObj, args);
- }
- return Interpreter.Interpret (this, cx, scope, thisObj, args);
- }
-
- public object Exec (Context cx, IScriptable scope)
- {
- if (idata.itsFunctionType != 0) {
- // Can only be applied to scripts
- throw new ApplicationException ();
- }
- if (!ScriptRuntime.hasTopCall (cx)) {
- // It will go through "call" path. but they are equivalent
- return ScriptRuntime.DoTopCall (this, cx, scope, scope, ScriptRuntime.EmptyArgs);
- }
- return Interpreter.Interpret (this, cx, scope, scope, ScriptRuntime.EmptyArgs);
- }
-
- protected internal override string getParamOrVarName (int index)
- {
- return idata.argNames [index];
- }
-
-
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+using EcmaScript.NET.Debugging;
+using EcmaScript.NET.Types;
+
+namespace EcmaScript.NET
+{
+
+
+ sealed class InterpretedFunction : BuiltinFunction, IScript
+ {
+ override public string FunctionName
+ {
+ get
+ {
+ return (idata.itsName == null) ? "" : idata.itsName;
+ }
+
+ }
+
+ override public string EncodedSource
+ {
+ get
+ {
+ return Interpreter.GetEncodedSource (idata);
+ }
+
+ }
+ override public DebuggableScript DebuggableView
+ {
+ get
+ {
+ return idata;
+ }
+
+ }
+ override protected internal Context.Versions LanguageVersion
+ {
+ get
+ {
+ return idata.languageVersion;
+ }
+
+ }
+ override protected internal int ParamCount
+ {
+ get
+ {
+ return idata.argCount;
+ }
+
+ }
+ override protected internal int ParamAndVarCount
+ {
+ get
+ {
+ return idata.argNames.Length;
+ }
+
+ }
+
+ internal InterpreterData idata;
+ internal SecurityController securityController;
+ internal object securityDomain;
+ internal IScriptable [] functionRegExps;
+
+ private InterpretedFunction (InterpreterData idata, object staticSecurityDomain)
+ {
+ this.idata = idata;
+
+ // Always get Context from the current thread to
+ // avoid security breaches via passing mangled Context instances
+ // with bogus SecurityController
+ Context cx = Context.CurrentContext;
+ SecurityController sc = cx.SecurityController;
+ object dynamicDomain;
+ if (sc != null) {
+ dynamicDomain = sc.getDynamicSecurityDomain (staticSecurityDomain);
+ }
+ else {
+ if (staticSecurityDomain != null) {
+ throw new ArgumentException ();
+ }
+ dynamicDomain = null;
+ }
+
+ this.securityController = sc;
+ this.securityDomain = dynamicDomain;
+ }
+
+ private InterpretedFunction (InterpretedFunction parent, int index)
+ {
+ this.idata = parent.idata.itsNestedFunctions [index];
+ this.securityController = parent.securityController;
+ this.securityDomain = parent.securityDomain;
+ }
+
+ /// Create script from compiled bytecode.
+ internal static InterpretedFunction createScript (InterpreterData idata, object staticSecurityDomain)
+ {
+ InterpretedFunction f;
+ f = new InterpretedFunction (idata, staticSecurityDomain);
+ return f;
+ }
+
+ /// Create function compiled from Function(...) constructor.
+ internal static InterpretedFunction createFunction (Context cx, IScriptable scope, InterpreterData idata, object staticSecurityDomain)
+ {
+ InterpretedFunction f;
+ f = new InterpretedFunction (idata, staticSecurityDomain);
+ f.initInterpretedFunction (cx, scope);
+ return f;
+ }
+
+ /// Create function embedded in script or another function.
+ internal static InterpretedFunction createFunction (Context cx, IScriptable scope, InterpretedFunction parent, int index)
+ {
+ InterpretedFunction f = new InterpretedFunction (parent, index);
+ f.initInterpretedFunction (cx, scope);
+ return f;
+ }
+
+ internal IScriptable [] createRegExpWraps (Context cx, IScriptable scope)
+ {
+ if (idata.itsRegExpLiterals == null)
+ Context.CodeBug ();
+
+ RegExpProxy rep = cx.RegExpProxy;
+ int N = idata.itsRegExpLiterals.Length;
+ IScriptable [] array = new IScriptable [N];
+ for (int i = 0; i != N; ++i) {
+ array [i] = rep.Wrap (cx, scope, idata.itsRegExpLiterals [i]);
+ }
+ return array;
+ }
+
+ private void initInterpretedFunction (Context cx, IScriptable scope)
+ {
+ initScriptFunction (cx, scope);
+ if (idata.itsRegExpLiterals != null) {
+ functionRegExps = createRegExpWraps (cx, scope);
+ }
+ }
+
+ public override object Call (Context cx, IScriptable scope, IScriptable thisObj, object [] args)
+ {
+ if (!ScriptRuntime.hasTopCall (cx)) {
+ return ScriptRuntime.DoTopCall (this, cx, scope, thisObj, args);
+ }
+ return Interpreter.Interpret (this, cx, scope, thisObj, args);
+ }
+
+ public object Exec (Context cx, IScriptable scope)
+ {
+ if (idata.itsFunctionType != 0) {
+ // Can only be applied to scripts
+ throw new Exception ();
+ }
+ if (!ScriptRuntime.hasTopCall (cx)) {
+ // It will go through "call" path. but they are equivalent
+ return ScriptRuntime.DoTopCall (this, cx, scope, scope, ScriptRuntime.EmptyArgs);
+ }
+ return Interpreter.Interpret (this, cx, scope, scope, ScriptRuntime.EmptyArgs);
+ }
+
+ protected internal override string getParamOrVarName (int index)
+ {
+ return idata.argNames [index];
+ }
+
+
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/Interpreter.cs b/src/EcmaScript.NET/Interpreter.cs
similarity index 97%
rename from Code/EcmaScript.NET/Interpreter.cs
rename to src/EcmaScript.NET/Interpreter.cs
index 05cb879..ea601da 100644
--- a/Code/EcmaScript.NET/Interpreter.cs
+++ b/src/EcmaScript.NET/Interpreter.cs
@@ -1,4755 +1,4755 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-using EcmaScript.NET.Debugging;
-using EcmaScript.NET.Collections;
-
-namespace EcmaScript.NET
-{
-
- public class Interpreter
- {
-
- // Additional interpreter-specific codes
-
- const int Icode_DUP = -1;
- const int Icode_DUP2 = -2;
- const int Icode_SWAP = -3;
- const int Icode_POP = -4;
- const int Icode_POP_RESULT = -5;
- const int Icode_IFEQ_POP = -6;
- const int Icode_VAR_INC_DEC = -7;
- const int Icode_NAME_INC_DEC = -8;
- const int Icode_PROP_INC_DEC = -9;
- const int Icode_ELEM_INC_DEC = -10;
- const int Icode_REF_INC_DEC = -11;
- const int Icode_SCOPE_LOAD = -12;
- const int Icode_SCOPE_SAVE = -13;
- const int Icode_TYPEOFNAME = -14;
- const int Icode_NAME_AND_THIS = -15;
- const int Icode_PROP_AND_THIS = -16;
- const int Icode_ELEM_AND_THIS = -17;
- const int Icode_VALUE_AND_THIS = -18;
- const int Icode_CLOSURE_EXPR = -19;
- const int Icode_CLOSURE_STMT = -20;
- const int Icode_CALLSPECIAL = -21;
- const int Icode_RETUNDEF = -22;
- const int Icode_GOSUB = -23;
- const int Icode_STARTSUB = -24;
- const int Icode_RETSUB = -25;
- const int Icode_LINE = -26;
- const int Icode_SHORTNUMBER = -27;
- const int Icode_INTNUMBER = -28;
- const int Icode_LITERAL_NEW = -29;
- const int Icode_LITERAL_SET = -30;
- const int Icode_SPARE_ARRAYLIT = -31;
- const int Icode_REG_IND_C0 = -32;
- const int Icode_REG_IND_C1 = -33;
- const int Icode_REG_IND_C2 = -34;
- const int Icode_REG_IND_C3 = -35;
- const int Icode_REG_IND_C4 = -36;
- const int Icode_REG_IND_C5 = -37;
- const int Icode_REG_IND1 = -38;
- const int Icode_REG_IND2 = -39;
- const int Icode_REG_IND4 = -40;
- const int Icode_REG_STR_C0 = -41;
- const int Icode_REG_STR_C1 = -42;
- const int Icode_REG_STR_C2 = -43;
- const int Icode_REG_STR_C3 = -44;
- const int Icode_REG_STR1 = -45;
- const int Icode_REG_STR2 = -46;
- const int Icode_REG_STR4 = -47;
- const int Icode_GETVAR1 = -48;
- const int Icode_SETVAR1 = -49;
- const int Icode_UNDEF = -50;
- const int Icode_ZERO = -51;
- const int Icode_ONE = -52;
- const int Icode_ENTERDQ = -53;
- const int Icode_LEAVEDQ = -54;
- const int Icode_TAIL_CALL = -55;
- const int Icode_LOCAL_CLEAR = -56;
- const int Icode_DEBUGGER = -57;
-
- // Last icode
- const int MIN_ICODE = -57;
-
-
- // data for parsing
-
- CompilerEnvirons compilerEnv;
-
- bool itsInFunctionFlag;
-
- InterpreterData itsData;
- ScriptOrFnNode scriptOrFn;
- int itsICodeTop;
- int itsStackDepth;
- int itsLineNumber;
- int itsDoubleTableTop;
- ObjToIntMap itsStrings = new ObjToIntMap (20);
- int itsLocalTop;
-
- const int MIN_LABEL_TABLE_SIZE = 32;
- const int MIN_FIXUP_TABLE_SIZE = 40;
- int [] itsLabelTable;
- int itsLabelTableTop;
- // itsFixupTable[i] = (label_index << 32) | fixup_site
- long [] itsFixupTable;
- int itsFixupTableTop;
- ObjArray itsLiteralIds = new ObjArray ();
-
- int itsExceptionTableTop;
- const int EXCEPTION_TRY_START_SLOT = 0;
- const int EXCEPTION_TRY_END_SLOT = 1;
- const int EXCEPTION_HANDLER_SLOT = 2;
- const int EXCEPTION_TYPE_SLOT = 3;
- const int EXCEPTION_LOCAL_SLOT = 4;
- const int EXCEPTION_SCOPE_SLOT = 5;
- // SLOT_SIZE: space for try start/end, handler, start, handler type,
- // exception local and scope local
- const int EXCEPTION_SLOT_SIZE = 6;
-
- // ECF_ or Expression Context Flags constants: for now only TAIL is available
- const int ECF_TAIL = 1 << 0;
-
-
- internal class CallFrame : System.ICloneable
- {
-
- internal CallFrame parentFrame;
- // amount of stack frames before this one on the interpretation stack
- internal int frameIndex;
- // If true indicates read-only frame that is a part of continuation
- internal bool frozen;
-
- internal InterpretedFunction fnOrScript;
- internal InterpreterData idata;
-
- // Stack structure
- // stack[0 <= i < localShift]: arguments and local variables
- // stack[localShift <= i <= emptyStackTop]: used for local temporaries
- // stack[emptyStackTop < i < stack.length]: stack data
- // sDbl[i]: if stack[i] is UniqueTag.DoubleMark, sDbl[i] holds the number value
-
- internal object [] stack;
- internal double [] sDbl;
-
- internal CallFrame varSource; // defaults to this unless continuation frame
- internal int localShift;
- internal int emptyStackTop;
-
- internal DebugFrame debuggerFrame;
- internal bool useActivation;
-
- internal IScriptable thisObj;
- internal IScriptable [] scriptRegExps;
-
- // The values that change during interpretation
-
- internal object result;
- internal double resultDbl;
- internal int pc;
- internal int pcPrevBranch;
- internal int pcSourceLineStart;
- internal IScriptable scope;
-
- internal int savedStackTop;
- internal int savedCallOp;
-
- internal virtual CallFrame cloneFrozen ()
- {
- if (!frozen)
- Context.CodeBug ();
-
- CallFrame copy = (CallFrame)Clone ();
-
- // clone stack but keep varSource to point to values
- // from this frame to share variables.
-
- // TODO: STACK
- copy.stack = new object [stack.Length];
- stack.CopyTo (copy.stack, 0);
- copy.sDbl = new double [sDbl.Length];
- sDbl.CopyTo (copy.sDbl, 0);
-
- copy.frozen = false;
- return copy;
- }
-
- virtual public object Clone ()
- {
- return base.MemberwiseClone ();
- }
- }
-
-
- sealed class ContinuationJump
- {
-
- internal CallFrame capturedFrame;
- internal CallFrame branchFrame;
- internal object result;
- internal double resultDbl;
-
- internal ContinuationJump (Continuation c, CallFrame current)
- {
- this.capturedFrame = (CallFrame)c.Implementation;
- if (this.capturedFrame == null || current == null) {
- // Continuation and current execution does not share
- // any frames if there is nothing to capture or
- // if there is no currently executed frames
- this.branchFrame = null;
- }
- else {
- // Search for branch frame where parent frame chains starting
- // from captured and current meet.
- CallFrame chain1 = this.capturedFrame;
- CallFrame chain2 = current;
-
- // First work parents of chain1 or chain2 until the same
- // frame depth.
- int diff = chain1.frameIndex - chain2.frameIndex;
- if (diff != 0) {
- if (diff < 0) {
- // swap to make sure that
- // chain1.frameIndex > chain2.frameIndex and diff > 0
- chain1 = current;
- chain2 = this.capturedFrame;
- diff = -diff;
- }
- do {
- chain1 = chain1.parentFrame;
- }
- while (--diff != 0);
- if (chain1.frameIndex != chain2.frameIndex)
- Context.CodeBug ();
- }
-
- // Now walk parents in parallel until a shared frame is found
- // or until the root is reached.
- while (chain1 != chain2 && chain1 != null) {
- chain1 = chain1.parentFrame;
- chain2 = chain2.parentFrame;
- }
-
- this.branchFrame = chain1;
- if (this.branchFrame != null && !this.branchFrame.frozen)
- Context.CodeBug ();
- }
- }
- }
-
- static string bytecodeName (int bytecode)
- {
- if (!validBytecode (bytecode)) {
- throw new ArgumentException (Convert.ToString (bytecode));
- }
-
- if (!Token.printICode) {
- return Convert.ToString (bytecode);
- }
-
- if (ValidTokenCode (bytecode)) {
- return Token.name (bytecode);
- }
-
- switch (bytecode) {
-
- case Icode_DUP:
- return "DUP";
-
- case Icode_DUP2:
- return "DUP2";
-
- case Icode_SWAP:
- return "SWAP";
-
- case Icode_POP:
- return "POP";
-
- case Icode_POP_RESULT:
- return "POP_RESULT";
-
- case Icode_IFEQ_POP:
- return "IFEQ_POP";
-
- case Icode_VAR_INC_DEC:
- return "VAR_INC_DEC";
-
- case Icode_NAME_INC_DEC:
- return "NAME_INC_DEC";
-
- case Icode_PROP_INC_DEC:
- return "PROP_INC_DEC";
-
- case Icode_ELEM_INC_DEC:
- return "ELEM_INC_DEC";
-
- case Icode_REF_INC_DEC:
- return "REF_INC_DEC";
-
- case Icode_SCOPE_LOAD:
- return "SCOPE_LOAD";
-
- case Icode_SCOPE_SAVE:
- return "SCOPE_SAVE";
-
- case Icode_TYPEOFNAME:
- return "TYPEOFNAME";
-
- case Icode_NAME_AND_THIS:
- return "NAME_AND_THIS";
-
- case Icode_PROP_AND_THIS:
- return "PROP_AND_THIS";
-
- case Icode_ELEM_AND_THIS:
- return "ELEM_AND_THIS";
-
- case Icode_VALUE_AND_THIS:
- return "VALUE_AND_THIS";
-
- case Icode_CLOSURE_EXPR:
- return "CLOSURE_EXPR";
-
- case Icode_CLOSURE_STMT:
- return "CLOSURE_STMT";
-
- case Icode_CALLSPECIAL:
- return "CALLSPECIAL";
-
- case Icode_RETUNDEF:
- return "RETUNDEF";
-
- case Icode_GOSUB:
- return "GOSUB";
-
- case Icode_STARTSUB:
- return "STARTSUB";
-
- case Icode_RETSUB:
- return "RETSUB";
-
- case Icode_LINE:
- return "LINE";
-
- case Icode_SHORTNUMBER:
- return "SHORTNUMBER";
-
- case Icode_INTNUMBER:
- return "INTNUMBER";
-
- case Icode_LITERAL_NEW:
- return "LITERAL_NEW";
-
- case Icode_LITERAL_SET:
- return "LITERAL_SET";
-
- case Icode_SPARE_ARRAYLIT:
- return "SPARE_ARRAYLIT";
-
- case Icode_REG_IND_C0:
- return "REG_IND_C0";
-
- case Icode_REG_IND_C1:
- return "REG_IND_C1";
-
- case Icode_REG_IND_C2:
- return "REG_IND_C2";
-
- case Icode_REG_IND_C3:
- return "REG_IND_C3";
-
- case Icode_REG_IND_C4:
- return "REG_IND_C4";
-
- case Icode_REG_IND_C5:
- return "REG_IND_C5";
-
- case Icode_REG_IND1:
- return "LOAD_IND1";
-
- case Icode_REG_IND2:
- return "LOAD_IND2";
-
- case Icode_REG_IND4:
- return "LOAD_IND4";
-
- case Icode_REG_STR_C0:
- return "REG_STR_C0";
-
- case Icode_REG_STR_C1:
- return "REG_STR_C1";
-
- case Icode_REG_STR_C2:
- return "REG_STR_C2";
-
- case Icode_REG_STR_C3:
- return "REG_STR_C3";
-
- case Icode_REG_STR1:
- return "LOAD_STR1";
-
- case Icode_REG_STR2:
- return "LOAD_STR2";
-
- case Icode_REG_STR4:
- return "LOAD_STR4";
-
- case Icode_GETVAR1:
- return "GETVAR1";
-
- case Icode_SETVAR1:
- return "SETVAR1";
-
- case Icode_UNDEF:
- return "UNDEF";
-
- case Icode_ZERO:
- return "ZERO";
-
- case Icode_ONE:
- return "ONE";
-
- case Icode_ENTERDQ:
- return "ENTERDQ";
-
- case Icode_LEAVEDQ:
- return "LEAVEDQ";
-
- case Icode_TAIL_CALL:
- return "TAIL_CALL";
-
- case Icode_LOCAL_CLEAR:
- return "LOCAL_CLEAR";
-
- case Icode_DEBUGGER:
- return "DEBUGGER";
- }
-
- // icode without name
- throw new ApplicationException (Convert.ToString (bytecode));
- }
-
- static bool validIcode (int icode)
- {
- return MIN_ICODE <= icode && icode <= -1;
- }
-
- static bool ValidTokenCode (int token)
- {
- return Token.FIRST_BYTECODE_TOKEN <= token && token <= Token.LAST_BYTECODE_TOKEN;
- }
-
- static bool validBytecode (int bytecode)
- {
- return validIcode (bytecode) || ValidTokenCode (bytecode);
- }
-
- public virtual object Compile (CompilerEnvirons compilerEnv, ScriptOrFnNode tree, string encodedSource, bool returnFunction)
- {
- this.compilerEnv = compilerEnv;
- new NodeTransformer ().transform (tree);
-
- if (Token.printTrees) {
- System.Console.Out.WriteLine (tree.toStringTree (tree));
- }
-
- if (returnFunction) {
- tree = tree.getFunctionNode (0);
- }
-
- scriptOrFn = tree;
- itsData = new InterpreterData (compilerEnv.LanguageVersion, scriptOrFn.SourceName, encodedSource);
- itsData.topLevel = true;
-
- if (returnFunction) {
- generateFunctionICode ();
- }
- else {
- generateICodeFromTree (scriptOrFn);
- }
-
- return itsData;
- }
-
- public virtual IScript CreateScriptObject (object bytecode, object staticSecurityDomain)
- {
- InterpreterData idata = (InterpreterData)bytecode;
- return InterpretedFunction.createScript (itsData, staticSecurityDomain);
- }
-
- public virtual IFunction CreateFunctionObject (Context cx, IScriptable scope, object bytecode, object staticSecurityDomain)
- {
- InterpreterData idata = (InterpreterData)bytecode;
- return InterpretedFunction.createFunction (cx, scope, itsData, staticSecurityDomain);
- }
-
- void generateFunctionICode ()
- {
- itsInFunctionFlag = true;
-
- FunctionNode theFunction = (FunctionNode)scriptOrFn;
-
- itsData.itsFunctionType = theFunction.FunctionType;
- itsData.itsNeedsActivation = theFunction.RequiresActivation;
- itsData.itsName = theFunction.FunctionName;
- if (!theFunction.IgnoreDynamicScope) {
- if (compilerEnv.UseDynamicScope) {
- itsData.useDynamicScope = true;
- }
- }
-
- generateICodeFromTree (theFunction.LastChild);
- }
-
- void generateICodeFromTree (Node tree)
- {
- generateNestedFunctions ();
-
- generateRegExpLiterals ();
-
- VisitStatement (tree);
- fixLabelGotos ();
- // add RETURN_RESULT only to scripts as function always ends with RETURN
- if (itsData.itsFunctionType == 0) {
- addToken (Token.RETURN_RESULT);
- }
-
- if (itsData.itsICode.Length != itsICodeTop) {
- // Make itsData.itsICode length exactly itsICodeTop to save memory
- // and catch bugs with jumps beyound icode as early as possible
- sbyte [] tmp = new sbyte [itsICodeTop];
- Array.Copy (itsData.itsICode, 0, tmp, 0, itsICodeTop);
- itsData.itsICode = tmp;
- }
- if (itsStrings.size () == 0) {
- itsData.itsStringTable = null;
- }
- else {
- itsData.itsStringTable = new string [itsStrings.size ()];
- ObjToIntMap.Iterator iter = itsStrings.newIterator ();
- for (iter.start (); !iter.done (); iter.next ()) {
- string str = (string)iter.Key;
- int index = iter.Value;
- if (itsData.itsStringTable [index] != null)
- Context.CodeBug ();
- itsData.itsStringTable [index] = str;
- }
- }
- if (itsDoubleTableTop == 0) {
- itsData.itsDoubleTable = null;
- }
- else if (itsData.itsDoubleTable.Length != itsDoubleTableTop) {
- double [] tmp = new double [itsDoubleTableTop];
- Array.Copy (itsData.itsDoubleTable, 0, tmp, 0, itsDoubleTableTop);
- itsData.itsDoubleTable = tmp;
- }
- if (itsExceptionTableTop != 0 && itsData.itsExceptionTable.Length != itsExceptionTableTop) {
- int [] tmp = new int [itsExceptionTableTop];
- Array.Copy (itsData.itsExceptionTable, 0, tmp, 0, itsExceptionTableTop);
- itsData.itsExceptionTable = tmp;
- }
-
- itsData.itsMaxVars = scriptOrFn.ParamAndVarCount;
- // itsMaxFrameArray: interpret method needs this amount for its
- // stack and sDbl arrays
- itsData.itsMaxFrameArray = itsData.itsMaxVars + itsData.itsMaxLocals + itsData.itsMaxStack;
-
- itsData.argNames = scriptOrFn.ParamAndVarNames;
- itsData.argCount = scriptOrFn.ParamCount;
-
- itsData.encodedSourceStart = scriptOrFn.EncodedSourceStart;
- itsData.encodedSourceEnd = scriptOrFn.EncodedSourceEnd;
-
- if (itsLiteralIds.size () != 0) {
- itsData.literalIds = itsLiteralIds.ToArray ();
- }
-
- if (Token.printICode)
- dumpICode (itsData);
- }
-
- void generateNestedFunctions ()
- {
- int functionCount = scriptOrFn.FunctionCount;
- if (functionCount == 0)
- return;
-
- InterpreterData [] array = new InterpreterData [functionCount];
- for (int i = 0; i != functionCount; i++) {
- FunctionNode def = scriptOrFn.getFunctionNode (i);
- Interpreter jsi = new Interpreter ();
- jsi.compilerEnv = compilerEnv;
- jsi.scriptOrFn = def;
- jsi.itsData = new InterpreterData (itsData);
- jsi.generateFunctionICode ();
- array [i] = jsi.itsData;
- }
- itsData.itsNestedFunctions = array;
- }
-
- void generateRegExpLiterals ()
- {
- int N = scriptOrFn.RegexpCount;
- if (N == 0)
- return;
-
- Context cx = Context.CurrentContext;
- RegExpProxy rep = cx.RegExpProxy;
- object [] array = new object [N];
- for (int i = 0; i != N; i++) {
- string str = scriptOrFn.getRegexpString (i);
- string flags = scriptOrFn.getRegexpFlags (i);
- array [i] = rep.Compile (cx, str, flags);
- }
- itsData.itsRegExpLiterals = array;
- }
-
- void updateLineNumber (Node node)
- {
- int lineno = node.Lineno;
- if (lineno != itsLineNumber && lineno >= 0) {
- if (itsData.firstLinePC < 0) {
- itsData.firstLinePC = lineno;
- }
- itsLineNumber = lineno;
- addIcode (Icode_LINE);
- addUint16 (lineno & 0xFFFF);
- }
- }
-
- ApplicationException badTree (Node node)
- {
- throw new ApplicationException (node.ToString ());
- }
-
- void VisitStatement (Node node)
- {
- int type = node.Type;
- Node child = node.FirstChild;
- switch (type) {
-
-
- case Token.FUNCTION: {
- int fnIndex = node.getExistingIntProp (Node.FUNCTION_PROP);
- int fnType = scriptOrFn.getFunctionNode (fnIndex).FunctionType;
- // Only function expressions or function expression
- // statements needs closure code creating new function
- // object on stack as function statements are initialized
- // at script/function start
- // In addition function expression can not present here
- // at statement level, they must only present as expressions.
- if (fnType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) {
- addIndexOp (Icode_CLOSURE_STMT, fnIndex);
- }
- else {
- if (fnType != FunctionNode.FUNCTION_STATEMENT) {
- throw Context.CodeBug ();
- }
- }
- }
- break;
-
-
- case Token.SCRIPT:
- case Token.LABEL:
- case Token.LOOP:
- case Token.BLOCK:
- case Token.EMPTY:
- case Token.WITH:
- updateLineNumber (node);
- while (child != null) {
- VisitStatement (child);
- child = child.Next;
- }
- break;
-
-
- case Token.ENTERWITH:
- VisitExpression (child, 0);
- addToken (Token.ENTERWITH);
- stackChange (-1);
- break;
-
-
- case Token.LEAVEWITH:
- addToken (Token.LEAVEWITH);
- break;
-
-
- case Token.LOCAL_BLOCK: {
- int local = allocLocal ();
- node.putIntProp (Node.LOCAL_PROP, local);
- updateLineNumber (node);
- while (child != null) {
- VisitStatement (child);
- child = child.Next;
- }
- addIndexOp (Icode_LOCAL_CLEAR, local);
- releaseLocal (local);
- }
- break;
-
- case Token.DEBUGGER:
- updateLineNumber (node);
- addIcode (Icode_DEBUGGER);
- break;
-
- case Token.SWITCH:
- updateLineNumber (node); {
- // See comments in IRFactory.createSwitch() for description
- // of SWITCH node
- Node switchNode = (Node.Jump)node;
- VisitExpression (child, 0);
- for (Node.Jump caseNode = (Node.Jump)child.Next; caseNode != null; caseNode = (Node.Jump)caseNode.Next) {
- if (caseNode.Type != Token.CASE)
- throw badTree (caseNode);
- Node test = caseNode.FirstChild;
- addIcode (Icode_DUP);
- stackChange (1);
- VisitExpression (test, 0);
- addToken (Token.SHEQ);
- stackChange (-1);
- // If true, Icode_IFEQ_POP will jump and remove case
- // value from stack
- addGoto (caseNode.target, Icode_IFEQ_POP);
- stackChange (-1);
- }
- addIcode (Icode_POP);
- stackChange (-1);
- }
- break;
-
-
- case Token.TARGET:
- markTargetLabel (node);
- break;
-
-
- case Token.IFEQ:
- case Token.IFNE: {
- Node target = ((Node.Jump)node).target;
- VisitExpression (child, 0);
- addGoto (target, type);
- stackChange (-1);
- }
- break;
-
-
- case Token.GOTO: {
- Node target = ((Node.Jump)node).target;
- addGoto (target, type);
- }
- break;
-
-
- case Token.JSR: {
- Node target = ((Node.Jump)node).target;
- addGoto (target, Icode_GOSUB);
- }
- break;
-
-
- case Token.FINALLY: {
- // Account for incomming GOTOSUB address
- stackChange (1);
- int finallyRegister = getLocalBlockRef (node);
- addIndexOp (Icode_STARTSUB, finallyRegister);
- stackChange (-1);
- while (child != null) {
- VisitStatement (child);
- child = child.Next;
- }
- addIndexOp (Icode_RETSUB, finallyRegister);
- }
- break;
-
-
- case Token.EXPR_VOID:
- case Token.EXPR_RESULT:
- updateLineNumber (node);
- VisitExpression (child, 0);
- addIcode ((type == Token.EXPR_VOID) ? Icode_POP : Icode_POP_RESULT);
- stackChange (-1);
- break;
-
-
- case Token.TRY: {
- Node.Jump tryNode = (Node.Jump)node;
- int exceptionObjectLocal = getLocalBlockRef (tryNode);
- int scopeLocal = allocLocal ();
-
- addIndexOp (Icode_SCOPE_SAVE, scopeLocal);
-
- int tryStart = itsICodeTop;
- while (child != null) {
- VisitStatement (child);
- child = child.Next;
- }
-
- Node catchTarget = tryNode.target;
- if (catchTarget != null) {
- int catchStartPC = itsLabelTable [getTargetLabel (catchTarget)];
- addExceptionHandler (tryStart, catchStartPC, catchStartPC, false, exceptionObjectLocal, scopeLocal);
- }
- Node finallyTarget = tryNode.Finally;
- if (finallyTarget != null) {
- int finallyStartPC = itsLabelTable [getTargetLabel (finallyTarget)];
- addExceptionHandler (tryStart, finallyStartPC, finallyStartPC, true, exceptionObjectLocal, scopeLocal);
- }
-
- addIndexOp (Icode_LOCAL_CLEAR, scopeLocal);
- releaseLocal (scopeLocal);
- }
- break;
-
-
- case Token.CATCH_SCOPE: {
- int localIndex = getLocalBlockRef (node);
- int scopeIndex = node.getExistingIntProp (Node.CATCH_SCOPE_PROP);
- string name = child.String;
- child = child.Next;
- VisitExpression (child, 0); // load expression object
- addStringPrefix (name);
- addIndexPrefix (localIndex);
- addToken (Token.CATCH_SCOPE);
- addUint8 (scopeIndex != 0 ? 1 : 0);
- stackChange (-1);
- }
- break;
-
-
- case Token.THROW:
- updateLineNumber (node);
- VisitExpression (child, 0);
- addToken (Token.THROW);
- addUint16 (itsLineNumber & 0xFFFF);
- stackChange (-1);
- break;
-
-
- case Token.RETHROW:
- updateLineNumber (node);
- addIndexOp (Token.RETHROW, getLocalBlockRef (node));
- break;
-
-
- case Token.RETURN:
- updateLineNumber (node);
- if (child != null) {
- VisitExpression (child, ECF_TAIL);
- addToken (Token.RETURN);
- stackChange (-1);
- }
- else {
- addIcode (Icode_RETUNDEF);
- }
- break;
-
-
- case Token.RETURN_RESULT:
- updateLineNumber (node);
- addToken (Token.RETURN_RESULT);
- break;
-
-
- case Token.ENUM_INIT_KEYS:
- case Token.ENUM_INIT_VALUES:
- VisitExpression (child, 0);
- addIndexOp (type, getLocalBlockRef (node));
- stackChange (-1);
- break;
-
-
- default:
- throw badTree (node);
-
- }
-
- if (itsStackDepth != 0) {
- throw Context.CodeBug ();
- }
- }
-
- bool VisitExpressionOptimized (Node node, int contextFlags)
- {
- return false;
-#if FALKSE
- if (node.Type == Token.ADD) {
- Node next = node.Next;
- if (next == null)
- return false;
- switch (next.Type) {
- case Token.NAME:
- case Token.STRING:
- return true;
- }
- }
- return false;
-#endif
- }
-
- void VisitExpression (Node node, int contextFlags)
- {
- if (VisitExpressionOptimized (node, contextFlags))
- return;
-
- int type = node.Type;
- Node child = node.FirstChild;
- int savedStackDepth = itsStackDepth;
- switch (type) {
-
-
- case Token.FUNCTION: {
- int fnIndex = node.getExistingIntProp (Node.FUNCTION_PROP);
- FunctionNode fn = scriptOrFn.getFunctionNode (fnIndex);
-
- // See comments in visitStatement for Token.FUNCTION case
- switch (fn.FunctionType) {
- case FunctionNode.FUNCTION_EXPRESSION:
- addIndexOp (Icode_CLOSURE_EXPR, fnIndex);
- break;
- default:
- throw Context.CodeBug ();
- }
-
- stackChange (1);
- }
- break;
-
-
- case Token.LOCAL_LOAD: {
- int localIndex = getLocalBlockRef (node);
- addIndexOp (Token.LOCAL_LOAD, localIndex);
- stackChange (1);
- }
- break;
-
-
- case Token.COMMA: {
- Node lastChild = node.LastChild;
- while (child != lastChild) {
- VisitExpression (child, 0);
- addIcode (Icode_POP);
- stackChange (-1);
- child = child.Next;
- }
- // Preserve tail context flag if any
- VisitExpression (child, contextFlags & ECF_TAIL);
- }
- break;
-
-
- case Token.USE_STACK:
- // Indicates that stack was modified externally,
- // like placed catch object
- stackChange (1);
- break;
-
-
- case Token.REF_CALL:
- case Token.CALL:
- case Token.NEW: {
- if (type == Token.NEW) {
- VisitExpression (child, 0);
- }
- else {
- generateCallFunAndThis (child);
- }
- int argCount = 0;
- while ((child = child.Next) != null) {
- VisitExpression (child, 0);
- ++argCount;
- }
- int callType = node.getIntProp (Node.SPECIALCALL_PROP, Node.NON_SPECIALCALL);
- if (callType != Node.NON_SPECIALCALL) {
- // embed line number and source filename
- addIndexOp (Icode_CALLSPECIAL, argCount);
- addUint8 (callType);
- addUint8 (type == Token.NEW ? 1 : 0);
- addUint16 (itsLineNumber & 0xFFFF);
- }
- else {
- if (type == Token.CALL) {
- if ((contextFlags & ECF_TAIL) != 0) {
- type = Icode_TAIL_CALL;
- }
- }
- addIndexOp (type, argCount);
- }
- // adjust stack
- if (type == Token.NEW) {
- // new: f, args -> result
- stackChange (-argCount);
- }
- else {
- // call: f, thisObj, args -> result
- // ref_call: f, thisObj, args -> ref
- stackChange (-1 - argCount);
- }
- if (argCount > itsData.itsMaxCalleeArgs) {
- itsData.itsMaxCalleeArgs = argCount;
- }
- }
- break;
-
-
- case Token.AND:
- case Token.OR: {
- VisitExpression (child, 0);
- addIcode (Icode_DUP);
- stackChange (1);
- int afterSecondJumpStart = itsICodeTop;
- int jump = (type == Token.AND) ? Token.IFNE : Token.IFEQ;
- addGotoOp (jump);
- stackChange (-1);
- addIcode (Icode_POP);
- stackChange (-1);
- child = child.Next;
- // Preserve tail context flag if any
- VisitExpression (child, contextFlags & ECF_TAIL);
- resolveForwardGoto (afterSecondJumpStart);
- }
- break;
-
-
- case Token.HOOK: {
- Node ifThen = child.Next;
- Node ifElse = ifThen.Next;
- VisitExpression (child, 0);
- int elseJumpStart = itsICodeTop;
- addGotoOp (Token.IFNE);
- ;
- stackChange (-1);
- // Preserve tail context flag if any
- VisitExpression (ifThen, contextFlags & ECF_TAIL);
- int afterElseJumpStart = itsICodeTop;
- addGotoOp (Token.GOTO);
- resolveForwardGoto (elseJumpStart);
- itsStackDepth = savedStackDepth;
- // Preserve tail context flag if any
- VisitExpression (ifElse, contextFlags & ECF_TAIL);
- resolveForwardGoto (afterElseJumpStart);
- }
- break;
-
-
- case Token.GETPROP:
- VisitExpression (child, 0);
- child = child.Next;
- addStringOp (Token.GETPROP, child.String);
- break;
-
-
- case Token.ADD:
- case Token.GETELEM:
- case Token.DELPROP:
- case Token.BITAND:
- case Token.BITOR:
- case Token.BITXOR:
- case Token.LSH:
- case Token.RSH:
- case Token.URSH:
- case Token.SUB:
- case Token.MOD:
- case Token.DIV:
- case Token.MUL:
- case Token.EQ:
- case Token.NE:
- case Token.SHEQ:
- case Token.SHNE:
- case Token.IN:
- case Token.INSTANCEOF:
- case Token.LE:
- case Token.LT:
- case Token.GE:
- case Token.GT:
- VisitExpression (child, 0);
- VisitExpression (child.Next, 0);
- addToken (type);
- stackChange (-1);
- break;
-
-
- case Token.POS:
- case Token.NEG:
- case Token.NOT:
- case Token.BITNOT:
- case Token.TYPEOF:
- case Token.VOID:
- VisitExpression (child, 0);
- if (type == Token.VOID) {
- addIcode (Icode_POP);
- addIcode (Icode_UNDEF);
- }
- else {
- addToken (type);
- }
- break;
-
-
- case Token.GET_REF:
- case Token.DEL_REF:
- VisitExpression (child, 0);
- addToken (type);
- break;
-
-
- case Token.SETPROP:
- case Token.SETPROP_OP:
- case Token.SETPROP_GETTER:
- case Token.SETPROP_SETTER:
- {
- VisitExpression (child, 0);
- child = child.Next;
- string property = child.String;
- child = child.Next;
- if (type == Token.SETPROP_OP) {
- addIcode (Icode_DUP);
- stackChange (1);
- addStringOp (Token.GETPROP, property);
- // Compensate for the following USE_STACK
- stackChange (-1);
- }
- VisitExpression (child, 0);
- addStringOp ((type == Token.SETPROP_OP) ? Token.SETPROP : type, property);
- stackChange (-1);
- }
- break;
-
-
- case Token.SETELEM:
- case Token.SETELEM_OP:
- VisitExpression (child, 0);
- child = child.Next;
- VisitExpression (child, 0);
- child = child.Next;
- if (type == Token.SETELEM_OP) {
- addIcode (Icode_DUP2);
- stackChange (2);
- addToken (Token.GETELEM);
- stackChange (-1);
- // Compensate for the following USE_STACK
- stackChange (-1);
- }
- VisitExpression (child, 0);
- addToken (Token.SETELEM);
- stackChange (-2);
- break;
-
-
- case Token.SET_REF:
- case Token.SET_REF_OP:
- VisitExpression (child, 0);
- child = child.Next;
- if (type == Token.SET_REF_OP) {
- addIcode (Icode_DUP);
- stackChange (1);
- addToken (Token.GET_REF);
- // Compensate for the following USE_STACK
- stackChange (-1);
- }
- VisitExpression (child, 0);
- addToken (Token.SET_REF);
- stackChange (-1);
- break;
-
-
- case Token.SETNAME: {
- string name = child.String;
- VisitExpression (child, 0);
- child = child.Next;
- VisitExpression (child, 0);
- addStringOp (Token.SETNAME, name);
- stackChange (-1);
- }
- break;
-
-
- case Token.TYPEOFNAME: {
- string name = node.String;
- int index = -1;
- // use typeofname if an activation frame exists
- // since the vars all exist there instead of in jregs
- if (itsInFunctionFlag && !itsData.itsNeedsActivation)
- index = scriptOrFn.getParamOrVarIndex (name);
- if (index == -1) {
- addStringOp (Icode_TYPEOFNAME, name);
- stackChange (1);
- }
- else {
- addVarOp (Token.GETVAR, index);
- stackChange (1);
- addToken (Token.TYPEOF);
- }
- }
- break;
-
-
- case Token.BINDNAME:
- case Token.NAME:
- case Token.STRING:
- addStringOp (type, node.String);
- stackChange (1);
- break;
-
-
- case Token.INC:
- case Token.DEC:
- VisitIncDec (node, child);
- break;
-
-
- case Token.NUMBER: {
- double num = node.Double;
- int inum = (int)num;
- if (inum == num) {
- if (inum == 0) {
- addIcode (Icode_ZERO);
- // Check for negative zero
- if (1.0 / num < 0.0) {
- addToken (Token.NEG);
- }
- }
- else if (inum == 1) {
- addIcode (Icode_ONE);
- }
- else if ((short)inum == inum) {
- addIcode (Icode_SHORTNUMBER);
- // write short as uin16 bit pattern
- addUint16 (inum & 0xFFFF);
- }
- else {
- addIcode (Icode_INTNUMBER);
- addInt (inum);
- }
- }
- else {
- int index = GetDoubleIndex (num);
- addIndexOp (Token.NUMBER, index);
- }
- stackChange (1);
- }
- break;
-
-
- case Token.GETVAR: {
- if (itsData.itsNeedsActivation)
- Context.CodeBug ();
- string name = node.String;
- int index = scriptOrFn.getParamOrVarIndex (name);
- addVarOp (Token.GETVAR, index);
- stackChange (1);
- }
- break;
-
-
- case Token.SETVAR: {
- if (itsData.itsNeedsActivation)
- Context.CodeBug ();
- string name = child.String;
- child = child.Next;
- VisitExpression (child, 0);
- int index = scriptOrFn.getParamOrVarIndex (name);
- addVarOp (Token.SETVAR, index);
- }
- break;
-
-
-
- case Token.NULL:
- case Token.THIS:
- case Token.THISFN:
- case Token.FALSE:
- case Token.TRUE:
- addToken (type);
- stackChange (1);
- break;
-
-
- case Token.ENUM_NEXT:
- case Token.ENUM_ID:
- addIndexOp (type, getLocalBlockRef (node));
- stackChange (1);
- break;
-
-
- case Token.REGEXP: {
- int index = node.getExistingIntProp (Node.REGEXP_PROP);
- addIndexOp (Token.REGEXP, index);
- stackChange (1);
- }
- break;
-
-
- case Token.ARRAYLIT:
- case Token.OBJECTLIT:
- VisitLiteral (node, child);
- break;
-
-
- case Token.REF_SPECIAL:
- VisitExpression (child, 0);
- addStringOp (type, (string)node.getProp (Node.NAME_PROP));
- break;
-
-
- case Token.REF_MEMBER:
- case Token.REF_NS_MEMBER:
- case Token.REF_NAME:
- case Token.REF_NS_NAME: {
- int memberTypeFlags = node.getIntProp (Node.MEMBER_TYPE_PROP, 0);
- // generate possible target, possible namespace and member
- int childCount = 0;
- do {
- VisitExpression (child, 0);
- ++childCount;
- child = child.Next;
- }
- while (child != null);
- addIndexOp (type, memberTypeFlags);
- stackChange (1 - childCount);
- }
- break;
-
-
- case Token.DOTQUERY: {
- int queryPC;
- updateLineNumber (node);
- VisitExpression (child, 0);
- addIcode (Icode_ENTERDQ);
- stackChange (-1);
- queryPC = itsICodeTop;
- VisitExpression (child.Next, 0);
- addBackwardGoto (Icode_LEAVEDQ, queryPC);
- }
- break;
-
-
- case Token.DEFAULTNAMESPACE:
- case Token.ESCXMLATTR:
- case Token.ESCXMLTEXT:
- VisitExpression (child, 0);
- addToken (type);
- break;
-
- default:
- throw badTree (node);
-
- }
- //if (savedStackDepth + 1 != itsStackDepth) {
- // EcmaScriptHelper.CodeBug();
- //}
- }
-
- void generateCallFunAndThis (Node left)
- {
- // Generate code to place on stack function and thisObj
- int type = left.Type;
- switch (type) {
-
- case Token.NAME: {
- string name = left.String;
- // stack: ... -> ... function thisObj
- addStringOp (Icode_NAME_AND_THIS, name);
- stackChange (2);
- break;
- }
-
- case Token.GETPROP:
- case Token.GETELEM: {
- Node target = left.FirstChild;
- VisitExpression (target, 0);
- Node id = target.Next;
- if (type == Token.GETPROP) {
- string property = id.String;
- // stack: ... target -> ... function thisObj
- addStringOp (Icode_PROP_AND_THIS, property);
- stackChange (1);
- }
- else {
- VisitExpression (id, 0);
- // stack: ... target id -> ... function thisObj
- addIcode (Icode_ELEM_AND_THIS);
- }
- break;
- }
-
- default:
- // Including Token.GETVAR
- VisitExpression (left, 0);
- // stack: ... value -> ... function thisObj
- addIcode (Icode_VALUE_AND_THIS);
- stackChange (1);
- break;
-
- }
- }
-
- void VisitIncDec (Node node, Node child)
- {
- int incrDecrMask = node.getExistingIntProp (Node.INCRDECR_PROP);
- int childType = child.Type;
- switch (childType) {
-
- case Token.GETVAR: {
- if (itsData.itsNeedsActivation)
- Context.CodeBug ();
- string name = child.String;
- int i = scriptOrFn.getParamOrVarIndex (name);
- addVarOp (Icode_VAR_INC_DEC, i);
- addUint8 (incrDecrMask);
- stackChange (1);
- break;
- }
-
- case Token.NAME: {
- string name = child.String;
- addStringOp (Icode_NAME_INC_DEC, name);
- addUint8 (incrDecrMask);
- stackChange (1);
- break;
- }
-
- case Token.GETPROP: {
- Node obj = child.FirstChild;
- VisitExpression (obj, 0);
- string property = obj.Next.String;
- addStringOp (Icode_PROP_INC_DEC, property);
- addUint8 (incrDecrMask);
- break;
- }
-
- case Token.GETELEM: {
- Node obj = child.FirstChild;
- VisitExpression (obj, 0);
- Node index = obj.Next;
- VisitExpression (index, 0);
- addIcode (Icode_ELEM_INC_DEC);
- addUint8 (incrDecrMask);
- stackChange (-1);
- break;
- }
-
- case Token.GET_REF: {
- Node rf = child.FirstChild;
- VisitExpression (rf, 0);
- addIcode (Icode_REF_INC_DEC);
- addUint8 (incrDecrMask);
- break;
- }
-
- default: {
- throw badTree (node);
- }
-
- }
- }
-
- void VisitLiteral (Node node, Node child)
- {
- int type = node.Type;
- int count;
- object [] propertyIds = null;
- if (type == Token.ARRAYLIT) {
- count = 0;
- for (Node n = child; n != null; n = n.Next) {
- ++count;
- }
- }
- else if (type == Token.OBJECTLIT) {
- propertyIds = (object [])node.getProp (Node.OBJECT_IDS_PROP);
- count = propertyIds.Length;
- }
- else {
- throw badTree (node);
- }
- addIndexOp (Icode_LITERAL_NEW, count);
- stackChange (1);
- while (child != null) {
- VisitExpression (child, 0);
- addIcode (Icode_LITERAL_SET);
- stackChange (-1);
- child = child.Next;
- }
- if (type == Token.ARRAYLIT) {
- int [] skipIndexes = (int [])node.getProp (Node.SKIP_INDEXES_PROP);
- if (skipIndexes == null) {
- addToken (Token.ARRAYLIT);
- }
- else {
- int index = itsLiteralIds.size ();
- itsLiteralIds.add (skipIndexes);
- addIndexOp (Icode_SPARE_ARRAYLIT, index);
- }
- }
- else {
- int index = itsLiteralIds.size ();
- itsLiteralIds.add (propertyIds);
- addIndexOp (Token.OBJECTLIT, index);
- }
- }
-
- int getLocalBlockRef (Node node)
- {
- Node localBlock = (Node)node.getProp (Node.LOCAL_BLOCK_PROP);
- return localBlock.getExistingIntProp (Node.LOCAL_PROP);
- }
-
- int getTargetLabel (Node target)
- {
- int label = target.labelId ();
- if (label != -1) {
- return label;
- }
- label = itsLabelTableTop;
- if (itsLabelTable == null || label == itsLabelTable.Length) {
- if (itsLabelTable == null) {
- itsLabelTable = new int [MIN_LABEL_TABLE_SIZE];
- }
- else {
- int [] tmp = new int [itsLabelTable.Length * 2];
- Array.Copy (itsLabelTable, 0, tmp, 0, label);
- itsLabelTable = tmp;
- }
- }
- itsLabelTableTop = label + 1;
- itsLabelTable [label] = -1;
-
- target.labelId (label);
- return label;
- }
-
- void markTargetLabel (Node target)
- {
- int label = getTargetLabel (target);
- if (itsLabelTable [label] != -1) {
- // Can mark label only once
- Context.CodeBug ();
- }
- itsLabelTable [label] = itsICodeTop;
- }
-
- void addGoto (Node target, int gotoOp)
- {
- int label = getTargetLabel (target);
- if (!(label < itsLabelTableTop))
- Context.CodeBug ();
- int targetPC = itsLabelTable [label];
-
- if (targetPC != -1) {
- addBackwardGoto (gotoOp, targetPC);
- }
- else {
- int gotoPC = itsICodeTop;
- addGotoOp (gotoOp);
- int top = itsFixupTableTop;
- if (itsFixupTable == null || top == itsFixupTable.Length) {
- if (itsFixupTable == null) {
- itsFixupTable = new long [MIN_FIXUP_TABLE_SIZE];
- }
- else {
- long [] tmp = new long [itsFixupTable.Length * 2];
- Array.Copy (itsFixupTable, 0, tmp, 0, top);
- itsFixupTable = tmp;
- }
- }
- itsFixupTableTop = top + 1;
- itsFixupTable [top] = ((long)label << 32) | (uint)gotoPC;
- }
- }
-
- void fixLabelGotos ()
- {
- for (int i = 0; i < itsFixupTableTop; i++) {
- long fixup = itsFixupTable [i];
- int label = (int)(fixup >> 32);
- int jumpSource = (int)fixup;
- int pc = itsLabelTable [label];
- if (pc == -1) {
- // Unlocated label
- throw Context.CodeBug ();
- }
- resolveGoto (jumpSource, pc);
- }
- itsFixupTableTop = 0;
- }
-
- void addBackwardGoto (int gotoOp, int jumpPC)
- {
- int fromPC = itsICodeTop;
- // Ensure that this is a jump backward
- if (fromPC <= jumpPC)
- throw Context.CodeBug ();
- addGotoOp (gotoOp);
- resolveGoto (fromPC, jumpPC);
- }
-
-
- void resolveForwardGoto (int fromPC)
- {
- // Ensure that forward jump skips at least self bytecode
- if (itsICodeTop < fromPC + 3)
- throw Context.CodeBug ();
- resolveGoto (fromPC, itsICodeTop);
- }
-
- void resolveGoto (int fromPC, int jumpPC)
- {
- int offset = jumpPC - fromPC;
- // Ensure that jumps do not overlap
- if (0 <= offset && offset <= 2)
- throw Context.CodeBug ();
- int offsetSite = fromPC + 1;
- if (offset != (short)offset) {
- if (itsData.longJumps == null) {
- itsData.longJumps = new UintMap ();
- }
- itsData.longJumps.put (offsetSite, jumpPC);
- offset = 0;
- }
- sbyte [] array = itsData.itsICode;
- array [offsetSite] = (sbyte)(offset >> 8);
- array [offsetSite + 1] = (sbyte)offset;
- }
-
- void addToken (int token)
- {
- if (!ValidTokenCode (token))
- throw Context.CodeBug ();
- addUint8 (token);
- }
-
- void addIcode (int icode)
- {
- if (!validIcode (icode))
- throw Context.CodeBug ();
- // Write negative icode as uint8 bits
- addUint8 (icode & 0xFF);
- }
-
- void addUint8 (int value)
- {
- if ((value & ~0xFF) != 0)
- throw Context.CodeBug ();
- sbyte [] array = itsData.itsICode;
- int top = itsICodeTop;
- if (top == array.Length) {
- array = increaseICodeCapasity (1);
- }
- array [top] = (sbyte)value;
- itsICodeTop = top + 1;
- }
-
- void addUint16 (int value)
- {
- if ((value & ~0xFFFF) != 0)
- throw Context.CodeBug ();
- sbyte [] array = itsData.itsICode;
- int top = itsICodeTop;
- if (top + 2 > array.Length) {
- array = increaseICodeCapasity (2);
- }
- array [top] = (sbyte)((uint)value >> 8);
- array [top + 1] = (sbyte)value;
- itsICodeTop = top + 2;
- }
-
- void addInt (int i)
- {
- sbyte [] array = itsData.itsICode;
- int top = itsICodeTop;
- if (top + 4 > array.Length) {
- array = increaseICodeCapasity (4);
- }
- array [top] = (sbyte)((uint)i >> 24);
- array [top + 1] = (sbyte)((uint)i >> 16);
- array [top + 2] = (sbyte)((uint)i >> 8);
- array [top + 3] = (sbyte)i;
- itsICodeTop = top + 4;
- }
-
- int GetDoubleIndex (double num)
- {
- int index = itsDoubleTableTop;
- if (index == 0) {
- itsData.itsDoubleTable = new double [64];
- }
- else if (itsData.itsDoubleTable.Length == index) {
- double [] na = new double [index * 2];
- Array.Copy (itsData.itsDoubleTable, 0, na, 0, index);
- itsData.itsDoubleTable = na;
- }
- itsData.itsDoubleTable [index] = num;
- itsDoubleTableTop = index + 1;
- return index;
- }
-
- void addVarOp (int op, int varIndex)
- {
- switch (op) {
-
- case Token.GETVAR:
- case Token.SETVAR:
- if (varIndex < 128) {
- addIcode (op == Token.GETVAR ? Icode_GETVAR1 : Icode_SETVAR1);
- addUint8 (varIndex);
- return;
- }
- // fallthrough
- goto case Icode_VAR_INC_DEC;
-
- case Icode_VAR_INC_DEC:
- addIndexOp (op, varIndex);
- return;
- }
- throw Context.CodeBug ();
- }
-
- void addStringOp (int op, string str)
- {
- addStringPrefix (str);
- if (validIcode (op)) {
- addIcode (op);
- }
- else {
- addToken (op);
- }
- }
-
- void addIndexOp (int op, int index)
- {
- addIndexPrefix (index);
- if (validIcode (op)) {
- addIcode (op);
- }
- else {
- addToken (op);
- }
- }
-
- void addStringPrefix (string str)
- {
- int index = itsStrings.Get (str, -1);
- if (index == -1) {
- index = itsStrings.size ();
- itsStrings.put (str, index);
- }
- if (index < 4) {
- addIcode (Icode_REG_STR_C0 - index);
- }
- else if (index <= 0xFF) {
- addIcode (Icode_REG_STR1);
- addUint8 (index);
- }
- else if (index <= 0xFFFF) {
- addIcode (Icode_REG_STR2);
- addUint16 (index);
- }
- else {
- addIcode (Icode_REG_STR4);
- addInt (index);
- }
- }
-
- void addIndexPrefix (int index)
- {
- if (index < 0)
- Context.CodeBug ();
- if (index < 6) {
- addIcode (Icode_REG_IND_C0 - index);
- }
- else if (index <= 0xFF) {
- addIcode (Icode_REG_IND1);
- addUint8 (index);
- }
- else if (index <= 0xFFFF) {
- addIcode (Icode_REG_IND2);
- addUint16 (index);
- }
- else {
- addIcode (Icode_REG_IND4);
- addInt (index);
- }
- }
-
- void addExceptionHandler (int icodeStart, int icodeEnd, int handlerStart, bool isFinally, int exceptionObjectLocal, int scopeLocal)
- {
- int top = itsExceptionTableTop;
- int [] table = itsData.itsExceptionTable;
- if (table == null) {
- if (top != 0)
- Context.CodeBug ();
- table = new int [EXCEPTION_SLOT_SIZE * 2];
- itsData.itsExceptionTable = table;
- }
- else if (table.Length == top) {
- table = new int [table.Length * 2];
- Array.Copy (itsData.itsExceptionTable, 0, table, 0, top);
- itsData.itsExceptionTable = table;
- }
- table [top + EXCEPTION_TRY_START_SLOT] = icodeStart;
- table [top + EXCEPTION_TRY_END_SLOT] = icodeEnd;
- table [top + EXCEPTION_HANDLER_SLOT] = handlerStart;
- table [top + EXCEPTION_TYPE_SLOT] = isFinally ? 1 : 0;
- table [top + EXCEPTION_LOCAL_SLOT] = exceptionObjectLocal;
- table [top + EXCEPTION_SCOPE_SLOT] = scopeLocal;
-
- itsExceptionTableTop = top + EXCEPTION_SLOT_SIZE;
- }
-
- sbyte [] increaseICodeCapasity (int extraSize)
- {
- int capacity = itsData.itsICode.Length;
- int top = itsICodeTop;
- if (top + extraSize <= capacity)
- throw Context.CodeBug ();
- capacity *= 2;
- if (top + extraSize > capacity) {
- capacity = top + extraSize;
- }
- sbyte [] array = new sbyte [capacity];
- Array.Copy (itsData.itsICode, 0, array, 0, top);
- itsData.itsICode = array;
- return array;
- }
-
- void stackChange (int change)
- {
- if (change <= 0) {
- itsStackDepth += change;
- }
- else {
- int newDepth = itsStackDepth + change;
- if (newDepth > itsData.itsMaxStack) {
- itsData.itsMaxStack = newDepth;
- }
- itsStackDepth = newDepth;
- }
- }
-
- int allocLocal ()
- {
- int localSlot = itsLocalTop;
- ++itsLocalTop;
- if (itsLocalTop > itsData.itsMaxLocals) {
- itsData.itsMaxLocals = itsLocalTop;
- }
- return localSlot;
- }
-
- void releaseLocal (int localSlot)
- {
- --itsLocalTop;
- if (localSlot != itsLocalTop)
- Context.CodeBug ();
- }
-
- static int GetShort (sbyte [] iCode, int pc)
- {
- return (iCode [pc] << 8) | (iCode [pc + 1] & 0xFF);
- }
-
- static int GetIndex (sbyte [] iCode, int pc)
- {
- return ((iCode [pc] & 0xFF) << 8) | (iCode [pc + 1] & 0xFF);
- }
-
- static int GetInt (sbyte [] iCode, int pc)
- {
- return (iCode [pc] << 24) | ((iCode [pc + 1] & 0xFF) << 16) | ((iCode [pc + 2] & 0xFF) << 8) | (iCode [pc + 3] & 0xFF);
- }
-
- static int getExceptionHandler (CallFrame frame, bool onlyFinally)
- {
- int [] exceptionTable = frame.idata.itsExceptionTable;
- if (exceptionTable == null) {
- // No exception handlers
- return -1;
- }
-
- // Icode switch in the interpreter increments PC immediately
- // and it is necessary to subtract 1 from the saved PC
- // to point it before the start of the next instruction.
- int pc = frame.pc - 1;
-
- // OPT: use binary search
- int best = -1, bestStart = 0, bestEnd = 0;
- for (int i = 0; i != exceptionTable.Length; i += EXCEPTION_SLOT_SIZE) {
- int start = exceptionTable [i + EXCEPTION_TRY_START_SLOT];
- int end = exceptionTable [i + EXCEPTION_TRY_END_SLOT];
- if (!(start <= pc && pc < end)) {
- continue;
- }
- if (onlyFinally && exceptionTable [i + EXCEPTION_TYPE_SLOT] != 1) {
- continue;
- }
- if (best >= 0) {
- // Since handlers always nest and they never have shared end
- // although they can share start it is sufficient to compare
- // handlers ends
- if (bestEnd < end) {
- continue;
- }
- // Check the above assumption
- if (bestStart > start)
- Context.CodeBug (); // should be nested
- if (bestEnd == end)
- Context.CodeBug (); // no ens sharing
- }
- best = i;
- bestStart = start;
- bestEnd = end;
- }
- return best;
- }
-
- static void dumpICode (InterpreterData idata)
- {
- if (!Token.printICode) {
- return;
- }
-
- sbyte [] iCode = idata.itsICode;
- int iCodeLength = iCode.Length;
- string [] strings = idata.itsStringTable;
-
- System.IO.TextWriter sw = Console.Out;
- sw.WriteLine ("ICode dump, for " + idata.itsName + ", length = " + iCodeLength);
- sw.WriteLine ("MaxStack = " + idata.itsMaxStack);
-
- int indexReg = 0;
- for (int pc = 0; pc < iCodeLength; ) {
- sw.Flush ();
- sw.Write (" [" + pc + "] ");
- int token = iCode [pc];
- int icodeLength = bytecodeSpan (token);
- string tname = bytecodeName (token);
- int old_pc = pc;
- ++pc;
- switch (token) {
-
- default:
- if (icodeLength != 1)
- Context.CodeBug ();
- sw.WriteLine (tname);
- break;
-
-
-
- case Icode_GOSUB:
- case Token.GOTO:
- case Token.IFEQ:
- case Token.IFNE:
- case Icode_IFEQ_POP:
- case Icode_LEAVEDQ: {
- int newPC = pc + GetShort (iCode, pc) - 1;
- sw.WriteLine (tname + " " + newPC);
- pc += 2;
- break;
- }
-
- case Icode_VAR_INC_DEC:
- case Icode_NAME_INC_DEC:
- case Icode_PROP_INC_DEC:
- case Icode_ELEM_INC_DEC:
- case Icode_REF_INC_DEC: {
- int incrDecrType = iCode [pc];
- sw.WriteLine (tname + " " + incrDecrType);
- ++pc;
- break;
- }
-
-
- case Icode_CALLSPECIAL: {
- int callType = iCode [pc] & 0xFF;
- bool isNew = (iCode [pc + 1] != 0);
- int line = GetIndex (iCode, pc + 2);
- sw.WriteLine (tname + " " + callType + " " + isNew + " " + indexReg + " " + line);
- pc += 4;
- break;
- }
-
-
- case Token.CATCH_SCOPE: {
- bool afterFisrtFlag = (iCode [pc] != 0);
- sw.WriteLine (tname + " " + afterFisrtFlag);
- ++pc;
- }
- break;
-
- case Token.REGEXP:
- sw.WriteLine (tname + " " + idata.itsRegExpLiterals [indexReg]);
- break;
-
- case Token.OBJECTLIT:
- case Icode_SPARE_ARRAYLIT:
- sw.WriteLine (tname + " " + idata.literalIds [indexReg]);
- break;
-
- case Icode_CLOSURE_EXPR:
- case Icode_CLOSURE_STMT:
- sw.WriteLine (tname + " " + idata.itsNestedFunctions [indexReg]);
- break;
-
- case Token.CALL:
- case Icode_TAIL_CALL:
- case Token.REF_CALL:
- case Token.NEW:
- sw.WriteLine (tname + ' ' + indexReg);
- break;
-
- case Token.THROW: {
- int line = GetIndex (iCode, pc);
- sw.WriteLine (tname + " : " + line);
- pc += 2;
- break;
- }
-
- case Icode_SHORTNUMBER: {
- int value = GetShort (iCode, pc);
- sw.WriteLine (tname + " " + value);
- pc += 2;
- break;
- }
-
- case Icode_INTNUMBER: {
- int value = GetInt (iCode, pc);
- sw.WriteLine (tname + " " + value);
- pc += 4;
- break;
- }
-
- case Token.NUMBER: {
- double value = idata.itsDoubleTable [indexReg];
- sw.WriteLine (tname + " " + value);
- pc += 2;
- break;
- }
-
- case Icode_LINE: {
- int line = GetIndex (iCode, pc);
- sw.WriteLine (tname + " : " + line);
- pc += 2;
- break;
- }
-
- case Icode_REG_STR1: {
- string str = strings [0xFF & iCode [pc]];
- sw.WriteLine (tname + " \"" + str + '"');
- ++pc;
- break;
- }
-
- case Icode_REG_STR2: {
- string str = strings [GetIndex (iCode, pc)];
- sw.WriteLine (tname + " \"" + str + '"');
- pc += 2;
- break;
- }
-
- case Icode_REG_STR4: {
- string str = strings [GetInt (iCode, pc)];
- sw.WriteLine (tname + " \"" + str + '"');
- pc += 4;
- break;
- }
-
- case Icode_REG_IND1: {
- indexReg = 0xFF & iCode [pc];
- sw.WriteLine (tname + " " + indexReg);
- ++pc;
- break;
- }
-
- case Icode_REG_IND2: {
- indexReg = GetIndex (iCode, pc);
- sw.WriteLine (tname + " " + indexReg);
- pc += 2;
- break;
- }
-
- case Icode_REG_IND4: {
- indexReg = GetInt (iCode, pc);
- sw.WriteLine (tname + " " + indexReg);
- pc += 4;
- break;
- }
-
- case Icode_GETVAR1:
- case Icode_SETVAR1:
- indexReg = iCode [pc];
- sw.WriteLine (tname + " " + indexReg);
- ++pc;
- break;
- }
- if (old_pc + icodeLength != pc)
- Context.CodeBug ();
- }
-
- int [] table = idata.itsExceptionTable;
- if (table != null) {
- sw.WriteLine ("Exception handlers: " + table.Length / EXCEPTION_SLOT_SIZE);
- for (int i = 0; i != table.Length; i += EXCEPTION_SLOT_SIZE) {
- int tryStart = table [i + EXCEPTION_TRY_START_SLOT];
- int tryEnd = table [i + EXCEPTION_TRY_END_SLOT];
- int handlerStart = table [i + EXCEPTION_HANDLER_SLOT];
- int type = table [i + EXCEPTION_TYPE_SLOT];
- int exceptionLocal = table [i + EXCEPTION_LOCAL_SLOT];
- int scopeLocal = table [i + EXCEPTION_SCOPE_SLOT];
-
- sw.WriteLine (" tryStart=" + tryStart + " tryEnd=" + tryEnd + " handlerStart=" + handlerStart + " type=" + (type == 0 ? "catch" : "finally") + " exceptionLocal=" + exceptionLocal);
- }
- }
- sw.Flush ();
- }
-
- static int bytecodeSpan (int bytecode)
- {
- switch (bytecode) {
-
- case Token.THROW:
- // source line
- return 1 + 2;
-
-
- case Icode_GOSUB:
- case Token.GOTO:
- case Token.IFEQ:
- case Token.IFNE:
- case Icode_IFEQ_POP:
- case Icode_LEAVEDQ:
- // target pc offset
- return 1 + 2;
-
-
- case Icode_CALLSPECIAL:
- // call type
- // is new
- // line number
- return 1 + 1 + 1 + 2;
-
-
- case Token.CATCH_SCOPE:
- // scope flag
- return 1 + 1;
-
-
- case Icode_VAR_INC_DEC:
- case Icode_NAME_INC_DEC:
- case Icode_PROP_INC_DEC:
- case Icode_ELEM_INC_DEC:
- case Icode_REF_INC_DEC:
- // type of ++/--
- return 1 + 1;
-
-
- case Icode_SHORTNUMBER:
- // short number
- return 1 + 2;
-
-
- case Icode_INTNUMBER:
- // int number
- return 1 + 4;
-
-
- case Icode_REG_IND1:
- // ubyte index
- return 1 + 1;
-
-
- case Icode_REG_IND2:
- // ushort index
- return 1 + 2;
-
-
- case Icode_REG_IND4:
- // int index
- return 1 + 4;
-
-
- case Icode_REG_STR1:
- // ubyte string index
- return 1 + 1;
-
-
- case Icode_REG_STR2:
- // ushort string index
- return 1 + 2;
-
-
- case Icode_REG_STR4:
- // int string index
- return 1 + 4;
-
-
- case Icode_GETVAR1:
- case Icode_SETVAR1:
- // byte var index
- return 1 + 1;
-
-
- case Icode_LINE:
- // line number
- return 1 + 2;
- }
-
- if (!validBytecode (bytecode))
- throw Context.CodeBug ();
-
- return 1;
- }
-
- internal static int [] getLineNumbers (InterpreterData data)
- {
- UintMap presentLines = new UintMap ();
-
- sbyte [] iCode = data.itsICode;
- int iCodeLength = iCode.Length;
- for (int pc = 0; pc != iCodeLength; ) {
- int bytecode = iCode [pc];
- int span = bytecodeSpan (bytecode);
- if (bytecode == Icode_LINE) {
- if (span != 3)
- Context.CodeBug ();
- int line = GetIndex (iCode, pc + 1);
- presentLines.put (line, 0);
- }
- pc += span;
- }
-
- return presentLines.Keys;
- }
-
- internal static void captureInterpreterStackInfo (EcmaScriptException ex)
- {
- Context cx = Context.CurrentContext;
- if (cx == null || cx.lastInterpreterFrame == null) {
- // No interpreter invocations
- ex.m_InterpreterStackInfo = null;
- ex.m_InterpreterLineData = null;
- return;
- }
- // has interpreter frame on the stack
- CallFrame [] array;
- if (cx.previousInterpreterInvocations == null || cx.previousInterpreterInvocations.size () == 0) {
- array = new CallFrame [1];
- }
- else {
- int previousCount = cx.previousInterpreterInvocations.size ();
- if (cx.previousInterpreterInvocations.peek () == cx.lastInterpreterFrame) {
- // It can happen if exception was generated after
- // frame was pushed to cx.previousInterpreterInvocations
- // but before assignment to cx.lastInterpreterFrame.
- // In this case frames has to be ignored.
- --previousCount;
- }
- array = new CallFrame [previousCount + 1];
- cx.previousInterpreterInvocations.ToArray (array);
- }
- array [array.Length - 1] = (CallFrame)cx.lastInterpreterFrame;
-
- int interpreterFrameCount = 0;
- for (int i = 0; i != array.Length; ++i) {
- interpreterFrameCount += 1 + array [i].frameIndex;
- }
-
- int [] linePC = new int [interpreterFrameCount];
- // Fill linePC with pc positions from all interpreter frames.
- // Start from the most nested frame
- int linePCIndex = interpreterFrameCount;
- for (int i = array.Length; i != 0; ) {
- --i;
- CallFrame frame = array [i];
- while (frame != null) {
- --linePCIndex;
- linePC [linePCIndex] = frame.pcSourceLineStart;
- frame = frame.parentFrame;
- }
- }
- if (linePCIndex != 0)
- Context.CodeBug ();
-
- ex.m_InterpreterStackInfo = array;
- ex.m_InterpreterLineData = linePC;
- }
-
- internal static string GetSourcePositionFromStack (Context cx, int [] linep)
- {
- CallFrame frame = (CallFrame)cx.lastInterpreterFrame;
- InterpreterData idata = frame.idata;
- if (frame.pcSourceLineStart >= 0) {
- linep [0] = GetIndex (idata.itsICode, frame.pcSourceLineStart);
- }
- else {
- linep [0] = 0;
- }
- return idata.itsSourceFile;
- }
-
-
- internal static string GetStack (EcmaScriptException ex)
- {
- System.Text.StringBuilder sb = new System.Text.StringBuilder ();
-
- CallFrame [] array = (CallFrame [])ex.m_InterpreterStackInfo;
- if (array == null) // TODO: When does this happen?
- return sb.ToString ();
-
- int [] linePC = ex.m_InterpreterLineData;
- int arrayIndex = array.Length;
- int linePCIndex = linePC.Length;
-
- while (arrayIndex != 0) {
- --arrayIndex;
-
- CallFrame frame = array [arrayIndex];
- while (frame != null) {
- if (linePCIndex == 0)
- Context.CodeBug ();
- --linePCIndex;
- InterpreterData idata = frame.idata;
-
- if (sb.Length > 0)
- sb.Append (Environment.NewLine);
- sb.Append ("\tat script");
- if (idata.itsName != null && idata.itsName.Length != 0) {
- sb.Append ('.');
- sb.Append (idata.itsName);
- }
- sb.Append ('(');
- sb.Append (idata.itsSourceFile);
- int pc = linePC [linePCIndex];
- if (pc >= 0) {
- // Include line info only if available
- sb.Append (':');
- sb.Append (GetIndex (idata.itsICode, pc));
- }
- sb.Append (')');
-
-
- frame = frame.parentFrame;
-
-
- }
- }
-
- return sb.ToString ();
- }
-
- internal static string getPatchedStack (EcmaScriptException ex, string nativeStackTrace)
- {
- string tag = "EcmaScript.NET.Interpreter.interpretLoop";
- System.Text.StringBuilder sb = new System.Text.StringBuilder (nativeStackTrace.Length + 1000);
- string lineSeparator = System.Environment.NewLine;
-
- CallFrame [] array = (CallFrame [])ex.m_InterpreterStackInfo;
- if (array == null) // TODO: when does this happen?
- return sb.ToString ();
-
- int [] linePC = ex.m_InterpreterLineData;
- int arrayIndex = array.Length;
- int linePCIndex = linePC.Length;
- int offset = 0;
- while (arrayIndex != 0) {
- --arrayIndex;
- int pos = nativeStackTrace.IndexOf (tag, offset);
- if (pos < 0) {
- break;
- }
-
- // Skip tag length
- pos += tag.Length;
- // Skip until the end of line
- for (; pos != nativeStackTrace.Length; ++pos) {
- char c = nativeStackTrace [pos];
- if (c == '\n' || c == '\r') {
- break;
- }
- }
- sb.Append (nativeStackTrace.Substring (offset, (pos) - (offset)));
- offset = pos;
-
- CallFrame frame = array [arrayIndex];
- while (frame != null) {
- if (linePCIndex == 0)
- Context.CodeBug ();
- --linePCIndex;
- InterpreterData idata = frame.idata;
- sb.Append (lineSeparator);
- sb.Append ("\tat script");
- if (idata.itsName != null && idata.itsName.Length != 0) {
- sb.Append ('.');
- sb.Append (idata.itsName);
- }
- sb.Append ('(');
- sb.Append (idata.itsSourceFile);
- int pc = linePC [linePCIndex];
- if (pc >= 0) {
- // Include line info only if available
- sb.Append (':');
- sb.Append (GetIndex (idata.itsICode, pc));
- }
- sb.Append (')');
- frame = frame.parentFrame;
- }
- }
- sb.Append (nativeStackTrace.Substring (offset));
-
- return sb.ToString ();
- }
-
- internal static string GetEncodedSource (InterpreterData idata)
- {
- if (idata.encodedSource == null) {
- return null;
- }
- return idata.encodedSource.Substring (idata.encodedSourceStart, (idata.encodedSourceEnd) - (idata.encodedSourceStart));
- }
-
- static void initFunction (Context cx, IScriptable scope, InterpretedFunction parent, int index)
- {
- InterpretedFunction fn;
- fn = InterpretedFunction.createFunction (cx, scope, parent, index);
- ScriptRuntime.initFunction (cx, scope, fn, fn.idata.itsFunctionType, parent.idata.evalScriptFlag);
- }
-
- internal static object Interpret (InterpretedFunction ifun, Context cx, IScriptable scope, IScriptable thisObj, object [] args)
- {
- using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier (128)) {
- if (!ScriptRuntime.hasTopCall (cx))
- Context.CodeBug ();
-
- if (cx.interpreterSecurityDomain != ifun.securityDomain) {
- object savedDomain = cx.interpreterSecurityDomain;
- cx.interpreterSecurityDomain = ifun.securityDomain;
- try {
- return ifun.securityController.callWithDomain (ifun.securityDomain, cx, ifun, scope, thisObj, args);
- }
- finally {
- cx.interpreterSecurityDomain = savedDomain;
- }
- }
-
- CallFrame frame = new CallFrame ();
- initFrame (cx, scope, thisObj, args, null, 0, args.Length, ifun, null, frame);
-
- return InterpretLoop (cx, frame, (object)null);
- }
- }
-
- public static object restartContinuation (Continuation c, Context cx, IScriptable scope, object [] args)
- {
- if (!ScriptRuntime.hasTopCall (cx)) {
- return ScriptRuntime.DoTopCall (c, cx, scope, null, args);
- }
-
- object arg;
- if (args.Length == 0) {
- arg = Undefined.Value;
- }
- else {
- arg = args [0];
- }
-
- CallFrame capturedFrame = (CallFrame)c.Implementation;
- if (capturedFrame == null) {
- // No frames to restart
- return arg;
- }
-
- ContinuationJump cjump = new ContinuationJump (c, null);
-
- cjump.result = arg;
- return InterpretLoop (cx, null, cjump);
- }
-
- static object InterpretLoop (Context cx, CallFrame frame, object throwable)
- {
- // throwable holds exception object to rethrow or catch
- // It is also used for continuation restart in which case
- // it holds ContinuationJump
-
- object DBL_MRK = UniqueTag.DoubleMark;
- object undefined = Undefined.Value;
-
- bool instructionCounting = (cx.instructionThreshold != 0);
- // arbitrary number to add to instructionCount when calling
- // other functions
- const int INVOCATION_COST = 100;
-
- // arbitrary exception cost for instruction counting
- const int EXCEPTION_COST = 100;
-
- string stringReg = null;
- int indexReg = -1;
-
- if (cx.lastInterpreterFrame != null) {
- // save the top frame from the previous interpreterLoop
- // invocation on the stack
- if (cx.previousInterpreterInvocations == null) {
- cx.previousInterpreterInvocations = new ObjArray ();
- }
- cx.previousInterpreterInvocations.push (cx.lastInterpreterFrame);
- }
-
- // When restarting continuation throwable is not null and to jump
- // to the code that rewind continuation state indexReg should be set
- // to -1.
- // With the normal call throable == null and indexReg == -1 allows to
- // catch bugs with using indeReg to access array eleemnts before
- // initializing indexReg.
-
- if (throwable != null) {
- // Assert assumptions
- if (!(throwable is ContinuationJump)) {
- // It should be continuation
- Context.CodeBug ();
- }
- }
-
- object interpreterResult = null;
- double interpreterResultDbl = 0.0;
-
- for (; ; ) {
-
- try {
-
- if (throwable != null) {
- // Recovering from exception, indexReg contains
- // the index of handler
-
- if (indexReg >= 0) {
- // Normal excepton handler, transfer
- // control appropriately
-
- if (frame.frozen) {
- // TODO: Deal with exceptios!!!
- frame = frame.cloneFrozen ();
- }
-
- int [] table = frame.idata.itsExceptionTable;
-
- frame.pc = table [indexReg + EXCEPTION_HANDLER_SLOT];
- if (instructionCounting) {
- frame.pcPrevBranch = frame.pc;
- }
-
- frame.savedStackTop = frame.emptyStackTop;
- int scopeLocal = frame.localShift + table [indexReg + EXCEPTION_SCOPE_SLOT];
- int exLocal = frame.localShift + table [indexReg + EXCEPTION_LOCAL_SLOT];
- frame.scope = (IScriptable)frame.stack [scopeLocal];
- frame.stack [exLocal] = throwable;
-
- throwable = null;
- }
- else {
- // Continuation restoration
- ContinuationJump cjump = (ContinuationJump)throwable;
-
- // Clear throwable to indicate that execptions are OK
- throwable = null;
-
- if (cjump.branchFrame != frame)
- Context.CodeBug ();
-
- // Check that we have at least one frozen frame
- // in the case of detached continuation restoration:
- // unwind code ensure that
- if (cjump.capturedFrame == null)
- Context.CodeBug ();
-
- // Need to rewind branchFrame, capturedFrame
- // and all frames in between
- int rewindCount = cjump.capturedFrame.frameIndex + 1;
- if (cjump.branchFrame != null) {
- rewindCount -= cjump.branchFrame.frameIndex;
- }
-
- int enterCount = 0;
- CallFrame [] enterFrames = null;
-
- CallFrame x = cjump.capturedFrame;
- for (int i = 0; i != rewindCount; ++i) {
- if (!x.frozen)
- Context.CodeBug ();
- if (isFrameEnterExitRequired (x)) {
- if (enterFrames == null) {
- // Allocate enough space to store the rest
- // of rewind frames in case all of them
- // would require to enter
- enterFrames = new CallFrame [rewindCount - i];
- }
- enterFrames [enterCount] = x;
- ++enterCount;
- }
- x = x.parentFrame;
- }
-
- while (enterCount != 0) {
- // execute enter: walk enterFrames in the reverse
- // order since they were stored starting from
- // the capturedFrame, not branchFrame
- --enterCount;
- x = enterFrames [enterCount];
- EnterFrame (cx, x, ScriptRuntime.EmptyArgs);
- }
-
- // Continuation jump is almost done: capturedFrame
- // points to the call to the function that captured
- // continuation, so clone capturedFrame and
- // emulate return that function with the suplied result
- frame = cjump.capturedFrame.cloneFrozen ();
- setCallResult (frame, cjump.result, cjump.resultDbl);
- // restart the execution
- }
-
- // Should be already cleared
- if (throwable != null)
- Context.CodeBug ();
- }
- else {
- if (frame.frozen)
- Context.CodeBug ();
- }
-
- // Use local variables for constant values in frame
- // for faster access
- object [] stack = frame.stack;
- double [] sDbl = frame.sDbl;
- object [] vars = frame.varSource.stack;
- double [] varDbls = frame.varSource.sDbl;
-
- sbyte [] iCode = frame.idata.itsICode;
- string [] strings = frame.idata.itsStringTable;
-
- // Use local for stackTop as well. Since execption handlers
- // can only exist at statement level where stack is empty,
- // it is necessary to save/restore stackTop only accross
- // function calls and normal returns.
- int stackTop = frame.savedStackTop;
-
- // Store new frame in cx which is used for error reporting etc.
- cx.lastInterpreterFrame = frame;
-
- for (; ; ) {
-
- // Exception handler assumes that PC is already incremented
- // pass the instruction start when it searches the
- // exception handler
- int op = iCode [frame.pc++];
- {
- switch (op) {
-
- case Token.THROW: {
- object value = stack [stackTop];
- if (value == DBL_MRK)
- value = sDbl [stackTop];
- stackTop--;
-
- int sourceLine = GetIndex (iCode, frame.pc);
- throwable = new EcmaScriptThrow (
- value, frame.idata.itsSourceFile, sourceLine);
- goto withoutExceptions_brk;
- }
-
- case Token.RETHROW: {
- indexReg += frame.localShift;
- throwable = stack [indexReg];
- break;
- }
-
- case Token.GE:
- case Token.LE:
- case Token.GT:
- case Token.LT: {
- --stackTop;
- object rhs = stack [stackTop + 1];
- object lhs = stack [stackTop];
- bool valBln;
- {
- {
- double rDbl, lDbl;
- if (rhs == DBL_MRK) {
- rDbl = sDbl [stackTop + 1];
- lDbl = stack_double (frame, stackTop);
- }
- else if (lhs == DBL_MRK) {
- rDbl = ScriptConvert.ToNumber (rhs);
- lDbl = sDbl [stackTop];
- }
- else {
-
- goto number_compare_brk;
- }
- switch (op) {
-
- case Token.GE:
- valBln = (lDbl >= rDbl);
-
- goto object_compare_brk;
-
- case Token.LE:
- valBln = (lDbl <= rDbl);
-
- goto object_compare_brk;
-
- case Token.GT:
- valBln = (lDbl > rDbl);
-
- goto object_compare_brk;
-
- case Token.LT:
- valBln = (lDbl < rDbl);
-
- goto object_compare_brk;
-
- default:
- throw Context.CodeBug ();
-
- }
- }
-
- number_compare_brk:
- ;
-
- switch (op) {
-
- case Token.GE:
- valBln = ScriptRuntime.cmp_LE (rhs, lhs);
- break;
-
- case Token.LE:
- valBln = ScriptRuntime.cmp_LE (lhs, rhs);
- break;
-
- case Token.GT:
- valBln = ScriptRuntime.cmp_LT (rhs, lhs);
- break;
-
- case Token.LT:
- valBln = ScriptRuntime.cmp_LT (lhs, rhs);
- break;
-
- default:
- throw Context.CodeBug ();
-
- }
- }
-
- object_compare_brk:
- ;
-
- stack [stackTop] = valBln;
-
- goto Loop;
- }
- goto case Token.IN;
-
- case Token.IN:
- case Token.INSTANCEOF: {
- object rhs = stack [stackTop];
- if (rhs == DBL_MRK)
- rhs = sDbl [stackTop];
- --stackTop;
- object lhs = stack [stackTop];
- if (lhs == DBL_MRK)
- lhs = sDbl [stackTop];
- bool valBln;
- if (op == Token.IN) {
- valBln = ScriptRuntime.In (lhs, rhs, cx);
- }
- else {
- valBln = ScriptRuntime.InstanceOf (lhs, rhs, cx);
- }
- stack [stackTop] = valBln;
-
- goto Loop;
- }
- goto case Token.EQ;
-
- case Token.EQ:
- case Token.NE: {
- --stackTop;
- bool valBln;
- object rhs = stack [stackTop + 1];
- object lhs = stack [stackTop];
- if (rhs == DBL_MRK) {
- if (lhs == DBL_MRK) {
- valBln = (sDbl [stackTop] == sDbl [stackTop + 1]);
- }
- else {
- valBln = ScriptRuntime.eqNumber (sDbl [stackTop + 1], lhs);
- }
- }
- else {
- if (lhs == DBL_MRK) {
- valBln = ScriptRuntime.eqNumber (sDbl [stackTop], rhs);
- }
- else {
- valBln = ScriptRuntime.eq (lhs, rhs);
- }
- }
- valBln ^= (op == Token.NE);
- stack [stackTop] = valBln;
-
- goto Loop;
- }
- goto case Token.SHEQ;
-
- case Token.SHEQ:
- case Token.SHNE: {
- --stackTop;
- object rhs = stack [stackTop + 1];
- object lhs = stack [stackTop];
- bool valBln;
- {
- double rdbl, ldbl;
- if (rhs == DBL_MRK) {
- rdbl = sDbl [stackTop + 1];
- if (lhs == DBL_MRK) {
- ldbl = sDbl [stackTop];
- }
- else if (CliHelper.IsNumber (lhs)) {
- ldbl = Convert.ToDouble (lhs);
- }
- else {
- valBln = false;
-
- goto shallow_compare_brk;
- }
- }
- else if (lhs == DBL_MRK) {
- ldbl = sDbl [stackTop];
- if (rhs == DBL_MRK) {
- rdbl = sDbl [stackTop + 1];
- }
- else if (CliHelper.IsNumber (rhs)) {
- rdbl = Convert.ToDouble (rhs);
- }
- else {
- valBln = false;
-
- goto shallow_compare_brk;
- }
- }
- else {
- valBln = ScriptRuntime.shallowEq (lhs, rhs);
-
- goto shallow_compare_brk;
- }
- valBln = (ldbl == rdbl);
- }
-
- shallow_compare_brk:
- ;
-
- valBln ^= (op == Token.SHNE);
- stack [stackTop] = valBln;
-
- goto Loop;
- }
- goto case Token.IFNE;
-
- case Token.IFNE:
- if (stack_boolean (frame, stackTop--)) {
- frame.pc += 2;
-
- goto Loop;
- }
-
- goto jumplessRun_brk;
-
- case Token.IFEQ:
- if (!stack_boolean (frame, stackTop--)) {
- frame.pc += 2;
-
- goto Loop;
- }
-
- goto jumplessRun_brk;
-
- case Icode_IFEQ_POP:
- if (!stack_boolean (frame, stackTop--)) {
- frame.pc += 2;
-
- goto Loop;
- }
- stack [stackTop--] = null;
-
- goto jumplessRun_brk;
-
- case Token.GOTO:
-
- goto jumplessRun_brk;
-
- case Icode_GOSUB:
- ++stackTop;
- stack [stackTop] = DBL_MRK;
- sDbl [stackTop] = frame.pc + 2;
-
- goto jumplessRun_brk;
-
- case Icode_STARTSUB:
- if (stackTop == frame.emptyStackTop + 1) {
- // Call from Icode_GOSUB: store return PC address in the local
- indexReg += frame.localShift;
- stack [indexReg] = stack [stackTop];
- sDbl [indexReg] = sDbl [stackTop];
- --stackTop;
- }
- else {
- // Call from exception handler: exception object is already stored
- // in the local
- if (stackTop != frame.emptyStackTop)
- Context.CodeBug ();
- }
-
- goto Loop;
- goto case Icode_RETSUB;
-
- case Icode_RETSUB: {
- // indexReg: local to store return address
- if (instructionCounting) {
- addInstructionCount (cx, frame, 0);
- }
- indexReg += frame.localShift;
- object value = stack [indexReg];
- if (value != DBL_MRK) {
- // Invocation from exception handler, restore object to rethrow
- throwable = value;
- goto withoutExceptions_brk;
- }
- // Normal return from GOSUB
- frame.pc = (int)sDbl [indexReg];
- if (instructionCounting) {
- frame.pcPrevBranch = frame.pc;
- }
-
- goto Loop;
- }
- goto case Icode_POP;
-
- case Icode_POP:
- stack [stackTop] = null;
- stackTop--;
-
- goto Loop;
- goto case Icode_POP_RESULT;
-
- case Icode_POP_RESULT:
- frame.result = stack [stackTop];
- frame.resultDbl = sDbl [stackTop];
- stack [stackTop] = null;
- --stackTop;
-
- goto Loop;
- goto case Icode_DUP;
-
- case Icode_DUP:
- stack [stackTop + 1] = stack [stackTop];
- sDbl [stackTop + 1] = sDbl [stackTop];
- stackTop++;
-
- goto Loop;
- goto case Icode_DUP2;
-
- case Icode_DUP2:
- stack [stackTop + 1] = stack [stackTop - 1];
- sDbl [stackTop + 1] = sDbl [stackTop - 1];
- stack [stackTop + 2] = stack [stackTop];
- sDbl [stackTop + 2] = sDbl [stackTop];
- stackTop += 2;
-
- goto Loop;
- goto case Icode_SWAP;
-
- case Icode_SWAP: {
- object o = stack [stackTop];
- stack [stackTop] = stack [stackTop - 1];
- stack [stackTop - 1] = o;
- double d = sDbl [stackTop];
- sDbl [stackTop] = sDbl [stackTop - 1];
- sDbl [stackTop - 1] = d;
-
- goto Loop;
- }
- goto case Token.RETURN;
-
- case Token.RETURN:
- frame.result = stack [stackTop];
- frame.resultDbl = sDbl [stackTop];
- --stackTop;
-
- goto Loop_brk;
-
- case Token.RETURN_RESULT:
-
- goto Loop_brk;
-
- case Icode_RETUNDEF:
- frame.result = undefined;
-
- goto Loop_brk;
-
- case Token.BITNOT: {
- int rIntValue = stack_int32 (frame, stackTop);
- stack [stackTop] = DBL_MRK;
- sDbl [stackTop] = ~rIntValue;
-
- goto Loop;
- }
- goto case Token.BITAND;
-
- case Token.BITAND:
- case Token.BITOR:
- case Token.BITXOR:
- case Token.LSH:
- case Token.RSH: {
- int rIntValue = stack_int32 (frame, stackTop);
- --stackTop;
- int lIntValue = stack_int32 (frame, stackTop);
- stack [stackTop] = DBL_MRK;
- switch (op) {
-
- case Token.BITAND:
- lIntValue &= rIntValue;
- break;
-
- case Token.BITOR:
- lIntValue |= rIntValue;
- break;
-
- case Token.BITXOR:
- lIntValue ^= rIntValue;
- break;
-
- case Token.LSH:
- lIntValue <<= rIntValue;
- break;
-
- case Token.RSH:
- lIntValue >>= rIntValue;
- break;
- }
- sDbl [stackTop] = lIntValue;
-
- goto Loop;
- }
- goto case Token.URSH;
-
- case Token.URSH: {
- int rIntValue = stack_int32 (frame, stackTop) & 0x1F;
- --stackTop;
- double lDbl = stack_double (frame, stackTop);
- stack [stackTop] = DBL_MRK;
- uint i = (uint)ScriptConvert.ToUint32 (lDbl);
- sDbl [stackTop] = i >> rIntValue;
-
- goto Loop;
- }
- goto case Token.NEG;
-
- case Token.NEG:
- case Token.POS: {
- double rDbl = stack_double (frame, stackTop);
- stack [stackTop] = DBL_MRK;
- if (op == Token.NEG) {
- rDbl = -rDbl;
- }
- sDbl [stackTop] = rDbl;
-
- goto Loop;
- }
- goto case Token.ADD;
-
- case Token.ADD:
- --stackTop;
- DoAdd (stack, sDbl, stackTop, cx);
-
- goto Loop;
- goto case Token.SUB;
-
- case Token.SUB:
- case Token.MUL:
- case Token.DIV:
- case Token.MOD: {
- double rDbl = stack_double (frame, stackTop);
- --stackTop;
- double lDbl = stack_double (frame, stackTop);
- stack [stackTop] = DBL_MRK;
- switch (op) {
-
- case Token.SUB:
- lDbl -= rDbl;
- break;
-
- case Token.MUL:
- lDbl *= rDbl;
- break;
-
- case Token.DIV:
- lDbl /= rDbl;
- break;
-
- case Token.MOD:
- lDbl %= rDbl;
- break;
- }
- sDbl [stackTop] = lDbl;
-
- goto Loop;
- }
- goto case Token.NOT;
-
- case Token.NOT:
- stack [stackTop] = !stack_boolean (frame, stackTop);
-
- goto Loop;
- goto case Token.BINDNAME;
-
- case Token.BINDNAME:
- stack [++stackTop] = ScriptRuntime.bind (cx, frame.scope, stringReg);
-
- goto Loop;
- goto case Token.SETNAME;
-
- case Token.SETNAME: {
- object rhs = stack [stackTop];
- if (rhs == DBL_MRK)
- rhs = sDbl [stackTop];
- --stackTop;
- IScriptable lhs = (IScriptable)stack [stackTop];
- stack [stackTop] = ScriptRuntime.setName (lhs, rhs, cx, frame.scope, stringReg);
-
- goto Loop;
- }
- goto case Token.DELPROP;
-
- case Token.DELPROP: {
- object rhs = stack [stackTop];
- if (rhs == DBL_MRK)
- rhs = sDbl [stackTop];
- --stackTop;
- object lhs = stack [stackTop];
- if (lhs == DBL_MRK)
- lhs = sDbl [stackTop];
- stack [stackTop] = ScriptRuntime.delete (lhs, rhs, cx);
-
- goto Loop;
- }
- goto case Token.GETPROP;
-
- case Token.GETPROP: {
- object lhs = stack [stackTop];
- if (lhs == DBL_MRK)
- lhs = sDbl [stackTop];
- stack [stackTop] = ScriptRuntime.getObjectProp (lhs, stringReg, cx);
-
- goto Loop;
- }
- goto case Token.SETPROP;
-
- case Token.SETPROP_GETTER:
- case Token.SETPROP_SETTER:
- case Token.SETPROP: {
- object rhs = stack [stackTop];
- if (rhs == DBL_MRK)
- rhs = sDbl [stackTop];
- --stackTop;
- object lhs = stack [stackTop];
- if (lhs == DBL_MRK)
- lhs = sDbl [stackTop];
-
- switch (op) {
- case Token.SETPROP_GETTER:
- ((ScriptableObject)lhs).DefineGetter(stringReg, ((ICallable)rhs));
- stack[stackTop] = rhs;
- break;
-
- case Token.SETPROP_SETTER:
- ((ScriptableObject)lhs).DefineSetter(stringReg, ((ICallable)rhs));
- stack[stackTop] = rhs;
- break;
-
-
- default:
- stack [stackTop] = ScriptRuntime.setObjectProp (lhs, stringReg, rhs, cx);
- break;
- }
-
- goto Loop;
- }
- goto case Icode_PROP_INC_DEC;
-
- case Icode_PROP_INC_DEC: {
- object lhs = stack [stackTop];
- if (lhs == DBL_MRK)
- lhs = sDbl [stackTop];
- stack [stackTop] = ScriptRuntime.propIncrDecr (lhs, stringReg, cx, iCode [frame.pc]);
- ++frame.pc;
-
- goto Loop;
- }
- goto case Token.GETELEM;
-
- case Token.GETELEM: {
- --stackTop;
- object lhs = stack [stackTop];
- if (lhs == DBL_MRK) {
- lhs = sDbl [stackTop];
- }
- object value;
- object id = stack [stackTop + 1];
- if (id != DBL_MRK) {
- value = ScriptRuntime.getObjectElem (lhs, id, cx);
- }
- else {
- double d = sDbl [stackTop + 1];
- value = ScriptRuntime.getObjectIndex (lhs, d, cx);
- }
- stack [stackTop] = value;
-
- goto Loop;
- }
- goto case Token.SETELEM;
-
- case Token.SETELEM: {
- stackTop -= 2;
- object rhs = stack [stackTop + 2];
- if (rhs == DBL_MRK) {
- rhs = sDbl [stackTop + 2];
- }
- object lhs = stack [stackTop];
- if (lhs == DBL_MRK) {
- lhs = sDbl [stackTop];
- }
- object value;
- object id = stack [stackTop + 1];
- if (id != DBL_MRK) {
- value = ScriptRuntime.setObjectElem (lhs, id, rhs, cx);
- }
- else {
- double d = sDbl [stackTop + 1];
- value = ScriptRuntime.setObjectIndex (lhs, d, rhs, cx);
- }
- stack [stackTop] = value;
-
- goto Loop;
- }
- goto case Icode_ELEM_INC_DEC;
-
- case Icode_ELEM_INC_DEC: {
- object rhs = stack [stackTop];
- if (rhs == DBL_MRK)
- rhs = sDbl [stackTop];
- --stackTop;
- object lhs = stack [stackTop];
- if (lhs == DBL_MRK)
- lhs = sDbl [stackTop];
- stack [stackTop] = ScriptRuntime.elemIncrDecr (lhs, rhs, cx, iCode [frame.pc]);
- ++frame.pc;
-
- goto Loop;
- }
- goto case Token.GET_REF;
-
- case Token.GET_REF: {
- IRef rf = (IRef)stack [stackTop];
- stack [stackTop] = ScriptRuntime.refGet (rf, cx);
-
- goto Loop;
- }
- goto case Token.SET_REF;
-
- case Token.SET_REF: {
- object value = stack [stackTop];
- if (value == DBL_MRK)
- value = sDbl [stackTop];
- --stackTop;
- IRef rf = (IRef)stack [stackTop];
- stack [stackTop] = ScriptRuntime.refSet (rf, value, cx);
-
- goto Loop;
- }
- goto case Token.DEL_REF;
-
- case Token.DEL_REF: {
- IRef rf = (IRef)stack [stackTop];
- stack [stackTop] = ScriptRuntime.refDel (rf, cx);
-
- goto Loop;
- }
- goto case Icode_REF_INC_DEC;
-
- case Icode_REF_INC_DEC: {
- IRef rf = (IRef)stack [stackTop];
- stack [stackTop] = ScriptRuntime.refIncrDecr (rf, cx, iCode [frame.pc]);
- ++frame.pc;
-
- goto Loop;
- }
- goto case Token.LOCAL_LOAD;
-
- case Token.LOCAL_LOAD:
- ++stackTop;
- indexReg += frame.localShift;
- stack [stackTop] = stack [indexReg];
- sDbl [stackTop] = sDbl [indexReg];
-
- goto Loop;
- goto case Icode_LOCAL_CLEAR;
-
- case Icode_LOCAL_CLEAR:
- indexReg += frame.localShift;
- stack [indexReg] = null;
-
- goto Loop;
- goto case Icode_NAME_AND_THIS;
-
- case Icode_NAME_AND_THIS:
- // stringReg: name
- ++stackTop;
- stack [stackTop] = ScriptRuntime.getNameFunctionAndThis (stringReg, cx, frame.scope);
- ++stackTop;
- stack [stackTop] = ScriptRuntime.lastStoredScriptable (cx);
-
- goto Loop;
- goto case Icode_PROP_AND_THIS;
-
- case Icode_PROP_AND_THIS: {
- object obj = stack [stackTop];
- if (obj == DBL_MRK)
- obj = sDbl [stackTop];
- // stringReg: property
- stack [stackTop] = ScriptRuntime.getPropFunctionAndThis (obj, stringReg, cx);
- ++stackTop;
- stack [stackTop] = ScriptRuntime.lastStoredScriptable (cx);
-
- goto Loop;
- }
- goto case Icode_ELEM_AND_THIS;
-
- case Icode_ELEM_AND_THIS: {
- object obj = stack [stackTop - 1];
- if (obj == DBL_MRK)
- obj = sDbl [stackTop - 1];
- object id = stack [stackTop];
- if (id == DBL_MRK)
- id = sDbl [stackTop];
- stack [stackTop - 1] = ScriptRuntime.GetElemFunctionAndThis (obj, id, cx);
- stack [stackTop] = ScriptRuntime.lastStoredScriptable (cx);
-
- goto Loop;
- }
- goto case Icode_VALUE_AND_THIS;
-
- case Icode_VALUE_AND_THIS: {
- object value = stack [stackTop];
- if (value == DBL_MRK)
- value = sDbl [stackTop];
- stack [stackTop] = ScriptRuntime.getValueFunctionAndThis (value, cx);
- ++stackTop;
- stack [stackTop] = ScriptRuntime.lastStoredScriptable (cx);
-
- goto Loop;
- }
- goto case Icode_CALLSPECIAL;
-
- case Icode_CALLSPECIAL: {
- if (instructionCounting) {
- cx.instructionCount += INVOCATION_COST;
- }
- int callType = iCode [frame.pc] & 0xFF;
- bool isNew = (iCode [frame.pc + 1] != 0);
- int sourceLine = GetIndex (iCode, frame.pc + 2);
-
- // indexReg: number of arguments
- if (isNew) {
- // stack change: function arg0 .. argN -> newResult
- stackTop -= indexReg;
-
- object function = stack [stackTop];
- if (function == DBL_MRK)
- function = sDbl [stackTop];
- object [] outArgs = GetArgsArray (stack, sDbl, stackTop + 1, indexReg);
- stack [stackTop] = ScriptRuntime.newSpecial (cx, function, outArgs, frame.scope, callType);
- }
- else {
- // stack change: function thisObj arg0 .. argN -> result
- stackTop -= (1 + indexReg);
-
- // Call code generation ensure that stack here
- // is ... Callable Scriptable
- IScriptable functionThis = (IScriptable)stack [stackTop + 1];
- ICallable function = (ICallable)stack [stackTop];
- object [] outArgs = GetArgsArray (stack, sDbl, stackTop + 2, indexReg);
- stack [stackTop] = ScriptRuntime.callSpecial (cx, function, functionThis, outArgs, frame.scope, frame.thisObj, callType, frame.idata.itsSourceFile, sourceLine);
- }
- frame.pc += 4;
-
- goto Loop;
- }
- goto case Token.CALL;
-
- case Token.CALL:
- case Icode_TAIL_CALL:
- case Token.REF_CALL: {
- if (instructionCounting) {
- cx.instructionCount += INVOCATION_COST;
- }
- // stack change: function thisObj arg0 .. argN -> result
- // indexReg: number of arguments
- stackTop -= (1 + indexReg);
-
- // CALL generation ensures that fun and funThisObj
- // are already Scriptable and Callable objects respectively
- ICallable fun = (ICallable)stack [stackTop];
- IScriptable funThisObj = (IScriptable)stack [stackTop + 1];
- if (op == Token.REF_CALL) {
- object [] outArgs = GetArgsArray (stack, sDbl, stackTop + 2, indexReg);
- stack [stackTop] = ScriptRuntime.callRef (fun, funThisObj, outArgs, cx);
-
- goto Loop;
- }
- IScriptable calleeScope = frame.scope;
- if (frame.useActivation) {
- calleeScope = ScriptableObject.GetTopLevelScope (frame.scope);
- }
- if (fun is InterpretedFunction) {
- InterpretedFunction ifun = (InterpretedFunction)fun;
- if (frame.fnOrScript.securityDomain == ifun.securityDomain) {
- CallFrame callParentFrame = frame;
- CallFrame calleeFrame = new CallFrame ();
- if (op == Icode_TAIL_CALL) {
- // In principle tail call can re-use the current
- // frame and its stack arrays but it is hard to
- // do properly. Any exceptions that can legally
- // happen during frame re-initialization including
- // StackOverflowException during innocent looking
- // System.arraycopy may leave the current frame
- // data corrupted leading to undefined behaviour
- // in the catch code bellow that unwinds JS stack
- // on exceptions. Then there is issue about frame release
- // end exceptions there.
- // To avoid frame allocation a released frame
- // can be cached for re-use which would also benefit
- // non-tail calls but it is not clear that this caching
- // would gain in performance due to potentially
- // bad iteraction with GC.
- callParentFrame = frame.parentFrame;
- }
- initFrame (cx, calleeScope, funThisObj, stack, sDbl, stackTop + 2, indexReg, ifun, callParentFrame, calleeFrame);
- if (op == Icode_TAIL_CALL) {
- // Release the parent
- ExitFrame (cx, frame, (object)null);
- }
- else {
- frame.savedStackTop = stackTop;
- frame.savedCallOp = op;
- }
- frame = calleeFrame;
-
- goto StateLoop;
- }
- }
-
- if (fun is Continuation) {
- // Jump to the captured continuation
- ContinuationJump cjump;
- cjump = new ContinuationJump ((Continuation)fun, frame);
-
- // continuation result is the first argument if any
- // of contination call
- if (indexReg == 0) {
- cjump.result = undefined;
- }
- else {
- cjump.result = stack [stackTop + 2];
- cjump.resultDbl = sDbl [stackTop + 2];
- }
-
- // Start the real unwind job
- throwable = cjump;
- break;
- }
-
- if (fun is IdFunctionObject) {
- IdFunctionObject ifun = (IdFunctionObject)fun;
- if (Continuation.IsContinuationConstructor (ifun)) {
- captureContinuation (cx, frame, stackTop);
-
- goto Loop;
- }
- }
-
- object [] outArgs2 = GetArgsArray (stack, sDbl, stackTop + 2, indexReg);
- stack [stackTop] = fun.Call (cx, calleeScope, funThisObj, outArgs2);
-
-
- goto Loop;
- }
- goto case Token.NEW;
-
- case Token.NEW: {
- if (instructionCounting) {
- cx.instructionCount += INVOCATION_COST;
- }
- // stack change: function arg0 .. argN -> newResult
- // indexReg: number of arguments
- stackTop -= indexReg;
-
- object lhs = stack [stackTop];
- if (lhs is InterpretedFunction) {
- InterpretedFunction f = (InterpretedFunction)lhs;
- if (frame.fnOrScript.securityDomain == f.securityDomain) {
- IScriptable newInstance = f.CreateObject (cx, frame.scope);
- CallFrame calleeFrame = new CallFrame ();
- initFrame (cx, frame.scope, newInstance, stack, sDbl, stackTop + 1, indexReg, f, frame, calleeFrame);
-
- stack [stackTop] = newInstance;
- frame.savedStackTop = stackTop;
- frame.savedCallOp = op;
- frame = calleeFrame;
-
- goto StateLoop;
- }
- }
- if (!(lhs is IFunction)) {
- if (lhs == DBL_MRK)
- lhs = sDbl [stackTop];
- throw ScriptRuntime.NotFunctionError (lhs);
- }
- IFunction fun = (IFunction)lhs;
-
- if (fun is IdFunctionObject) {
- IdFunctionObject ifun = (IdFunctionObject)fun;
- if (Continuation.IsContinuationConstructor (ifun)) {
- captureContinuation (cx, frame, stackTop);
-
- goto Loop;
- }
- }
-
- object [] outArgs = GetArgsArray (stack, sDbl, stackTop + 1, indexReg);
- stack [stackTop] = fun.Construct (cx, frame.scope, outArgs);
-
- goto Loop;
- }
- goto case Token.TYPEOF;
-
- case Token.TYPEOF: {
- object lhs = stack [stackTop];
- if (lhs == DBL_MRK)
- lhs = sDbl [stackTop];
- stack [stackTop] = ScriptRuntime.Typeof (lhs);
-
- goto Loop;
- }
- goto case Icode_TYPEOFNAME;
-
- case Icode_TYPEOFNAME:
- stack [++stackTop] = ScriptRuntime.TypeofName (frame.scope, stringReg);
-
- goto Loop;
- goto case Token.STRING;
-
- case Token.STRING:
- stack [++stackTop] = stringReg;
-
- goto Loop;
- goto case Icode_SHORTNUMBER;
-
- case Icode_SHORTNUMBER:
- ++stackTop;
- stack [stackTop] = DBL_MRK;
- sDbl [stackTop] = GetShort (iCode, frame.pc);
- frame.pc += 2;
-
- goto Loop;
- goto case Icode_INTNUMBER;
-
- case Icode_INTNUMBER:
- ++stackTop;
- stack [stackTop] = DBL_MRK;
- sDbl [stackTop] = GetInt (iCode, frame.pc);
- frame.pc += 4;
-
- goto Loop;
- goto case Token.NUMBER;
-
- case Token.NUMBER:
- ++stackTop;
- stack [stackTop] = DBL_MRK;
- sDbl [stackTop] = frame.idata.itsDoubleTable [indexReg];
-
- goto Loop;
- goto case Token.NAME;
-
- case Token.NAME:
- stack [++stackTop] = ScriptRuntime.name (cx, frame.scope, stringReg);
-
- goto Loop;
- goto case Icode_NAME_INC_DEC;
-
- case Icode_NAME_INC_DEC:
- stack [++stackTop] = ScriptRuntime.nameIncrDecr (frame.scope, stringReg, iCode [frame.pc]);
- ++frame.pc;
-
- goto Loop;
- goto case Icode_SETVAR1;
-
- case Icode_SETVAR1:
- indexReg = iCode [frame.pc++];
- // fallthrough
- goto case Token.SETVAR;
-
- case Token.SETVAR:
- if (!frame.useActivation) {
- vars [indexReg] = stack [stackTop];
- varDbls [indexReg] = sDbl [stackTop];
- }
- else {
- object val = stack [stackTop];
- if (val == DBL_MRK)
- val = sDbl [stackTop];
- stringReg = frame.idata.argNames [indexReg];
- frame.scope.Put (stringReg, frame.scope, val);
- }
-
- goto Loop;
- goto case Icode_GETVAR1;
-
- case Icode_GETVAR1:
- indexReg = iCode [frame.pc++];
- // fallthrough
- goto case Token.GETVAR;
-
- case Token.GETVAR:
- ++stackTop;
- if (!frame.useActivation) {
- stack [stackTop] = vars [indexReg];
- sDbl [stackTop] = varDbls [indexReg];
- }
- else {
- stringReg = frame.idata.argNames [indexReg];
- stack [stackTop] = frame.scope.Get (stringReg, frame.scope);
- }
-
- goto Loop;
- goto case Icode_VAR_INC_DEC;
-
- case Icode_VAR_INC_DEC: {
- // indexReg : varindex
- ++stackTop;
- int incrDecrMask = iCode [frame.pc];
- if (!frame.useActivation) {
- stack [stackTop] = DBL_MRK;
- object varValue = vars [indexReg];
- double d;
- if (varValue == DBL_MRK) {
- d = varDbls [indexReg];
- }
- else {
- d = ScriptConvert.ToNumber (varValue);
- vars [indexReg] = DBL_MRK;
- }
- double d2 = ((incrDecrMask & Node.DECR_FLAG) == 0) ? d + 1.0 : d - 1.0;
- varDbls [indexReg] = d2;
- sDbl [stackTop] = ((incrDecrMask & Node.POST_FLAG) == 0) ? d2 : d;
- }
- else {
- string varName = frame.idata.argNames [indexReg];
- stack [stackTop] = ScriptRuntime.nameIncrDecr (frame.scope, varName, incrDecrMask);
- }
- ++frame.pc;
-
- goto Loop;
- }
- goto case Icode_ZERO;
-
- case Icode_ZERO:
- ++stackTop;
- stack [stackTop] = DBL_MRK;
- sDbl [stackTop] = 0;
-
- goto Loop;
- goto case Icode_ONE;
-
- case Icode_ONE:
- ++stackTop;
- stack [stackTop] = DBL_MRK;
- sDbl [stackTop] = 1;
-
- goto Loop;
- goto case Token.NULL;
-
- case Token.NULL:
- stack [++stackTop] = null;
-
- goto Loop;
- goto case Token.THIS;
-
- case Token.THIS:
- stack [++stackTop] = frame.thisObj;
-
- goto Loop;
- goto case Token.THISFN;
-
- case Token.THISFN:
- stack [++stackTop] = frame.fnOrScript;
-
- goto Loop;
- goto case Token.FALSE;
-
- case Token.FALSE:
- stack [++stackTop] = false;
-
- goto Loop;
- goto case Token.TRUE;
-
- case Token.TRUE:
- stack [++stackTop] = true;
-
- goto Loop;
- goto case Icode_UNDEF;
-
- case Icode_UNDEF:
- stack [++stackTop] = undefined;
-
- goto Loop;
- goto case Token.ENTERWITH;
-
- case Token.ENTERWITH: {
- object lhs = stack [stackTop];
- if (lhs == DBL_MRK)
- lhs = sDbl [stackTop];
- --stackTop;
- frame.scope = ScriptRuntime.enterWith (lhs, cx, frame.scope);
-
- goto Loop;
- }
- goto case Token.LEAVEWITH;
-
- case Token.LEAVEWITH:
- frame.scope = ScriptRuntime.leaveWith (frame.scope);
-
- goto Loop;
- goto case Token.CATCH_SCOPE;
-
- case Token.CATCH_SCOPE: {
- // stack top: exception object
- // stringReg: name of exception variable
- // indexReg: local for exception scope
- --stackTop;
- indexReg += frame.localShift;
-
- bool afterFirstScope = (frame.idata.itsICode [frame.pc] != 0);
-
- Exception caughtException = (Exception)stack [stackTop + 1];
- IScriptable lastCatchScope;
- if (!afterFirstScope) {
- lastCatchScope = null;
- }
- else {
- lastCatchScope = (IScriptable)stack [indexReg];
- }
- stack [indexReg] = ScriptRuntime.NewCatchScope (caughtException, lastCatchScope, stringReg, cx, frame.scope);
- ++frame.pc;
-
- goto Loop;
- }
- goto case Token.ENUM_INIT_KEYS;
-
- case Token.ENUM_INIT_KEYS:
- case Token.ENUM_INIT_VALUES: {
- object lhs = stack [stackTop];
- if (lhs == DBL_MRK)
- lhs = sDbl [stackTop];
- --stackTop;
- indexReg += frame.localShift;
-
- if (lhs is IIdEnumerable) {
- stack [indexReg] = ((IIdEnumerable)lhs).GetEnumeration (cx, (op == Token.ENUM_INIT_VALUES));
- }
- else {
- stack [indexReg] = new IdEnumeration (lhs, cx, (op == Token.ENUM_INIT_VALUES));
- }
-
-
- goto Loop;
- }
- goto case Token.ENUM_NEXT;
-
- case Token.ENUM_NEXT:
- case Token.ENUM_ID: {
- indexReg += frame.localShift;
- IdEnumeration val = (IdEnumeration)stack [indexReg];
- ++stackTop;
- stack [stackTop] = (op == Token.ENUM_NEXT) ? val.MoveNext () : val.Current (cx);
-
- goto Loop;
- }
- goto case Token.REF_SPECIAL;
-
- case Token.REF_SPECIAL: {
- //stringReg: name of special property
- object obj = stack [stackTop];
- if (obj == DBL_MRK)
- obj = sDbl [stackTop];
- stack [stackTop] = ScriptRuntime.specialRef (obj, stringReg, cx);
-
- goto Loop;
- }
- goto case Token.REF_MEMBER;
-
- case Token.REF_MEMBER: {
- //indexReg: flags
- object elem = stack [stackTop];
- if (elem == DBL_MRK)
- elem = sDbl [stackTop];
- --stackTop;
- object obj = stack [stackTop];
- if (obj == DBL_MRK)
- obj = sDbl [stackTop];
- stack [stackTop] = ScriptRuntime.memberRef (obj, elem, cx, indexReg);
-
- goto Loop;
- }
- goto case Token.REF_NS_MEMBER;
-
- case Token.REF_NS_MEMBER: {
- //indexReg: flags
- object elem = stack [stackTop];
- if (elem == DBL_MRK)
- elem = sDbl [stackTop];
- --stackTop;
- object ns = stack [stackTop];
- if (ns == DBL_MRK)
- ns = sDbl [stackTop];
- --stackTop;
- object obj = stack [stackTop];
- if (obj == DBL_MRK)
- obj = sDbl [stackTop];
- stack [stackTop] = ScriptRuntime.memberRef (obj, ns, elem, cx, indexReg);
-
- goto Loop;
- }
- goto case Token.REF_NAME;
-
- case Token.REF_NAME: {
- //indexReg: flags
- object name = stack [stackTop];
- if (name == DBL_MRK)
- name = sDbl [stackTop];
- stack [stackTop] = ScriptRuntime.nameRef (name, cx, frame.scope, indexReg);
-
- goto Loop;
- }
- goto case Token.REF_NS_NAME;
-
- case Token.REF_NS_NAME: {
- //indexReg: flags
- object name = stack [stackTop];
- if (name == DBL_MRK)
- name = sDbl [stackTop];
- --stackTop;
- object ns = stack [stackTop];
- if (ns == DBL_MRK)
- ns = sDbl [stackTop];
- stack [stackTop] = ScriptRuntime.nameRef (ns, name, cx, frame.scope, indexReg);
-
- goto Loop;
- }
- goto case Icode_SCOPE_LOAD;
-
- case Icode_SCOPE_LOAD:
- indexReg += frame.localShift;
- frame.scope = (IScriptable)stack [indexReg];
-
- goto Loop;
- goto case Icode_SCOPE_SAVE;
-
- case Icode_SCOPE_SAVE:
- indexReg += frame.localShift;
- stack [indexReg] = frame.scope;
-
- goto Loop;
- goto case Icode_CLOSURE_EXPR;
-
- case Icode_CLOSURE_EXPR: {
- InterpretedFunction fun = InterpretedFunction.createFunction (cx, frame.scope, frame.fnOrScript, indexReg);
- stack [++stackTop] = fun;
- }
- goto Loop;
- goto case Icode_CLOSURE_STMT;
-
- case Icode_CLOSURE_STMT:
- initFunction (cx, frame.scope, frame.fnOrScript, indexReg);
-
- goto Loop;
- goto case Token.REGEXP;
-
- case Token.REGEXP:
- stack [++stackTop] = frame.scriptRegExps [indexReg];
-
- goto Loop;
- goto case Icode_LITERAL_NEW;
-
- case Icode_LITERAL_NEW:
- // indexReg: number of values in the literal
- ++stackTop;
- stack [stackTop] = new object [indexReg];
- sDbl [stackTop] = 0;
-
- goto Loop;
- goto case Icode_LITERAL_SET;
-
- case Icode_LITERAL_SET: {
- object value = stack [stackTop];
- if (value == DBL_MRK)
- value = sDbl [stackTop];
- --stackTop;
- int i = (int)sDbl [stackTop];
- ((object [])stack [stackTop]) [i] = value;
- sDbl [stackTop] = i + 1;
-
- goto Loop;
- }
- goto case Token.ARRAYLIT;
-
- case Token.ARRAYLIT:
- case Icode_SPARE_ARRAYLIT:
- case Token.OBJECTLIT: {
- object [] data = (object [])stack [stackTop];
- object val;
- if (op == Token.OBJECTLIT) {
- object [] ids = (object [])frame.idata.literalIds [indexReg];
- val = ScriptRuntime.newObjectLiteral (ids, data, cx, frame.scope);
- }
- else {
- int [] skipIndexces = null;
- if (op == Icode_SPARE_ARRAYLIT) {
- skipIndexces = (int [])frame.idata.literalIds [indexReg];
- }
- val = ScriptRuntime.newArrayLiteral (data, skipIndexces, cx, frame.scope);
- }
- stack [stackTop] = val;
-
- goto Loop;
- }
- goto case Icode_ENTERDQ;
-
- case Icode_ENTERDQ: {
- object lhs = stack [stackTop];
- if (lhs == DBL_MRK)
- lhs = sDbl [stackTop];
- --stackTop;
- frame.scope = ScriptRuntime.enterDotQuery (lhs, frame.scope);
-
- goto Loop;
- }
- goto case Icode_LEAVEDQ;
-
- case Icode_LEAVEDQ: {
- bool valBln = stack_boolean (frame, stackTop);
- object x = ScriptRuntime.updateDotQuery (valBln, frame.scope);
- if (x != null) {
- stack [stackTop] = x;
- frame.scope = ScriptRuntime.leaveDotQuery (frame.scope);
- frame.pc += 2;
-
- goto Loop;
- }
- // reset stack and PC to code after ENTERDQ
- --stackTop;
-
- goto jumplessRun_brk;
- }
-
- case Token.DEFAULTNAMESPACE: {
- object value = stack [stackTop];
- if (value == DBL_MRK)
- value = sDbl [stackTop];
- stack [stackTop] = ScriptRuntime.setDefaultNamespace (value, cx);
-
- goto Loop;
- }
- goto case Token.ESCXMLATTR;
-
- case Token.ESCXMLATTR: {
- object value = stack [stackTop];
- if (value != DBL_MRK) {
- stack [stackTop] = ScriptRuntime.escapeAttributeValue (value, cx);
- }
-
- goto Loop;
- }
- goto case Token.ESCXMLTEXT;
-
- case Token.ESCXMLTEXT: {
- object value = stack [stackTop];
- if (value != DBL_MRK) {
- stack [stackTop] = ScriptRuntime.escapeTextValue (value, cx);
- }
-
- goto Loop;
- }
- goto case Icode_LINE;
-
- case Icode_DEBUGGER: {
- if (frame.debuggerFrame != null) {
- frame.debuggerFrame.OnDebuggerStatement(cx);
- }
- break;
- }
-
- case Icode_LINE:
- frame.pcSourceLineStart = frame.pc;
- if (frame.debuggerFrame != null) {
- int line = GetIndex (iCode, frame.pc);
- frame.debuggerFrame.OnLineChange (cx, line);
- }
- frame.pc += 2;
-
- goto Loop;
- goto case Icode_REG_IND_C0;
-
- case Icode_REG_IND_C0:
- indexReg = 0;
-
- goto Loop;
- goto case Icode_REG_IND_C1;
-
- case Icode_REG_IND_C1:
- indexReg = 1;
-
- goto Loop;
- goto case Icode_REG_IND_C2;
-
- case Icode_REG_IND_C2:
- indexReg = 2;
-
- goto Loop;
- goto case Icode_REG_IND_C3;
-
- case Icode_REG_IND_C3:
- indexReg = 3;
-
- goto Loop;
- goto case Icode_REG_IND_C4;
-
- case Icode_REG_IND_C4:
- indexReg = 4;
-
- goto Loop;
- goto case Icode_REG_IND_C5;
-
- case Icode_REG_IND_C5:
- indexReg = 5;
-
- goto Loop;
- goto case Icode_REG_IND1;
-
- case Icode_REG_IND1:
- indexReg = 0xFF & iCode [frame.pc];
- ++frame.pc;
-
- goto Loop;
- goto case Icode_REG_IND2;
-
- case Icode_REG_IND2:
- indexReg = GetIndex (iCode, frame.pc);
- frame.pc += 2;
-
- goto Loop;
- goto case Icode_REG_IND4;
-
- case Icode_REG_IND4:
- indexReg = GetInt (iCode, frame.pc);
- frame.pc += 4;
-
- goto Loop;
- goto case Icode_REG_STR_C0;
-
- case Icode_REG_STR_C0:
- stringReg = strings [0];
-
- goto Loop;
- goto case Icode_REG_STR_C1;
-
- case Icode_REG_STR_C1:
- stringReg = strings [1];
-
- goto Loop;
- goto case Icode_REG_STR_C2;
-
- case Icode_REG_STR_C2:
- stringReg = strings [2];
-
- goto Loop;
- goto case Icode_REG_STR_C3;
-
- case Icode_REG_STR_C3:
- stringReg = strings [3];
-
- goto Loop;
- goto case Icode_REG_STR1;
-
- case Icode_REG_STR1:
- stringReg = strings [0xFF & iCode [frame.pc]];
- ++frame.pc;
-
- goto Loop;
- goto case Icode_REG_STR2;
-
- case Icode_REG_STR2:
- stringReg = strings [GetIndex (iCode, frame.pc)];
- frame.pc += 2;
-
- goto Loop;
- goto case Icode_REG_STR4;
-
- case Icode_REG_STR4:
- stringReg = strings [GetInt (iCode, frame.pc)];
- frame.pc += 4;
-
- goto Loop;
- goto default;
-
- default:
- dumpICode (frame.idata);
- throw new ApplicationException ("Unknown icode : " + op + " @ pc : " + (frame.pc - 1));
-
- } // end of interpreter switch
- }
-
- jumplessRun_brk:
- ;
- // end of jumplessRun label block
-
- // This should be reachable only for jump implementation
- // when pc points to encoded target offset
- if (instructionCounting) {
- addInstructionCount (cx, frame, 2);
- }
- int offset = GetShort (iCode, frame.pc);
- if (offset != 0) {
- // -1 accounts for pc pointing to jump opcode + 1
- frame.pc += offset - 1;
- }
- else {
- frame.pc = frame.idata.longJumps.getExistingInt (frame.pc);
- }
- if (instructionCounting) {
- frame.pcPrevBranch = frame.pc;
- }
-
- goto Loop;
-
- Loop:
- ;
- }
-
- Loop_brk:
- ;
- // end of Loop: for
-
- ExitFrame (cx, frame, (object)null);
- interpreterResult = frame.result;
- interpreterResultDbl = frame.resultDbl;
- if (frame.parentFrame != null) {
- frame = frame.parentFrame;
- if (frame.frozen) {
- frame = frame.cloneFrozen ();
- }
- setCallResult (frame, interpreterResult, interpreterResultDbl);
- interpreterResult = null; // Help GC
-
- goto StateLoop;
- }
-
- goto StateLoop_brk;
- }
- // end of interpreter withoutExceptions: try
- catch (Exception ex) {
- if (throwable != null) {
- // This is serious bug and it is better to track it ASAP
- throw new ApplicationException ();
- }
- throwable = ex;
- }
-
- withoutExceptions_brk:
-
- // This should be reachable only after above catch or from
- // finally when it needs to propagate exception or from
- // explicit throw
- if (throwable == null)
- Context.CodeBug ();
-
- // Exception type
- const int EX_CATCH_STATE = 2; // Can execute JS catch
- const int EX_FINALLY_STATE = 1; // Can execute JS finally
- const int EX_NO_JS_STATE = 0; // Terminate JS execution
-
- int exState;
- ContinuationJump cjump2 = null;
-
- if (throwable is EcmaScriptThrow) {
- exState = EX_CATCH_STATE;
- }
- else if (throwable is EcmaScriptError) {
- // an offical ECMA error object,
- exState = EX_CATCH_STATE;
- }
- else if (throwable is EcmaScriptRuntimeException) {
- exState = EX_CATCH_STATE;
- }
- else if (throwable is EcmaScriptException) {
- exState = EX_FINALLY_STATE;
- }
- else if (throwable is Exception) {
- exState = EX_NO_JS_STATE;
- }
- else {
- // It must be ContinuationJump
- exState = EX_FINALLY_STATE;
- cjump2 = (ContinuationJump)throwable;
- }
-
- if (instructionCounting) {
- try {
- addInstructionCount (cx, frame, EXCEPTION_COST);
- }
- catch (ApplicationException ex) {
- // Error from instruction counting
- // => unconditionally terminate JS
- throwable = ex;
- cjump2 = null;
- exState = EX_NO_JS_STATE;
- }
- }
- if (frame.debuggerFrame != null && throwable is ApplicationException) {
- // Call debugger only for RuntimeException
- ApplicationException rex = (ApplicationException)throwable;
- try {
- frame.debuggerFrame.OnExceptionThrown (cx, rex);
- }
- catch (Exception ex) {
- // Any exception from debugger
- // => unconditionally terminate JS
- throwable = ex;
- cjump2 = null;
- exState = EX_NO_JS_STATE;
- }
- }
-
- for (; ; ) {
- if (exState != EX_NO_JS_STATE) {
- bool onlyFinally = (exState != EX_CATCH_STATE);
- indexReg = getExceptionHandler (frame, onlyFinally);
- if (indexReg >= 0) {
- // We caught an exception, restart the loop
- // with exception pending the processing at the loop
- // start
-
- goto StateLoop;
- }
- }
- // No allowed execption handlers in this frame, unwind
- // to parent and try to look there
-
- ExitFrame (cx, frame, throwable);
-
- frame = frame.parentFrame;
- if (frame == null) {
- break;
- }
- if (cjump2 != null && cjump2.branchFrame == frame) {
- // Continuation branch point was hit,
- // restart the state loop to reenter continuation
- indexReg = -1;
-
- goto StateLoop;
- }
- }
-
- // No more frames, rethrow the exception or deal with continuation
- if (cjump2 != null) {
- if (cjump2.branchFrame != null) {
- // The above loop should locate the top frame
- Context.CodeBug ();
- }
- if (cjump2.capturedFrame != null) {
- // Restarting detached continuation
- indexReg = -1;
-
- goto StateLoop;
- }
- // Return continuation result to the caller
- interpreterResult = cjump2.result;
- interpreterResultDbl = cjump2.resultDbl;
- throwable = null;
- }
-
- goto StateLoop_brk;
-
- StateLoop:
- ;
- }
-
- StateLoop_brk:
- ;
- // end of StateLoop: for(;;)
-
- // Do cleanups/restorations before the final return or throw
-
- if (cx.previousInterpreterInvocations != null && cx.previousInterpreterInvocations.size () != 0) {
- cx.lastInterpreterFrame = cx.previousInterpreterInvocations.pop ();
- }
- else {
- // It was the last interpreter frame on the stack
- cx.lastInterpreterFrame = null;
- // Force GC of the value cx.previousInterpreterInvocations
- cx.previousInterpreterInvocations = null;
- }
-
- if (throwable != null) {
- if (throwable is Helpers.StackOverflowVerifierException) {
- throw Context.ReportRuntimeError (
- ScriptRuntime.GetMessage ("mag.too.deep.parser.recursion"));
- }
- throw (Exception)throwable;
- }
-
- return (interpreterResult != DBL_MRK) ? interpreterResult :
- interpreterResultDbl;
- }
-
- static void initFrame (Context cx, IScriptable callerScope, IScriptable thisObj, object [] args, double [] argsDbl, int argShift, int argCount, InterpretedFunction fnOrScript, CallFrame parentFrame, CallFrame frame)
- {
- InterpreterData idata = fnOrScript.idata;
-
- bool useActivation = idata.itsNeedsActivation;
- DebugFrame debuggerFrame = null;
- if (cx.m_Debugger != null) {
- debuggerFrame = cx.m_Debugger.GetFrame (cx, idata);
- if (debuggerFrame != null) {
- useActivation = true;
- }
- }
-
- if (useActivation) {
- // Copy args to new array to pass to enterActivationFunction
- // or debuggerFrame.onEnter
- if (argsDbl != null) {
- args = GetArgsArray (args, argsDbl, argShift, argCount);
- }
- argShift = 0;
- argsDbl = null;
- }
-
- IScriptable scope;
- if (idata.itsFunctionType != 0) {
- if (!idata.useDynamicScope) {
- scope = fnOrScript.ParentScope;
- }
- else {
- scope = callerScope;
- }
-
- if (useActivation) {
- scope = ScriptRuntime.createFunctionActivation (fnOrScript, scope, args);
- }
- }
- else {
- scope = callerScope;
- ScriptRuntime.initScript (fnOrScript, thisObj, cx, scope, fnOrScript.idata.evalScriptFlag);
- }
-
- if (idata.itsNestedFunctions != null) {
- if (idata.itsFunctionType != 0 && !idata.itsNeedsActivation)
- Context.CodeBug ();
- for (int i = 0; i < idata.itsNestedFunctions.Length; i++) {
- InterpreterData fdata = idata.itsNestedFunctions [i];
- if (fdata.itsFunctionType == FunctionNode.FUNCTION_STATEMENT) {
- initFunction (cx, scope, fnOrScript, i);
- }
- }
- }
-
- IScriptable [] scriptRegExps = null;
- if (idata.itsRegExpLiterals != null) {
- // Wrapped regexps for functions are stored in
- // InterpretedFunction
- // but for script which should not contain references to scope
- // the regexps re-wrapped during each script execution
- if (idata.itsFunctionType != 0) {
- scriptRegExps = fnOrScript.functionRegExps;
- }
- else {
- scriptRegExps = fnOrScript.createRegExpWraps (cx, scope);
- }
- }
-
- // Initialize args, vars, locals and stack
-
- int emptyStackTop = idata.itsMaxVars + idata.itsMaxLocals - 1;
- int maxFrameArray = idata.itsMaxFrameArray;
- if (maxFrameArray != emptyStackTop + idata.itsMaxStack + 1)
- Context.CodeBug ();
-
- object [] stack;
- double [] sDbl;
- bool stackReuse;
- if (frame.stack != null && maxFrameArray <= frame.stack.Length) {
- // Reuse stacks from old frame
- stackReuse = true;
- stack = frame.stack;
- sDbl = frame.sDbl;
- }
- else {
- stackReuse = false;
- stack = new object [maxFrameArray];
- sDbl = new double [maxFrameArray];
- }
-
- int definedArgs = idata.argCount;
- if (definedArgs > argCount) {
- definedArgs = argCount;
- }
-
- // Fill the frame structure
-
- frame.parentFrame = parentFrame;
- frame.frameIndex = (parentFrame == null) ? 0 : parentFrame.frameIndex + 1;
- if (frame.frameIndex > cx.MaximumInterpreterStackDepth)
- throw ScriptRuntime.TypeErrorById ("msg.stackoverflow");
- frame.frozen = false;
-
- frame.fnOrScript = fnOrScript;
- frame.idata = idata;
-
- frame.stack = stack;
- frame.sDbl = sDbl;
- frame.varSource = frame;
- frame.localShift = idata.itsMaxVars;
- frame.emptyStackTop = emptyStackTop;
-
- frame.debuggerFrame = debuggerFrame;
- frame.useActivation = useActivation;
-
- frame.thisObj = thisObj;
- frame.scriptRegExps = scriptRegExps;
-
- // Initialize initial values of variables that change during
- // interpretation.
- frame.result = Undefined.Value;
- frame.pc = 0;
- frame.pcPrevBranch = 0;
- frame.pcSourceLineStart = idata.firstLinePC;
- frame.scope = scope;
-
- frame.savedStackTop = emptyStackTop;
- frame.savedCallOp = 0;
-
- Array.Copy (args, argShift, stack, 0, definedArgs);
- if (argsDbl != null) {
- Array.Copy (argsDbl, argShift, sDbl, 0, definedArgs);
- }
- for (int i = definedArgs; i != idata.itsMaxVars; ++i) {
- stack [i] = Undefined.Value;
- }
- if (stackReuse) {
- // Clean the stack part and space beyond stack if any
- // of the old array to allow to GC objects there
- for (int i = emptyStackTop + 1; i != stack.Length; ++i) {
- stack [i] = null;
- }
- }
-
- EnterFrame (cx, frame, args);
- }
-
- static bool isFrameEnterExitRequired (CallFrame frame)
- {
- return frame.debuggerFrame != null || frame.idata.itsNeedsActivation;
- }
-
- static void EnterFrame (Context cx, CallFrame frame, object [] args)
- {
- if (frame.debuggerFrame != null) {
- frame.debuggerFrame.OnEnter (cx, frame.scope, frame.thisObj, args);
- }
- if (frame.idata.itsNeedsActivation) {
- // Enter activation only when itsNeedsActivation true, not when
- // useActivation holds since debugger should not interfere
- // with activation chaining
- ScriptRuntime.enterActivationFunction (cx, frame.scope);
- }
- }
-
- static void ExitFrame (Context cx, CallFrame frame, object throwable)
- {
- if (frame.idata.itsNeedsActivation) {
- ScriptRuntime.exitActivationFunction (cx);
- }
-
- if (frame.debuggerFrame != null) {
- try {
- if (throwable is Exception) {
- frame.debuggerFrame.OnExit (cx, true, throwable);
- }
- else {
- object result;
- ContinuationJump cjump = (ContinuationJump)throwable;
- if (cjump == null) {
- result = frame.result;
- }
- else {
- result = cjump.result;
- }
- if (result == UniqueTag.DoubleMark) {
- double resultDbl;
- if (cjump == null) {
- resultDbl = frame.resultDbl;
- }
- else {
- resultDbl = cjump.resultDbl;
- }
- result = resultDbl;
- }
- frame.debuggerFrame.OnExit (cx, false, result);
- }
- }
- catch (Exception ex) {
- Console.Error.WriteLine ("USAGE WARNING: onExit terminated with exception");
- Console.Error.WriteLine (ex.ToString ());
- }
- }
- }
-
- static void setCallResult (CallFrame frame, object callResult, double callResultDbl)
- {
- if (frame.savedCallOp == Token.CALL) {
- frame.stack [frame.savedStackTop] = callResult;
- frame.sDbl [frame.savedStackTop] = callResultDbl;
- }
- else if (frame.savedCallOp == Token.NEW) {
- // If construct returns scriptable,
- // then it replaces on stack top saved original instance
- // of the object.
- if (callResult is IScriptable) {
- frame.stack [frame.savedStackTop] = callResult;
- }
- }
- else {
- Context.CodeBug ();
- }
- frame.savedCallOp = 0;
- }
-
- static void captureContinuation (Context cx, CallFrame frame, int stackTop)
- {
- Continuation c = new Continuation ();
- ScriptRuntime.setObjectProtoAndParent (c, ScriptRuntime.getTopCallScope (cx));
-
- // Make sure that all frames upstack frames are frozen
- CallFrame x = frame.parentFrame;
- while (x != null && !x.frozen) {
- x.frozen = true;
- // Allow to GC unused stack space
- for (int i = x.savedStackTop + 1; i != x.stack.Length; ++i) {
- // Allow to GC unused stack space
- x.stack [i] = null;
- }
- if (x.savedCallOp == Token.CALL) {
- // the call will always overwrite the stack top with the result
- x.stack [x.savedStackTop] = null;
- }
- else {
- if (x.savedCallOp != Token.NEW)
- Context.CodeBug ();
- // the new operator uses stack top to store the constructed
- // object so it shall not be cleared: see comments in
- // setCallResult
- }
- x = x.parentFrame;
- }
-
- c.initImplementation (frame.parentFrame);
- frame.stack [stackTop] = c;
- }
-
- static int stack_int32 (CallFrame frame, int i)
- {
- object x = frame.stack [i];
- double value;
- if (x == UniqueTag.DoubleMark) {
- value = frame.sDbl [i];
- }
- else {
- value = ScriptConvert.ToNumber (x);
- }
- return ScriptConvert.ToInt32 (value);
- }
-
- static double stack_double (CallFrame frame, int i)
- {
- object x = frame.stack [i];
- if (x != UniqueTag.DoubleMark) {
- return ScriptConvert.ToNumber (x);
- }
- else {
- return frame.sDbl [i];
- }
- }
-
- static bool stack_boolean (CallFrame frame, int i)
- {
- object x = frame.stack [i];
- if (x is bool) {
- return (bool)x;
- }
- else if (x == UniqueTag.DoubleMark) {
- double d = frame.sDbl [i];
- return !double.IsNaN (d) && d != 0.0;
- }
- else if (x == null || x == Undefined.Value) {
- return false;
- }
- else if (CliHelper.IsNumber (x)) {
- double d = Convert.ToDouble (x);
- return (!double.IsNaN (d) && d != 0.0);
- }
- else {
- return ScriptConvert.ToBoolean (x);
- }
- }
-
- static void DoAdd (object [] stack, double [] sDbl, int stackTop, Context cx)
- {
- object rhs = stack [stackTop + 1];
- object lhs = stack [stackTop];
- double d;
- bool leftRightOrder;
- if (rhs == UniqueTag.DoubleMark) {
- d = sDbl [stackTop + 1];
- if (lhs == UniqueTag.DoubleMark) {
- sDbl [stackTop] += d;
- return;
- }
- leftRightOrder = true;
- // fallthrough to object + number code
- }
- else if (lhs == UniqueTag.DoubleMark) {
- d = sDbl [stackTop];
- lhs = rhs;
- leftRightOrder = false;
- // fallthrough to object + number code
- }
- else {
- if (lhs is IScriptable || rhs is IScriptable) {
- stack [stackTop] = ScriptRuntime.Add (lhs, rhs, cx);
- }
- else if (lhs is string) {
- string lstr = (string)lhs;
- string rstr = ScriptConvert.ToString (rhs);
- stack [stackTop] = string.Concat (lstr, rstr);
- }
- else if (rhs is string) {
- string lstr = ScriptConvert.ToString (lhs);
- string rstr = (string)rhs;
- stack [stackTop] = string.Concat (lstr, rstr);
- }
- else {
- double lDbl = (CliHelper.IsNumber (lhs)) ? Convert.ToDouble (lhs) : ScriptConvert.ToNumber (lhs);
- double rDbl = (CliHelper.IsNumber (rhs)) ? Convert.ToDouble (rhs) : ScriptConvert.ToNumber (rhs);
- stack [stackTop] = UniqueTag.DoubleMark;
- sDbl [stackTop] = lDbl + rDbl;
- }
- return;
- }
-
- // handle object(lhs) + number(d) code
- if (lhs is IScriptable) {
- rhs = d;
- if (!leftRightOrder) {
- object tmp = lhs;
- lhs = rhs;
- rhs = tmp;
- }
- stack [stackTop] = ScriptRuntime.Add (lhs, rhs, cx);
- }
- else if (lhs is string) {
- string lstr = (string)lhs;
- string rstr = ScriptConvert.ToString (d);
- if (leftRightOrder) {
- stack [stackTop] = string.Concat (lstr, rstr);
- }
- else {
- stack [stackTop] = string.Concat (rstr, lstr);
- }
- }
- else {
- double lDbl = (CliHelper.IsNumber (lhs)) ? Convert.ToDouble (lhs) : ScriptConvert.ToNumber (lhs);
- stack [stackTop] = UniqueTag.DoubleMark;
- sDbl [stackTop] = lDbl + d;
- }
- }
-
- void addGotoOp (int gotoOp)
- {
- sbyte [] array = itsData.itsICode;
- int top = itsICodeTop;
- if (top + 3 > array.Length) {
- array = increaseICodeCapasity (3);
- }
- array [top] = (sbyte)gotoOp;
- // Offset would written later
- itsICodeTop = top + 1 + 2;
- }
-
-
- static object [] GetArgsArray (object [] stack, double [] sDbl, int shift, int count)
- {
- if (count == 0) {
- return ScriptRuntime.EmptyArgs;
- }
- object [] args = new object [count];
- for (int i = 0; i != count; ++i, ++shift) {
- object val = stack [shift];
- if (val == UniqueTag.DoubleMark) {
- val = sDbl [shift];
- }
- args [i] = val;
- }
- return args;
- }
-
- static void addInstructionCount (Context cx, CallFrame frame, int extra)
- {
- cx.instructionCount += frame.pc - frame.pcPrevBranch + extra;
- if (cx.instructionCount > cx.instructionThreshold) {
- cx.ObserveInstructionCount (cx.instructionCount);
- cx.instructionCount = 0;
- }
- }
-
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+using EcmaScript.NET.Debugging;
+using EcmaScript.NET.Collections;
+
+namespace EcmaScript.NET
+{
+
+ public class Interpreter
+ {
+
+ // Additional interpreter-specific codes
+
+ const int Icode_DUP = -1;
+ const int Icode_DUP2 = -2;
+ const int Icode_SWAP = -3;
+ const int Icode_POP = -4;
+ const int Icode_POP_RESULT = -5;
+ const int Icode_IFEQ_POP = -6;
+ const int Icode_VAR_INC_DEC = -7;
+ const int Icode_NAME_INC_DEC = -8;
+ const int Icode_PROP_INC_DEC = -9;
+ const int Icode_ELEM_INC_DEC = -10;
+ const int Icode_REF_INC_DEC = -11;
+ const int Icode_SCOPE_LOAD = -12;
+ const int Icode_SCOPE_SAVE = -13;
+ const int Icode_TYPEOFNAME = -14;
+ const int Icode_NAME_AND_THIS = -15;
+ const int Icode_PROP_AND_THIS = -16;
+ const int Icode_ELEM_AND_THIS = -17;
+ const int Icode_VALUE_AND_THIS = -18;
+ const int Icode_CLOSURE_EXPR = -19;
+ const int Icode_CLOSURE_STMT = -20;
+ const int Icode_CALLSPECIAL = -21;
+ const int Icode_RETUNDEF = -22;
+ const int Icode_GOSUB = -23;
+ const int Icode_STARTSUB = -24;
+ const int Icode_RETSUB = -25;
+ const int Icode_LINE = -26;
+ const int Icode_SHORTNUMBER = -27;
+ const int Icode_INTNUMBER = -28;
+ const int Icode_LITERAL_NEW = -29;
+ const int Icode_LITERAL_SET = -30;
+ const int Icode_SPARE_ARRAYLIT = -31;
+ const int Icode_REG_IND_C0 = -32;
+ const int Icode_REG_IND_C1 = -33;
+ const int Icode_REG_IND_C2 = -34;
+ const int Icode_REG_IND_C3 = -35;
+ const int Icode_REG_IND_C4 = -36;
+ const int Icode_REG_IND_C5 = -37;
+ const int Icode_REG_IND1 = -38;
+ const int Icode_REG_IND2 = -39;
+ const int Icode_REG_IND4 = -40;
+ const int Icode_REG_STR_C0 = -41;
+ const int Icode_REG_STR_C1 = -42;
+ const int Icode_REG_STR_C2 = -43;
+ const int Icode_REG_STR_C3 = -44;
+ const int Icode_REG_STR1 = -45;
+ const int Icode_REG_STR2 = -46;
+ const int Icode_REG_STR4 = -47;
+ const int Icode_GETVAR1 = -48;
+ const int Icode_SETVAR1 = -49;
+ const int Icode_UNDEF = -50;
+ const int Icode_ZERO = -51;
+ const int Icode_ONE = -52;
+ const int Icode_ENTERDQ = -53;
+ const int Icode_LEAVEDQ = -54;
+ const int Icode_TAIL_CALL = -55;
+ const int Icode_LOCAL_CLEAR = -56;
+ const int Icode_DEBUGGER = -57;
+
+ // Last icode
+ const int MIN_ICODE = -57;
+
+
+ // data for parsing
+
+ CompilerEnvirons compilerEnv;
+
+ bool itsInFunctionFlag;
+
+ InterpreterData itsData;
+ ScriptOrFnNode scriptOrFn;
+ int itsICodeTop;
+ int itsStackDepth;
+ int itsLineNumber;
+ int itsDoubleTableTop;
+ ObjToIntMap itsStrings = new ObjToIntMap (20);
+ int itsLocalTop;
+
+ const int MIN_LABEL_TABLE_SIZE = 32;
+ const int MIN_FIXUP_TABLE_SIZE = 40;
+ int [] itsLabelTable;
+ int itsLabelTableTop;
+ // itsFixupTable[i] = (label_index << 32) | fixup_site
+ long [] itsFixupTable;
+ int itsFixupTableTop;
+ ObjArray itsLiteralIds = new ObjArray ();
+
+ int itsExceptionTableTop;
+ const int EXCEPTION_TRY_START_SLOT = 0;
+ const int EXCEPTION_TRY_END_SLOT = 1;
+ const int EXCEPTION_HANDLER_SLOT = 2;
+ const int EXCEPTION_TYPE_SLOT = 3;
+ const int EXCEPTION_LOCAL_SLOT = 4;
+ const int EXCEPTION_SCOPE_SLOT = 5;
+ // SLOT_SIZE: space for try start/end, handler, start, handler type,
+ // exception local and scope local
+ const int EXCEPTION_SLOT_SIZE = 6;
+
+ // ECF_ or Expression Context Flags constants: for now only TAIL is available
+ const int ECF_TAIL = 1 << 0;
+
+
+ internal class CallFrame : System.ICloneable
+ {
+
+ internal CallFrame parentFrame;
+ // amount of stack frames before this one on the interpretation stack
+ internal int frameIndex;
+ // If true indicates read-only frame that is a part of continuation
+ internal bool frozen;
+
+ internal InterpretedFunction fnOrScript;
+ internal InterpreterData idata;
+
+ // Stack structure
+ // stack[0 <= i < localShift]: arguments and local variables
+ // stack[localShift <= i <= emptyStackTop]: used for local temporaries
+ // stack[emptyStackTop < i < stack.length]: stack data
+ // sDbl[i]: if stack[i] is UniqueTag.DoubleMark, sDbl[i] holds the number value
+
+ internal object [] stack;
+ internal double [] sDbl;
+
+ internal CallFrame varSource; // defaults to this unless continuation frame
+ internal int localShift;
+ internal int emptyStackTop;
+
+ internal DebugFrame debuggerFrame;
+ internal bool useActivation;
+
+ internal IScriptable thisObj;
+ internal IScriptable [] scriptRegExps;
+
+ // The values that change during interpretation
+
+ internal object result;
+ internal double resultDbl;
+ internal int pc;
+ internal int pcPrevBranch;
+ internal int pcSourceLineStart;
+ internal IScriptable scope;
+
+ internal int savedStackTop;
+ internal int savedCallOp;
+
+ internal virtual CallFrame cloneFrozen ()
+ {
+ if (!frozen)
+ Context.CodeBug ();
+
+ CallFrame copy = (CallFrame)Clone ();
+
+ // clone stack but keep varSource to point to values
+ // from this frame to share variables.
+
+ // TODO: STACK
+ copy.stack = new object [stack.Length];
+ stack.CopyTo (copy.stack, 0);
+ copy.sDbl = new double [sDbl.Length];
+ sDbl.CopyTo (copy.sDbl, 0);
+
+ copy.frozen = false;
+ return copy;
+ }
+
+ virtual public object Clone ()
+ {
+ return base.MemberwiseClone ();
+ }
+ }
+
+
+ sealed class ContinuationJump
+ {
+
+ internal CallFrame capturedFrame;
+ internal CallFrame branchFrame;
+ internal object result;
+ internal double resultDbl;
+
+ internal ContinuationJump (Continuation c, CallFrame current)
+ {
+ this.capturedFrame = (CallFrame)c.Implementation;
+ if (this.capturedFrame == null || current == null) {
+ // Continuation and current execution does not share
+ // any frames if there is nothing to capture or
+ // if there is no currently executed frames
+ this.branchFrame = null;
+ }
+ else {
+ // Search for branch frame where parent frame chains starting
+ // from captured and current meet.
+ CallFrame chain1 = this.capturedFrame;
+ CallFrame chain2 = current;
+
+ // First work parents of chain1 or chain2 until the same
+ // frame depth.
+ int diff = chain1.frameIndex - chain2.frameIndex;
+ if (diff != 0) {
+ if (diff < 0) {
+ // swap to make sure that
+ // chain1.frameIndex > chain2.frameIndex and diff > 0
+ chain1 = current;
+ chain2 = this.capturedFrame;
+ diff = -diff;
+ }
+ do {
+ chain1 = chain1.parentFrame;
+ }
+ while (--diff != 0);
+ if (chain1.frameIndex != chain2.frameIndex)
+ Context.CodeBug ();
+ }
+
+ // Now walk parents in parallel until a shared frame is found
+ // or until the root is reached.
+ while (chain1 != chain2 && chain1 != null) {
+ chain1 = chain1.parentFrame;
+ chain2 = chain2.parentFrame;
+ }
+
+ this.branchFrame = chain1;
+ if (this.branchFrame != null && !this.branchFrame.frozen)
+ Context.CodeBug ();
+ }
+ }
+ }
+
+ static string bytecodeName (int bytecode)
+ {
+ if (!validBytecode (bytecode)) {
+ throw new ArgumentException (Convert.ToString (bytecode));
+ }
+
+ if (!Token.printICode) {
+ return Convert.ToString (bytecode);
+ }
+
+ if (ValidTokenCode (bytecode)) {
+ return Token.name (bytecode);
+ }
+
+ switch (bytecode) {
+
+ case Icode_DUP:
+ return "DUP";
+
+ case Icode_DUP2:
+ return "DUP2";
+
+ case Icode_SWAP:
+ return "SWAP";
+
+ case Icode_POP:
+ return "POP";
+
+ case Icode_POP_RESULT:
+ return "POP_RESULT";
+
+ case Icode_IFEQ_POP:
+ return "IFEQ_POP";
+
+ case Icode_VAR_INC_DEC:
+ return "VAR_INC_DEC";
+
+ case Icode_NAME_INC_DEC:
+ return "NAME_INC_DEC";
+
+ case Icode_PROP_INC_DEC:
+ return "PROP_INC_DEC";
+
+ case Icode_ELEM_INC_DEC:
+ return "ELEM_INC_DEC";
+
+ case Icode_REF_INC_DEC:
+ return "REF_INC_DEC";
+
+ case Icode_SCOPE_LOAD:
+ return "SCOPE_LOAD";
+
+ case Icode_SCOPE_SAVE:
+ return "SCOPE_SAVE";
+
+ case Icode_TYPEOFNAME:
+ return "TYPEOFNAME";
+
+ case Icode_NAME_AND_THIS:
+ return "NAME_AND_THIS";
+
+ case Icode_PROP_AND_THIS:
+ return "PROP_AND_THIS";
+
+ case Icode_ELEM_AND_THIS:
+ return "ELEM_AND_THIS";
+
+ case Icode_VALUE_AND_THIS:
+ return "VALUE_AND_THIS";
+
+ case Icode_CLOSURE_EXPR:
+ return "CLOSURE_EXPR";
+
+ case Icode_CLOSURE_STMT:
+ return "CLOSURE_STMT";
+
+ case Icode_CALLSPECIAL:
+ return "CALLSPECIAL";
+
+ case Icode_RETUNDEF:
+ return "RETUNDEF";
+
+ case Icode_GOSUB:
+ return "GOSUB";
+
+ case Icode_STARTSUB:
+ return "STARTSUB";
+
+ case Icode_RETSUB:
+ return "RETSUB";
+
+ case Icode_LINE:
+ return "LINE";
+
+ case Icode_SHORTNUMBER:
+ return "SHORTNUMBER";
+
+ case Icode_INTNUMBER:
+ return "INTNUMBER";
+
+ case Icode_LITERAL_NEW:
+ return "LITERAL_NEW";
+
+ case Icode_LITERAL_SET:
+ return "LITERAL_SET";
+
+ case Icode_SPARE_ARRAYLIT:
+ return "SPARE_ARRAYLIT";
+
+ case Icode_REG_IND_C0:
+ return "REG_IND_C0";
+
+ case Icode_REG_IND_C1:
+ return "REG_IND_C1";
+
+ case Icode_REG_IND_C2:
+ return "REG_IND_C2";
+
+ case Icode_REG_IND_C3:
+ return "REG_IND_C3";
+
+ case Icode_REG_IND_C4:
+ return "REG_IND_C4";
+
+ case Icode_REG_IND_C5:
+ return "REG_IND_C5";
+
+ case Icode_REG_IND1:
+ return "LOAD_IND1";
+
+ case Icode_REG_IND2:
+ return "LOAD_IND2";
+
+ case Icode_REG_IND4:
+ return "LOAD_IND4";
+
+ case Icode_REG_STR_C0:
+ return "REG_STR_C0";
+
+ case Icode_REG_STR_C1:
+ return "REG_STR_C1";
+
+ case Icode_REG_STR_C2:
+ return "REG_STR_C2";
+
+ case Icode_REG_STR_C3:
+ return "REG_STR_C3";
+
+ case Icode_REG_STR1:
+ return "LOAD_STR1";
+
+ case Icode_REG_STR2:
+ return "LOAD_STR2";
+
+ case Icode_REG_STR4:
+ return "LOAD_STR4";
+
+ case Icode_GETVAR1:
+ return "GETVAR1";
+
+ case Icode_SETVAR1:
+ return "SETVAR1";
+
+ case Icode_UNDEF:
+ return "UNDEF";
+
+ case Icode_ZERO:
+ return "ZERO";
+
+ case Icode_ONE:
+ return "ONE";
+
+ case Icode_ENTERDQ:
+ return "ENTERDQ";
+
+ case Icode_LEAVEDQ:
+ return "LEAVEDQ";
+
+ case Icode_TAIL_CALL:
+ return "TAIL_CALL";
+
+ case Icode_LOCAL_CLEAR:
+ return "LOCAL_CLEAR";
+
+ case Icode_DEBUGGER:
+ return "DEBUGGER";
+ }
+
+ // icode without name
+ throw new Exception (Convert.ToString (bytecode));
+ }
+
+ static bool validIcode (int icode)
+ {
+ return MIN_ICODE <= icode && icode <= -1;
+ }
+
+ static bool ValidTokenCode (int token)
+ {
+ return Token.FIRST_BYTECODE_TOKEN <= token && token <= Token.LAST_BYTECODE_TOKEN;
+ }
+
+ static bool validBytecode (int bytecode)
+ {
+ return validIcode (bytecode) || ValidTokenCode (bytecode);
+ }
+
+ public virtual object Compile (CompilerEnvirons compilerEnv, ScriptOrFnNode tree, string encodedSource, bool returnFunction)
+ {
+ this.compilerEnv = compilerEnv;
+ new NodeTransformer ().transform (tree);
+
+ if (Token.printTrees) {
+ System.Console.Out.WriteLine (tree.toStringTree (tree));
+ }
+
+ if (returnFunction) {
+ tree = tree.getFunctionNode (0);
+ }
+
+ scriptOrFn = tree;
+ itsData = new InterpreterData (compilerEnv.LanguageVersion, scriptOrFn.SourceName, encodedSource);
+ itsData.topLevel = true;
+
+ if (returnFunction) {
+ generateFunctionICode ();
+ }
+ else {
+ generateICodeFromTree (scriptOrFn);
+ }
+
+ return itsData;
+ }
+
+ public virtual IScript CreateScriptObject (object bytecode, object staticSecurityDomain)
+ {
+ InterpreterData idata = (InterpreterData)bytecode;
+ return InterpretedFunction.createScript (itsData, staticSecurityDomain);
+ }
+
+ public virtual IFunction CreateFunctionObject (Context cx, IScriptable scope, object bytecode, object staticSecurityDomain)
+ {
+ InterpreterData idata = (InterpreterData)bytecode;
+ return InterpretedFunction.createFunction (cx, scope, itsData, staticSecurityDomain);
+ }
+
+ void generateFunctionICode ()
+ {
+ itsInFunctionFlag = true;
+
+ FunctionNode theFunction = (FunctionNode)scriptOrFn;
+
+ itsData.itsFunctionType = theFunction.FunctionType;
+ itsData.itsNeedsActivation = theFunction.RequiresActivation;
+ itsData.itsName = theFunction.FunctionName;
+ if (!theFunction.IgnoreDynamicScope) {
+ if (compilerEnv.UseDynamicScope) {
+ itsData.useDynamicScope = true;
+ }
+ }
+
+ generateICodeFromTree (theFunction.LastChild);
+ }
+
+ void generateICodeFromTree (Node tree)
+ {
+ generateNestedFunctions ();
+
+ generateRegExpLiterals ();
+
+ VisitStatement (tree);
+ fixLabelGotos ();
+ // add RETURN_RESULT only to scripts as function always ends with RETURN
+ if (itsData.itsFunctionType == 0) {
+ addToken (Token.RETURN_RESULT);
+ }
+
+ if (itsData.itsICode.Length != itsICodeTop) {
+ // Make itsData.itsICode length exactly itsICodeTop to save memory
+ // and catch bugs with jumps beyound icode as early as possible
+ sbyte [] tmp = new sbyte [itsICodeTop];
+ Array.Copy (itsData.itsICode, 0, tmp, 0, itsICodeTop);
+ itsData.itsICode = tmp;
+ }
+ if (itsStrings.size () == 0) {
+ itsData.itsStringTable = null;
+ }
+ else {
+ itsData.itsStringTable = new string [itsStrings.size ()];
+ ObjToIntMap.Iterator iter = itsStrings.newIterator ();
+ for (iter.start (); !iter.done (); iter.next ()) {
+ string str = (string)iter.Key;
+ int index = iter.Value;
+ if (itsData.itsStringTable [index] != null)
+ Context.CodeBug ();
+ itsData.itsStringTable [index] = str;
+ }
+ }
+ if (itsDoubleTableTop == 0) {
+ itsData.itsDoubleTable = null;
+ }
+ else if (itsData.itsDoubleTable.Length != itsDoubleTableTop) {
+ double [] tmp = new double [itsDoubleTableTop];
+ Array.Copy (itsData.itsDoubleTable, 0, tmp, 0, itsDoubleTableTop);
+ itsData.itsDoubleTable = tmp;
+ }
+ if (itsExceptionTableTop != 0 && itsData.itsExceptionTable.Length != itsExceptionTableTop) {
+ int [] tmp = new int [itsExceptionTableTop];
+ Array.Copy (itsData.itsExceptionTable, 0, tmp, 0, itsExceptionTableTop);
+ itsData.itsExceptionTable = tmp;
+ }
+
+ itsData.itsMaxVars = scriptOrFn.ParamAndVarCount;
+ // itsMaxFrameArray: interpret method needs this amount for its
+ // stack and sDbl arrays
+ itsData.itsMaxFrameArray = itsData.itsMaxVars + itsData.itsMaxLocals + itsData.itsMaxStack;
+
+ itsData.argNames = scriptOrFn.ParamAndVarNames;
+ itsData.argCount = scriptOrFn.ParamCount;
+
+ itsData.encodedSourceStart = scriptOrFn.EncodedSourceStart;
+ itsData.encodedSourceEnd = scriptOrFn.EncodedSourceEnd;
+
+ if (itsLiteralIds.size () != 0) {
+ itsData.literalIds = itsLiteralIds.ToArray ();
+ }
+
+ if (Token.printICode)
+ dumpICode (itsData);
+ }
+
+ void generateNestedFunctions ()
+ {
+ int functionCount = scriptOrFn.FunctionCount;
+ if (functionCount == 0)
+ return;
+
+ InterpreterData [] array = new InterpreterData [functionCount];
+ for (int i = 0; i != functionCount; i++) {
+ FunctionNode def = scriptOrFn.getFunctionNode (i);
+ Interpreter jsi = new Interpreter ();
+ jsi.compilerEnv = compilerEnv;
+ jsi.scriptOrFn = def;
+ jsi.itsData = new InterpreterData (itsData);
+ jsi.generateFunctionICode ();
+ array [i] = jsi.itsData;
+ }
+ itsData.itsNestedFunctions = array;
+ }
+
+ void generateRegExpLiterals ()
+ {
+ int N = scriptOrFn.RegexpCount;
+ if (N == 0)
+ return;
+
+ Context cx = Context.CurrentContext;
+ RegExpProxy rep = cx.RegExpProxy;
+ object [] array = new object [N];
+ for (int i = 0; i != N; i++) {
+ string str = scriptOrFn.getRegexpString (i);
+ string flags = scriptOrFn.getRegexpFlags (i);
+ array [i] = rep.Compile (cx, str, flags);
+ }
+ itsData.itsRegExpLiterals = array;
+ }
+
+ void updateLineNumber (Node node)
+ {
+ int lineno = node.Lineno;
+ if (lineno != itsLineNumber && lineno >= 0) {
+ if (itsData.firstLinePC < 0) {
+ itsData.firstLinePC = lineno;
+ }
+ itsLineNumber = lineno;
+ addIcode (Icode_LINE);
+ addUint16 (lineno & 0xFFFF);
+ }
+ }
+
+ Exception badTree (Node node)
+ {
+ throw new Exception (node.ToString ());
+ }
+
+ void VisitStatement (Node node)
+ {
+ int type = node.Type;
+ Node child = node.FirstChild;
+ switch (type) {
+
+
+ case Token.FUNCTION: {
+ int fnIndex = node.getExistingIntProp (Node.FUNCTION_PROP);
+ int fnType = scriptOrFn.getFunctionNode (fnIndex).FunctionType;
+ // Only function expressions or function expression
+ // statements needs closure code creating new function
+ // object on stack as function statements are initialized
+ // at script/function start
+ // In addition function expression can not present here
+ // at statement level, they must only present as expressions.
+ if (fnType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) {
+ addIndexOp (Icode_CLOSURE_STMT, fnIndex);
+ }
+ else {
+ if (fnType != FunctionNode.FUNCTION_STATEMENT) {
+ throw Context.CodeBug ();
+ }
+ }
+ }
+ break;
+
+
+ case Token.SCRIPT:
+ case Token.LABEL:
+ case Token.LOOP:
+ case Token.BLOCK:
+ case Token.EMPTY:
+ case Token.WITH:
+ updateLineNumber (node);
+ while (child != null) {
+ VisitStatement (child);
+ child = child.Next;
+ }
+ break;
+
+
+ case Token.ENTERWITH:
+ VisitExpression (child, 0);
+ addToken (Token.ENTERWITH);
+ stackChange (-1);
+ break;
+
+
+ case Token.LEAVEWITH:
+ addToken (Token.LEAVEWITH);
+ break;
+
+
+ case Token.LOCAL_BLOCK: {
+ int local = allocLocal ();
+ node.putIntProp (Node.LOCAL_PROP, local);
+ updateLineNumber (node);
+ while (child != null) {
+ VisitStatement (child);
+ child = child.Next;
+ }
+ addIndexOp (Icode_LOCAL_CLEAR, local);
+ releaseLocal (local);
+ }
+ break;
+
+ case Token.DEBUGGER:
+ updateLineNumber (node);
+ addIcode (Icode_DEBUGGER);
+ break;
+
+ case Token.SWITCH:
+ updateLineNumber (node); {
+ // See comments in IRFactory.createSwitch() for description
+ // of SWITCH node
+ Node switchNode = (Node.Jump)node;
+ VisitExpression (child, 0);
+ for (Node.Jump caseNode = (Node.Jump)child.Next; caseNode != null; caseNode = (Node.Jump)caseNode.Next) {
+ if (caseNode.Type != Token.CASE)
+ throw badTree (caseNode);
+ Node test = caseNode.FirstChild;
+ addIcode (Icode_DUP);
+ stackChange (1);
+ VisitExpression (test, 0);
+ addToken (Token.SHEQ);
+ stackChange (-1);
+ // If true, Icode_IFEQ_POP will jump and remove case
+ // value from stack
+ addGoto (caseNode.target, Icode_IFEQ_POP);
+ stackChange (-1);
+ }
+ addIcode (Icode_POP);
+ stackChange (-1);
+ }
+ break;
+
+
+ case Token.TARGET:
+ markTargetLabel (node);
+ break;
+
+
+ case Token.IFEQ:
+ case Token.IFNE: {
+ Node target = ((Node.Jump)node).target;
+ VisitExpression (child, 0);
+ addGoto (target, type);
+ stackChange (-1);
+ }
+ break;
+
+
+ case Token.GOTO: {
+ Node target = ((Node.Jump)node).target;
+ addGoto (target, type);
+ }
+ break;
+
+
+ case Token.JSR: {
+ Node target = ((Node.Jump)node).target;
+ addGoto (target, Icode_GOSUB);
+ }
+ break;
+
+
+ case Token.FINALLY: {
+ // Account for incomming GOTOSUB address
+ stackChange (1);
+ int finallyRegister = getLocalBlockRef (node);
+ addIndexOp (Icode_STARTSUB, finallyRegister);
+ stackChange (-1);
+ while (child != null) {
+ VisitStatement (child);
+ child = child.Next;
+ }
+ addIndexOp (Icode_RETSUB, finallyRegister);
+ }
+ break;
+
+
+ case Token.EXPR_VOID:
+ case Token.EXPR_RESULT:
+ updateLineNumber (node);
+ VisitExpression (child, 0);
+ addIcode ((type == Token.EXPR_VOID) ? Icode_POP : Icode_POP_RESULT);
+ stackChange (-1);
+ break;
+
+
+ case Token.TRY: {
+ Node.Jump tryNode = (Node.Jump)node;
+ int exceptionObjectLocal = getLocalBlockRef (tryNode);
+ int scopeLocal = allocLocal ();
+
+ addIndexOp (Icode_SCOPE_SAVE, scopeLocal);
+
+ int tryStart = itsICodeTop;
+ while (child != null) {
+ VisitStatement (child);
+ child = child.Next;
+ }
+
+ Node catchTarget = tryNode.target;
+ if (catchTarget != null) {
+ int catchStartPC = itsLabelTable [getTargetLabel (catchTarget)];
+ addExceptionHandler (tryStart, catchStartPC, catchStartPC, false, exceptionObjectLocal, scopeLocal);
+ }
+ Node finallyTarget = tryNode.Finally;
+ if (finallyTarget != null) {
+ int finallyStartPC = itsLabelTable [getTargetLabel (finallyTarget)];
+ addExceptionHandler (tryStart, finallyStartPC, finallyStartPC, true, exceptionObjectLocal, scopeLocal);
+ }
+
+ addIndexOp (Icode_LOCAL_CLEAR, scopeLocal);
+ releaseLocal (scopeLocal);
+ }
+ break;
+
+
+ case Token.CATCH_SCOPE: {
+ int localIndex = getLocalBlockRef (node);
+ int scopeIndex = node.getExistingIntProp (Node.CATCH_SCOPE_PROP);
+ string name = child.String;
+ child = child.Next;
+ VisitExpression (child, 0); // load expression object
+ addStringPrefix (name);
+ addIndexPrefix (localIndex);
+ addToken (Token.CATCH_SCOPE);
+ addUint8 (scopeIndex != 0 ? 1 : 0);
+ stackChange (-1);
+ }
+ break;
+
+
+ case Token.THROW:
+ updateLineNumber (node);
+ VisitExpression (child, 0);
+ addToken (Token.THROW);
+ addUint16 (itsLineNumber & 0xFFFF);
+ stackChange (-1);
+ break;
+
+
+ case Token.RETHROW:
+ updateLineNumber (node);
+ addIndexOp (Token.RETHROW, getLocalBlockRef (node));
+ break;
+
+
+ case Token.RETURN:
+ updateLineNumber (node);
+ if (child != null) {
+ VisitExpression (child, ECF_TAIL);
+ addToken (Token.RETURN);
+ stackChange (-1);
+ }
+ else {
+ addIcode (Icode_RETUNDEF);
+ }
+ break;
+
+
+ case Token.RETURN_RESULT:
+ updateLineNumber (node);
+ addToken (Token.RETURN_RESULT);
+ break;
+
+
+ case Token.ENUM_INIT_KEYS:
+ case Token.ENUM_INIT_VALUES:
+ VisitExpression (child, 0);
+ addIndexOp (type, getLocalBlockRef (node));
+ stackChange (-1);
+ break;
+
+
+ default:
+ throw badTree (node);
+
+ }
+
+ if (itsStackDepth != 0) {
+ throw Context.CodeBug ();
+ }
+ }
+
+ bool VisitExpressionOptimized (Node node, int contextFlags)
+ {
+ return false;
+#if FALKSE
+ if (node.Type == Token.ADD) {
+ Node next = node.Next;
+ if (next == null)
+ return false;
+ switch (next.Type) {
+ case Token.NAME:
+ case Token.STRING:
+ return true;
+ }
+ }
+ return false;
+#endif
+ }
+
+ void VisitExpression (Node node, int contextFlags)
+ {
+ if (VisitExpressionOptimized (node, contextFlags))
+ return;
+
+ int type = node.Type;
+ Node child = node.FirstChild;
+ int savedStackDepth = itsStackDepth;
+ switch (type) {
+
+
+ case Token.FUNCTION: {
+ int fnIndex = node.getExistingIntProp (Node.FUNCTION_PROP);
+ FunctionNode fn = scriptOrFn.getFunctionNode (fnIndex);
+
+ // See comments in visitStatement for Token.FUNCTION case
+ switch (fn.FunctionType) {
+ case FunctionNode.FUNCTION_EXPRESSION:
+ addIndexOp (Icode_CLOSURE_EXPR, fnIndex);
+ break;
+ default:
+ throw Context.CodeBug ();
+ }
+
+ stackChange (1);
+ }
+ break;
+
+
+ case Token.LOCAL_LOAD: {
+ int localIndex = getLocalBlockRef (node);
+ addIndexOp (Token.LOCAL_LOAD, localIndex);
+ stackChange (1);
+ }
+ break;
+
+
+ case Token.COMMA: {
+ Node lastChild = node.LastChild;
+ while (child != lastChild) {
+ VisitExpression (child, 0);
+ addIcode (Icode_POP);
+ stackChange (-1);
+ child = child.Next;
+ }
+ // Preserve tail context flag if any
+ VisitExpression (child, contextFlags & ECF_TAIL);
+ }
+ break;
+
+
+ case Token.USE_STACK:
+ // Indicates that stack was modified externally,
+ // like placed catch object
+ stackChange (1);
+ break;
+
+
+ case Token.REF_CALL:
+ case Token.CALL:
+ case Token.NEW: {
+ if (type == Token.NEW) {
+ VisitExpression (child, 0);
+ }
+ else {
+ generateCallFunAndThis (child);
+ }
+ int argCount = 0;
+ while ((child = child.Next) != null) {
+ VisitExpression (child, 0);
+ ++argCount;
+ }
+ int callType = node.getIntProp (Node.SPECIALCALL_PROP, Node.NON_SPECIALCALL);
+ if (callType != Node.NON_SPECIALCALL) {
+ // embed line number and source filename
+ addIndexOp (Icode_CALLSPECIAL, argCount);
+ addUint8 (callType);
+ addUint8 (type == Token.NEW ? 1 : 0);
+ addUint16 (itsLineNumber & 0xFFFF);
+ }
+ else {
+ if (type == Token.CALL) {
+ if ((contextFlags & ECF_TAIL) != 0) {
+ type = Icode_TAIL_CALL;
+ }
+ }
+ addIndexOp (type, argCount);
+ }
+ // adjust stack
+ if (type == Token.NEW) {
+ // new: f, args -> result
+ stackChange (-argCount);
+ }
+ else {
+ // call: f, thisObj, args -> result
+ // ref_call: f, thisObj, args -> ref
+ stackChange (-1 - argCount);
+ }
+ if (argCount > itsData.itsMaxCalleeArgs) {
+ itsData.itsMaxCalleeArgs = argCount;
+ }
+ }
+ break;
+
+
+ case Token.AND:
+ case Token.OR: {
+ VisitExpression (child, 0);
+ addIcode (Icode_DUP);
+ stackChange (1);
+ int afterSecondJumpStart = itsICodeTop;
+ int jump = (type == Token.AND) ? Token.IFNE : Token.IFEQ;
+ addGotoOp (jump);
+ stackChange (-1);
+ addIcode (Icode_POP);
+ stackChange (-1);
+ child = child.Next;
+ // Preserve tail context flag if any
+ VisitExpression (child, contextFlags & ECF_TAIL);
+ resolveForwardGoto (afterSecondJumpStart);
+ }
+ break;
+
+
+ case Token.HOOK: {
+ Node ifThen = child.Next;
+ Node ifElse = ifThen.Next;
+ VisitExpression (child, 0);
+ int elseJumpStart = itsICodeTop;
+ addGotoOp (Token.IFNE);
+ ;
+ stackChange (-1);
+ // Preserve tail context flag if any
+ VisitExpression (ifThen, contextFlags & ECF_TAIL);
+ int afterElseJumpStart = itsICodeTop;
+ addGotoOp (Token.GOTO);
+ resolveForwardGoto (elseJumpStart);
+ itsStackDepth = savedStackDepth;
+ // Preserve tail context flag if any
+ VisitExpression (ifElse, contextFlags & ECF_TAIL);
+ resolveForwardGoto (afterElseJumpStart);
+ }
+ break;
+
+
+ case Token.GETPROP:
+ VisitExpression (child, 0);
+ child = child.Next;
+ addStringOp (Token.GETPROP, child.String);
+ break;
+
+
+ case Token.ADD:
+ case Token.GETELEM:
+ case Token.DELPROP:
+ case Token.BITAND:
+ case Token.BITOR:
+ case Token.BITXOR:
+ case Token.LSH:
+ case Token.RSH:
+ case Token.URSH:
+ case Token.SUB:
+ case Token.MOD:
+ case Token.DIV:
+ case Token.MUL:
+ case Token.EQ:
+ case Token.NE:
+ case Token.SHEQ:
+ case Token.SHNE:
+ case Token.IN:
+ case Token.INSTANCEOF:
+ case Token.LE:
+ case Token.LT:
+ case Token.GE:
+ case Token.GT:
+ VisitExpression (child, 0);
+ VisitExpression (child.Next, 0);
+ addToken (type);
+ stackChange (-1);
+ break;
+
+
+ case Token.POS:
+ case Token.NEG:
+ case Token.NOT:
+ case Token.BITNOT:
+ case Token.TYPEOF:
+ case Token.VOID:
+ VisitExpression (child, 0);
+ if (type == Token.VOID) {
+ addIcode (Icode_POP);
+ addIcode (Icode_UNDEF);
+ }
+ else {
+ addToken (type);
+ }
+ break;
+
+
+ case Token.GET_REF:
+ case Token.DEL_REF:
+ VisitExpression (child, 0);
+ addToken (type);
+ break;
+
+
+ case Token.SETPROP:
+ case Token.SETPROP_OP:
+ case Token.SETPROP_GETTER:
+ case Token.SETPROP_SETTER:
+ {
+ VisitExpression (child, 0);
+ child = child.Next;
+ string property = child.String;
+ child = child.Next;
+ if (type == Token.SETPROP_OP) {
+ addIcode (Icode_DUP);
+ stackChange (1);
+ addStringOp (Token.GETPROP, property);
+ // Compensate for the following USE_STACK
+ stackChange (-1);
+ }
+ VisitExpression (child, 0);
+ addStringOp ((type == Token.SETPROP_OP) ? Token.SETPROP : type, property);
+ stackChange (-1);
+ }
+ break;
+
+
+ case Token.SETELEM:
+ case Token.SETELEM_OP:
+ VisitExpression (child, 0);
+ child = child.Next;
+ VisitExpression (child, 0);
+ child = child.Next;
+ if (type == Token.SETELEM_OP) {
+ addIcode (Icode_DUP2);
+ stackChange (2);
+ addToken (Token.GETELEM);
+ stackChange (-1);
+ // Compensate for the following USE_STACK
+ stackChange (-1);
+ }
+ VisitExpression (child, 0);
+ addToken (Token.SETELEM);
+ stackChange (-2);
+ break;
+
+
+ case Token.SET_REF:
+ case Token.SET_REF_OP:
+ VisitExpression (child, 0);
+ child = child.Next;
+ if (type == Token.SET_REF_OP) {
+ addIcode (Icode_DUP);
+ stackChange (1);
+ addToken (Token.GET_REF);
+ // Compensate for the following USE_STACK
+ stackChange (-1);
+ }
+ VisitExpression (child, 0);
+ addToken (Token.SET_REF);
+ stackChange (-1);
+ break;
+
+
+ case Token.SETNAME: {
+ string name = child.String;
+ VisitExpression (child, 0);
+ child = child.Next;
+ VisitExpression (child, 0);
+ addStringOp (Token.SETNAME, name);
+ stackChange (-1);
+ }
+ break;
+
+
+ case Token.TYPEOFNAME: {
+ string name = node.String;
+ int index = -1;
+ // use typeofname if an activation frame exists
+ // since the vars all exist there instead of in jregs
+ if (itsInFunctionFlag && !itsData.itsNeedsActivation)
+ index = scriptOrFn.getParamOrVarIndex (name);
+ if (index == -1) {
+ addStringOp (Icode_TYPEOFNAME, name);
+ stackChange (1);
+ }
+ else {
+ addVarOp (Token.GETVAR, index);
+ stackChange (1);
+ addToken (Token.TYPEOF);
+ }
+ }
+ break;
+
+
+ case Token.BINDNAME:
+ case Token.NAME:
+ case Token.STRING:
+ addStringOp (type, node.String);
+ stackChange (1);
+ break;
+
+
+ case Token.INC:
+ case Token.DEC:
+ VisitIncDec (node, child);
+ break;
+
+
+ case Token.NUMBER: {
+ double num = node.Double;
+ int inum = (int)num;
+ if (inum == num) {
+ if (inum == 0) {
+ addIcode (Icode_ZERO);
+ // Check for negative zero
+ if (1.0 / num < 0.0) {
+ addToken (Token.NEG);
+ }
+ }
+ else if (inum == 1) {
+ addIcode (Icode_ONE);
+ }
+ else if ((short)inum == inum) {
+ addIcode (Icode_SHORTNUMBER);
+ // write short as uin16 bit pattern
+ addUint16 (inum & 0xFFFF);
+ }
+ else {
+ addIcode (Icode_INTNUMBER);
+ addInt (inum);
+ }
+ }
+ else {
+ int index = GetDoubleIndex (num);
+ addIndexOp (Token.NUMBER, index);
+ }
+ stackChange (1);
+ }
+ break;
+
+
+ case Token.GETVAR: {
+ if (itsData.itsNeedsActivation)
+ Context.CodeBug ();
+ string name = node.String;
+ int index = scriptOrFn.getParamOrVarIndex (name);
+ addVarOp (Token.GETVAR, index);
+ stackChange (1);
+ }
+ break;
+
+
+ case Token.SETVAR: {
+ if (itsData.itsNeedsActivation)
+ Context.CodeBug ();
+ string name = child.String;
+ child = child.Next;
+ VisitExpression (child, 0);
+ int index = scriptOrFn.getParamOrVarIndex (name);
+ addVarOp (Token.SETVAR, index);
+ }
+ break;
+
+
+
+ case Token.NULL:
+ case Token.THIS:
+ case Token.THISFN:
+ case Token.FALSE:
+ case Token.TRUE:
+ addToken (type);
+ stackChange (1);
+ break;
+
+
+ case Token.ENUM_NEXT:
+ case Token.ENUM_ID:
+ addIndexOp (type, getLocalBlockRef (node));
+ stackChange (1);
+ break;
+
+
+ case Token.REGEXP: {
+ int index = node.getExistingIntProp (Node.REGEXP_PROP);
+ addIndexOp (Token.REGEXP, index);
+ stackChange (1);
+ }
+ break;
+
+
+ case Token.ARRAYLIT:
+ case Token.OBJECTLIT:
+ VisitLiteral (node, child);
+ break;
+
+
+ case Token.REF_SPECIAL:
+ VisitExpression (child, 0);
+ addStringOp (type, (string)node.getProp (Node.NAME_PROP));
+ break;
+
+
+ case Token.REF_MEMBER:
+ case Token.REF_NS_MEMBER:
+ case Token.REF_NAME:
+ case Token.REF_NS_NAME: {
+ int memberTypeFlags = node.getIntProp (Node.MEMBER_TYPE_PROP, 0);
+ // generate possible target, possible namespace and member
+ int childCount = 0;
+ do {
+ VisitExpression (child, 0);
+ ++childCount;
+ child = child.Next;
+ }
+ while (child != null);
+ addIndexOp (type, memberTypeFlags);
+ stackChange (1 - childCount);
+ }
+ break;
+
+
+ case Token.DOTQUERY: {
+ int queryPC;
+ updateLineNumber (node);
+ VisitExpression (child, 0);
+ addIcode (Icode_ENTERDQ);
+ stackChange (-1);
+ queryPC = itsICodeTop;
+ VisitExpression (child.Next, 0);
+ addBackwardGoto (Icode_LEAVEDQ, queryPC);
+ }
+ break;
+
+
+ case Token.DEFAULTNAMESPACE:
+ case Token.ESCXMLATTR:
+ case Token.ESCXMLTEXT:
+ VisitExpression (child, 0);
+ addToken (type);
+ break;
+
+ default:
+ throw badTree (node);
+
+ }
+ //if (savedStackDepth + 1 != itsStackDepth) {
+ // EcmaScriptHelper.CodeBug();
+ //}
+ }
+
+ void generateCallFunAndThis (Node left)
+ {
+ // Generate code to place on stack function and thisObj
+ int type = left.Type;
+ switch (type) {
+
+ case Token.NAME: {
+ string name = left.String;
+ // stack: ... -> ... function thisObj
+ addStringOp (Icode_NAME_AND_THIS, name);
+ stackChange (2);
+ break;
+ }
+
+ case Token.GETPROP:
+ case Token.GETELEM: {
+ Node target = left.FirstChild;
+ VisitExpression (target, 0);
+ Node id = target.Next;
+ if (type == Token.GETPROP) {
+ string property = id.String;
+ // stack: ... target -> ... function thisObj
+ addStringOp (Icode_PROP_AND_THIS, property);
+ stackChange (1);
+ }
+ else {
+ VisitExpression (id, 0);
+ // stack: ... target id -> ... function thisObj
+ addIcode (Icode_ELEM_AND_THIS);
+ }
+ break;
+ }
+
+ default:
+ // Including Token.GETVAR
+ VisitExpression (left, 0);
+ // stack: ... value -> ... function thisObj
+ addIcode (Icode_VALUE_AND_THIS);
+ stackChange (1);
+ break;
+
+ }
+ }
+
+ void VisitIncDec (Node node, Node child)
+ {
+ int incrDecrMask = node.getExistingIntProp (Node.INCRDECR_PROP);
+ int childType = child.Type;
+ switch (childType) {
+
+ case Token.GETVAR: {
+ if (itsData.itsNeedsActivation)
+ Context.CodeBug ();
+ string name = child.String;
+ int i = scriptOrFn.getParamOrVarIndex (name);
+ addVarOp (Icode_VAR_INC_DEC, i);
+ addUint8 (incrDecrMask);
+ stackChange (1);
+ break;
+ }
+
+ case Token.NAME: {
+ string name = child.String;
+ addStringOp (Icode_NAME_INC_DEC, name);
+ addUint8 (incrDecrMask);
+ stackChange (1);
+ break;
+ }
+
+ case Token.GETPROP: {
+ Node obj = child.FirstChild;
+ VisitExpression (obj, 0);
+ string property = obj.Next.String;
+ addStringOp (Icode_PROP_INC_DEC, property);
+ addUint8 (incrDecrMask);
+ break;
+ }
+
+ case Token.GETELEM: {
+ Node obj = child.FirstChild;
+ VisitExpression (obj, 0);
+ Node index = obj.Next;
+ VisitExpression (index, 0);
+ addIcode (Icode_ELEM_INC_DEC);
+ addUint8 (incrDecrMask);
+ stackChange (-1);
+ break;
+ }
+
+ case Token.GET_REF: {
+ Node rf = child.FirstChild;
+ VisitExpression (rf, 0);
+ addIcode (Icode_REF_INC_DEC);
+ addUint8 (incrDecrMask);
+ break;
+ }
+
+ default: {
+ throw badTree (node);
+ }
+
+ }
+ }
+
+ void VisitLiteral (Node node, Node child)
+ {
+ int type = node.Type;
+ int count;
+ object [] propertyIds = null;
+ if (type == Token.ARRAYLIT) {
+ count = 0;
+ for (Node n = child; n != null; n = n.Next) {
+ ++count;
+ }
+ }
+ else if (type == Token.OBJECTLIT) {
+ propertyIds = (object [])node.getProp (Node.OBJECT_IDS_PROP);
+ count = propertyIds.Length;
+ }
+ else {
+ throw badTree (node);
+ }
+ addIndexOp (Icode_LITERAL_NEW, count);
+ stackChange (1);
+ while (child != null) {
+ VisitExpression (child, 0);
+ addIcode (Icode_LITERAL_SET);
+ stackChange (-1);
+ child = child.Next;
+ }
+ if (type == Token.ARRAYLIT) {
+ int [] skipIndexes = (int [])node.getProp (Node.SKIP_INDEXES_PROP);
+ if (skipIndexes == null) {
+ addToken (Token.ARRAYLIT);
+ }
+ else {
+ int index = itsLiteralIds.size ();
+ itsLiteralIds.add (skipIndexes);
+ addIndexOp (Icode_SPARE_ARRAYLIT, index);
+ }
+ }
+ else {
+ int index = itsLiteralIds.size ();
+ itsLiteralIds.add (propertyIds);
+ addIndexOp (Token.OBJECTLIT, index);
+ }
+ }
+
+ int getLocalBlockRef (Node node)
+ {
+ Node localBlock = (Node)node.getProp (Node.LOCAL_BLOCK_PROP);
+ return localBlock.getExistingIntProp (Node.LOCAL_PROP);
+ }
+
+ int getTargetLabel (Node target)
+ {
+ int label = target.labelId ();
+ if (label != -1) {
+ return label;
+ }
+ label = itsLabelTableTop;
+ if (itsLabelTable == null || label == itsLabelTable.Length) {
+ if (itsLabelTable == null) {
+ itsLabelTable = new int [MIN_LABEL_TABLE_SIZE];
+ }
+ else {
+ int [] tmp = new int [itsLabelTable.Length * 2];
+ Array.Copy (itsLabelTable, 0, tmp, 0, label);
+ itsLabelTable = tmp;
+ }
+ }
+ itsLabelTableTop = label + 1;
+ itsLabelTable [label] = -1;
+
+ target.labelId (label);
+ return label;
+ }
+
+ void markTargetLabel (Node target)
+ {
+ int label = getTargetLabel (target);
+ if (itsLabelTable [label] != -1) {
+ // Can mark label only once
+ Context.CodeBug ();
+ }
+ itsLabelTable [label] = itsICodeTop;
+ }
+
+ void addGoto (Node target, int gotoOp)
+ {
+ int label = getTargetLabel (target);
+ if (!(label < itsLabelTableTop))
+ Context.CodeBug ();
+ int targetPC = itsLabelTable [label];
+
+ if (targetPC != -1) {
+ addBackwardGoto (gotoOp, targetPC);
+ }
+ else {
+ int gotoPC = itsICodeTop;
+ addGotoOp (gotoOp);
+ int top = itsFixupTableTop;
+ if (itsFixupTable == null || top == itsFixupTable.Length) {
+ if (itsFixupTable == null) {
+ itsFixupTable = new long [MIN_FIXUP_TABLE_SIZE];
+ }
+ else {
+ long [] tmp = new long [itsFixupTable.Length * 2];
+ Array.Copy (itsFixupTable, 0, tmp, 0, top);
+ itsFixupTable = tmp;
+ }
+ }
+ itsFixupTableTop = top + 1;
+ itsFixupTable [top] = ((long)label << 32) | (uint)gotoPC;
+ }
+ }
+
+ void fixLabelGotos ()
+ {
+ for (int i = 0; i < itsFixupTableTop; i++) {
+ long fixup = itsFixupTable [i];
+ int label = (int)(fixup >> 32);
+ int jumpSource = (int)fixup;
+ int pc = itsLabelTable [label];
+ if (pc == -1) {
+ // Unlocated label
+ throw Context.CodeBug ();
+ }
+ resolveGoto (jumpSource, pc);
+ }
+ itsFixupTableTop = 0;
+ }
+
+ void addBackwardGoto (int gotoOp, int jumpPC)
+ {
+ int fromPC = itsICodeTop;
+ // Ensure that this is a jump backward
+ if (fromPC <= jumpPC)
+ throw Context.CodeBug ();
+ addGotoOp (gotoOp);
+ resolveGoto (fromPC, jumpPC);
+ }
+
+
+ void resolveForwardGoto (int fromPC)
+ {
+ // Ensure that forward jump skips at least self bytecode
+ if (itsICodeTop < fromPC + 3)
+ throw Context.CodeBug ();
+ resolveGoto (fromPC, itsICodeTop);
+ }
+
+ void resolveGoto (int fromPC, int jumpPC)
+ {
+ int offset = jumpPC - fromPC;
+ // Ensure that jumps do not overlap
+ if (0 <= offset && offset <= 2)
+ throw Context.CodeBug ();
+ int offsetSite = fromPC + 1;
+ if (offset != (short)offset) {
+ if (itsData.longJumps == null) {
+ itsData.longJumps = new UintMap ();
+ }
+ itsData.longJumps.put (offsetSite, jumpPC);
+ offset = 0;
+ }
+ sbyte [] array = itsData.itsICode;
+ array [offsetSite] = (sbyte)(offset >> 8);
+ array [offsetSite + 1] = (sbyte)offset;
+ }
+
+ void addToken (int token)
+ {
+ if (!ValidTokenCode (token))
+ throw Context.CodeBug ();
+ addUint8 (token);
+ }
+
+ void addIcode (int icode)
+ {
+ if (!validIcode (icode))
+ throw Context.CodeBug ();
+ // Write negative icode as uint8 bits
+ addUint8 (icode & 0xFF);
+ }
+
+ void addUint8 (int value)
+ {
+ if ((value & ~0xFF) != 0)
+ throw Context.CodeBug ();
+ sbyte [] array = itsData.itsICode;
+ int top = itsICodeTop;
+ if (top == array.Length) {
+ array = increaseICodeCapasity (1);
+ }
+ array [top] = (sbyte)value;
+ itsICodeTop = top + 1;
+ }
+
+ void addUint16 (int value)
+ {
+ if ((value & ~0xFFFF) != 0)
+ throw Context.CodeBug ();
+ sbyte [] array = itsData.itsICode;
+ int top = itsICodeTop;
+ if (top + 2 > array.Length) {
+ array = increaseICodeCapasity (2);
+ }
+ array [top] = (sbyte)((uint)value >> 8);
+ array [top + 1] = (sbyte)value;
+ itsICodeTop = top + 2;
+ }
+
+ void addInt (int i)
+ {
+ sbyte [] array = itsData.itsICode;
+ int top = itsICodeTop;
+ if (top + 4 > array.Length) {
+ array = increaseICodeCapasity (4);
+ }
+ array [top] = (sbyte)((uint)i >> 24);
+ array [top + 1] = (sbyte)((uint)i >> 16);
+ array [top + 2] = (sbyte)((uint)i >> 8);
+ array [top + 3] = (sbyte)i;
+ itsICodeTop = top + 4;
+ }
+
+ int GetDoubleIndex (double num)
+ {
+ int index = itsDoubleTableTop;
+ if (index == 0) {
+ itsData.itsDoubleTable = new double [64];
+ }
+ else if (itsData.itsDoubleTable.Length == index) {
+ double [] na = new double [index * 2];
+ Array.Copy (itsData.itsDoubleTable, 0, na, 0, index);
+ itsData.itsDoubleTable = na;
+ }
+ itsData.itsDoubleTable [index] = num;
+ itsDoubleTableTop = index + 1;
+ return index;
+ }
+
+ void addVarOp (int op, int varIndex)
+ {
+ switch (op) {
+
+ case Token.GETVAR:
+ case Token.SETVAR:
+ if (varIndex < 128) {
+ addIcode (op == Token.GETVAR ? Icode_GETVAR1 : Icode_SETVAR1);
+ addUint8 (varIndex);
+ return;
+ }
+ // fallthrough
+ goto case Icode_VAR_INC_DEC;
+
+ case Icode_VAR_INC_DEC:
+ addIndexOp (op, varIndex);
+ return;
+ }
+ throw Context.CodeBug ();
+ }
+
+ void addStringOp (int op, string str)
+ {
+ addStringPrefix (str);
+ if (validIcode (op)) {
+ addIcode (op);
+ }
+ else {
+ addToken (op);
+ }
+ }
+
+ void addIndexOp (int op, int index)
+ {
+ addIndexPrefix (index);
+ if (validIcode (op)) {
+ addIcode (op);
+ }
+ else {
+ addToken (op);
+ }
+ }
+
+ void addStringPrefix (string str)
+ {
+ int index = itsStrings.Get (str, -1);
+ if (index == -1) {
+ index = itsStrings.size ();
+ itsStrings.put (str, index);
+ }
+ if (index < 4) {
+ addIcode (Icode_REG_STR_C0 - index);
+ }
+ else if (index <= 0xFF) {
+ addIcode (Icode_REG_STR1);
+ addUint8 (index);
+ }
+ else if (index <= 0xFFFF) {
+ addIcode (Icode_REG_STR2);
+ addUint16 (index);
+ }
+ else {
+ addIcode (Icode_REG_STR4);
+ addInt (index);
+ }
+ }
+
+ void addIndexPrefix (int index)
+ {
+ if (index < 0)
+ Context.CodeBug ();
+ if (index < 6) {
+ addIcode (Icode_REG_IND_C0 - index);
+ }
+ else if (index <= 0xFF) {
+ addIcode (Icode_REG_IND1);
+ addUint8 (index);
+ }
+ else if (index <= 0xFFFF) {
+ addIcode (Icode_REG_IND2);
+ addUint16 (index);
+ }
+ else {
+ addIcode (Icode_REG_IND4);
+ addInt (index);
+ }
+ }
+
+ void addExceptionHandler (int icodeStart, int icodeEnd, int handlerStart, bool isFinally, int exceptionObjectLocal, int scopeLocal)
+ {
+ int top = itsExceptionTableTop;
+ int [] table = itsData.itsExceptionTable;
+ if (table == null) {
+ if (top != 0)
+ Context.CodeBug ();
+ table = new int [EXCEPTION_SLOT_SIZE * 2];
+ itsData.itsExceptionTable = table;
+ }
+ else if (table.Length == top) {
+ table = new int [table.Length * 2];
+ Array.Copy (itsData.itsExceptionTable, 0, table, 0, top);
+ itsData.itsExceptionTable = table;
+ }
+ table [top + EXCEPTION_TRY_START_SLOT] = icodeStart;
+ table [top + EXCEPTION_TRY_END_SLOT] = icodeEnd;
+ table [top + EXCEPTION_HANDLER_SLOT] = handlerStart;
+ table [top + EXCEPTION_TYPE_SLOT] = isFinally ? 1 : 0;
+ table [top + EXCEPTION_LOCAL_SLOT] = exceptionObjectLocal;
+ table [top + EXCEPTION_SCOPE_SLOT] = scopeLocal;
+
+ itsExceptionTableTop = top + EXCEPTION_SLOT_SIZE;
+ }
+
+ sbyte [] increaseICodeCapasity (int extraSize)
+ {
+ int capacity = itsData.itsICode.Length;
+ int top = itsICodeTop;
+ if (top + extraSize <= capacity)
+ throw Context.CodeBug ();
+ capacity *= 2;
+ if (top + extraSize > capacity) {
+ capacity = top + extraSize;
+ }
+ sbyte [] array = new sbyte [capacity];
+ Array.Copy (itsData.itsICode, 0, array, 0, top);
+ itsData.itsICode = array;
+ return array;
+ }
+
+ void stackChange (int change)
+ {
+ if (change <= 0) {
+ itsStackDepth += change;
+ }
+ else {
+ int newDepth = itsStackDepth + change;
+ if (newDepth > itsData.itsMaxStack) {
+ itsData.itsMaxStack = newDepth;
+ }
+ itsStackDepth = newDepth;
+ }
+ }
+
+ int allocLocal ()
+ {
+ int localSlot = itsLocalTop;
+ ++itsLocalTop;
+ if (itsLocalTop > itsData.itsMaxLocals) {
+ itsData.itsMaxLocals = itsLocalTop;
+ }
+ return localSlot;
+ }
+
+ void releaseLocal (int localSlot)
+ {
+ --itsLocalTop;
+ if (localSlot != itsLocalTop)
+ Context.CodeBug ();
+ }
+
+ static int GetShort (sbyte [] iCode, int pc)
+ {
+ return (iCode [pc] << 8) | (iCode [pc + 1] & 0xFF);
+ }
+
+ static int GetIndex (sbyte [] iCode, int pc)
+ {
+ return ((iCode [pc] & 0xFF) << 8) | (iCode [pc + 1] & 0xFF);
+ }
+
+ static int GetInt (sbyte [] iCode, int pc)
+ {
+ return (iCode [pc] << 24) | ((iCode [pc + 1] & 0xFF) << 16) | ((iCode [pc + 2] & 0xFF) << 8) | (iCode [pc + 3] & 0xFF);
+ }
+
+ static int getExceptionHandler (CallFrame frame, bool onlyFinally)
+ {
+ int [] exceptionTable = frame.idata.itsExceptionTable;
+ if (exceptionTable == null) {
+ // No exception handlers
+ return -1;
+ }
+
+ // Icode switch in the interpreter increments PC immediately
+ // and it is necessary to subtract 1 from the saved PC
+ // to point it before the start of the next instruction.
+ int pc = frame.pc - 1;
+
+ // OPT: use binary search
+ int best = -1, bestStart = 0, bestEnd = 0;
+ for (int i = 0; i != exceptionTable.Length; i += EXCEPTION_SLOT_SIZE) {
+ int start = exceptionTable [i + EXCEPTION_TRY_START_SLOT];
+ int end = exceptionTable [i + EXCEPTION_TRY_END_SLOT];
+ if (!(start <= pc && pc < end)) {
+ continue;
+ }
+ if (onlyFinally && exceptionTable [i + EXCEPTION_TYPE_SLOT] != 1) {
+ continue;
+ }
+ if (best >= 0) {
+ // Since handlers always nest and they never have shared end
+ // although they can share start it is sufficient to compare
+ // handlers ends
+ if (bestEnd < end) {
+ continue;
+ }
+ // Check the above assumption
+ if (bestStart > start)
+ Context.CodeBug (); // should be nested
+ if (bestEnd == end)
+ Context.CodeBug (); // no ens sharing
+ }
+ best = i;
+ bestStart = start;
+ bestEnd = end;
+ }
+ return best;
+ }
+
+ static void dumpICode (InterpreterData idata)
+ {
+ if (!Token.printICode) {
+ return;
+ }
+
+ sbyte [] iCode = idata.itsICode;
+ int iCodeLength = iCode.Length;
+ string [] strings = idata.itsStringTable;
+
+ System.IO.TextWriter sw = Console.Out;
+ sw.WriteLine ("ICode dump, for " + idata.itsName + ", length = " + iCodeLength);
+ sw.WriteLine ("MaxStack = " + idata.itsMaxStack);
+
+ int indexReg = 0;
+ for (int pc = 0; pc < iCodeLength; ) {
+ sw.Flush ();
+ sw.Write (" [" + pc + "] ");
+ int token = iCode [pc];
+ int icodeLength = bytecodeSpan (token);
+ string tname = bytecodeName (token);
+ int old_pc = pc;
+ ++pc;
+ switch (token) {
+
+ default:
+ if (icodeLength != 1)
+ Context.CodeBug ();
+ sw.WriteLine (tname);
+ break;
+
+
+
+ case Icode_GOSUB:
+ case Token.GOTO:
+ case Token.IFEQ:
+ case Token.IFNE:
+ case Icode_IFEQ_POP:
+ case Icode_LEAVEDQ: {
+ int newPC = pc + GetShort (iCode, pc) - 1;
+ sw.WriteLine (tname + " " + newPC);
+ pc += 2;
+ break;
+ }
+
+ case Icode_VAR_INC_DEC:
+ case Icode_NAME_INC_DEC:
+ case Icode_PROP_INC_DEC:
+ case Icode_ELEM_INC_DEC:
+ case Icode_REF_INC_DEC: {
+ int incrDecrType = iCode [pc];
+ sw.WriteLine (tname + " " + incrDecrType);
+ ++pc;
+ break;
+ }
+
+
+ case Icode_CALLSPECIAL: {
+ int callType = iCode [pc] & 0xFF;
+ bool isNew = (iCode [pc + 1] != 0);
+ int line = GetIndex (iCode, pc + 2);
+ sw.WriteLine (tname + " " + callType + " " + isNew + " " + indexReg + " " + line);
+ pc += 4;
+ break;
+ }
+
+
+ case Token.CATCH_SCOPE: {
+ bool afterFisrtFlag = (iCode [pc] != 0);
+ sw.WriteLine (tname + " " + afterFisrtFlag);
+ ++pc;
+ }
+ break;
+
+ case Token.REGEXP:
+ sw.WriteLine (tname + " " + idata.itsRegExpLiterals [indexReg]);
+ break;
+
+ case Token.OBJECTLIT:
+ case Icode_SPARE_ARRAYLIT:
+ sw.WriteLine (tname + " " + idata.literalIds [indexReg]);
+ break;
+
+ case Icode_CLOSURE_EXPR:
+ case Icode_CLOSURE_STMT:
+ sw.WriteLine (tname + " " + idata.itsNestedFunctions [indexReg]);
+ break;
+
+ case Token.CALL:
+ case Icode_TAIL_CALL:
+ case Token.REF_CALL:
+ case Token.NEW:
+ sw.WriteLine (tname + ' ' + indexReg);
+ break;
+
+ case Token.THROW: {
+ int line = GetIndex (iCode, pc);
+ sw.WriteLine (tname + " : " + line);
+ pc += 2;
+ break;
+ }
+
+ case Icode_SHORTNUMBER: {
+ int value = GetShort (iCode, pc);
+ sw.WriteLine (tname + " " + value);
+ pc += 2;
+ break;
+ }
+
+ case Icode_INTNUMBER: {
+ int value = GetInt (iCode, pc);
+ sw.WriteLine (tname + " " + value);
+ pc += 4;
+ break;
+ }
+
+ case Token.NUMBER: {
+ double value = idata.itsDoubleTable [indexReg];
+ sw.WriteLine (tname + " " + value);
+ pc += 2;
+ break;
+ }
+
+ case Icode_LINE: {
+ int line = GetIndex (iCode, pc);
+ sw.WriteLine (tname + " : " + line);
+ pc += 2;
+ break;
+ }
+
+ case Icode_REG_STR1: {
+ string str = strings [0xFF & iCode [pc]];
+ sw.WriteLine (tname + " \"" + str + '"');
+ ++pc;
+ break;
+ }
+
+ case Icode_REG_STR2: {
+ string str = strings [GetIndex (iCode, pc)];
+ sw.WriteLine (tname + " \"" + str + '"');
+ pc += 2;
+ break;
+ }
+
+ case Icode_REG_STR4: {
+ string str = strings [GetInt (iCode, pc)];
+ sw.WriteLine (tname + " \"" + str + '"');
+ pc += 4;
+ break;
+ }
+
+ case Icode_REG_IND1: {
+ indexReg = 0xFF & iCode [pc];
+ sw.WriteLine (tname + " " + indexReg);
+ ++pc;
+ break;
+ }
+
+ case Icode_REG_IND2: {
+ indexReg = GetIndex (iCode, pc);
+ sw.WriteLine (tname + " " + indexReg);
+ pc += 2;
+ break;
+ }
+
+ case Icode_REG_IND4: {
+ indexReg = GetInt (iCode, pc);
+ sw.WriteLine (tname + " " + indexReg);
+ pc += 4;
+ break;
+ }
+
+ case Icode_GETVAR1:
+ case Icode_SETVAR1:
+ indexReg = iCode [pc];
+ sw.WriteLine (tname + " " + indexReg);
+ ++pc;
+ break;
+ }
+ if (old_pc + icodeLength != pc)
+ Context.CodeBug ();
+ }
+
+ int [] table = idata.itsExceptionTable;
+ if (table != null) {
+ sw.WriteLine ("Exception handlers: " + table.Length / EXCEPTION_SLOT_SIZE);
+ for (int i = 0; i != table.Length; i += EXCEPTION_SLOT_SIZE) {
+ int tryStart = table [i + EXCEPTION_TRY_START_SLOT];
+ int tryEnd = table [i + EXCEPTION_TRY_END_SLOT];
+ int handlerStart = table [i + EXCEPTION_HANDLER_SLOT];
+ int type = table [i + EXCEPTION_TYPE_SLOT];
+ int exceptionLocal = table [i + EXCEPTION_LOCAL_SLOT];
+ int scopeLocal = table [i + EXCEPTION_SCOPE_SLOT];
+
+ sw.WriteLine (" tryStart=" + tryStart + " tryEnd=" + tryEnd + " handlerStart=" + handlerStart + " type=" + (type == 0 ? "catch" : "finally") + " exceptionLocal=" + exceptionLocal);
+ }
+ }
+ sw.Flush ();
+ }
+
+ static int bytecodeSpan (int bytecode)
+ {
+ switch (bytecode) {
+
+ case Token.THROW:
+ // source line
+ return 1 + 2;
+
+
+ case Icode_GOSUB:
+ case Token.GOTO:
+ case Token.IFEQ:
+ case Token.IFNE:
+ case Icode_IFEQ_POP:
+ case Icode_LEAVEDQ:
+ // target pc offset
+ return 1 + 2;
+
+
+ case Icode_CALLSPECIAL:
+ // call type
+ // is new
+ // line number
+ return 1 + 1 + 1 + 2;
+
+
+ case Token.CATCH_SCOPE:
+ // scope flag
+ return 1 + 1;
+
+
+ case Icode_VAR_INC_DEC:
+ case Icode_NAME_INC_DEC:
+ case Icode_PROP_INC_DEC:
+ case Icode_ELEM_INC_DEC:
+ case Icode_REF_INC_DEC:
+ // type of ++/--
+ return 1 + 1;
+
+
+ case Icode_SHORTNUMBER:
+ // short number
+ return 1 + 2;
+
+
+ case Icode_INTNUMBER:
+ // int number
+ return 1 + 4;
+
+
+ case Icode_REG_IND1:
+ // ubyte index
+ return 1 + 1;
+
+
+ case Icode_REG_IND2:
+ // ushort index
+ return 1 + 2;
+
+
+ case Icode_REG_IND4:
+ // int index
+ return 1 + 4;
+
+
+ case Icode_REG_STR1:
+ // ubyte string index
+ return 1 + 1;
+
+
+ case Icode_REG_STR2:
+ // ushort string index
+ return 1 + 2;
+
+
+ case Icode_REG_STR4:
+ // int string index
+ return 1 + 4;
+
+
+ case Icode_GETVAR1:
+ case Icode_SETVAR1:
+ // byte var index
+ return 1 + 1;
+
+
+ case Icode_LINE:
+ // line number
+ return 1 + 2;
+ }
+
+ if (!validBytecode (bytecode))
+ throw Context.CodeBug ();
+
+ return 1;
+ }
+
+ internal static int [] getLineNumbers (InterpreterData data)
+ {
+ UintMap presentLines = new UintMap ();
+
+ sbyte [] iCode = data.itsICode;
+ int iCodeLength = iCode.Length;
+ for (int pc = 0; pc != iCodeLength; ) {
+ int bytecode = iCode [pc];
+ int span = bytecodeSpan (bytecode);
+ if (bytecode == Icode_LINE) {
+ if (span != 3)
+ Context.CodeBug ();
+ int line = GetIndex (iCode, pc + 1);
+ presentLines.put (line, 0);
+ }
+ pc += span;
+ }
+
+ return presentLines.Keys;
+ }
+
+ internal static void captureInterpreterStackInfo (EcmaScriptException ex)
+ {
+ Context cx = Context.CurrentContext;
+ if (cx == null || cx.lastInterpreterFrame == null) {
+ // No interpreter invocations
+ ex.m_InterpreterStackInfo = null;
+ ex.m_InterpreterLineData = null;
+ return;
+ }
+ // has interpreter frame on the stack
+ CallFrame [] array;
+ if (cx.previousInterpreterInvocations == null || cx.previousInterpreterInvocations.size () == 0) {
+ array = new CallFrame [1];
+ }
+ else {
+ int previousCount = cx.previousInterpreterInvocations.size ();
+ if (cx.previousInterpreterInvocations.peek () == cx.lastInterpreterFrame) {
+ // It can happen if exception was generated after
+ // frame was pushed to cx.previousInterpreterInvocations
+ // but before assignment to cx.lastInterpreterFrame.
+ // In this case frames has to be ignored.
+ --previousCount;
+ }
+ array = new CallFrame [previousCount + 1];
+ cx.previousInterpreterInvocations.ToArray (array);
+ }
+ array [array.Length - 1] = (CallFrame)cx.lastInterpreterFrame;
+
+ int interpreterFrameCount = 0;
+ for (int i = 0; i != array.Length; ++i) {
+ interpreterFrameCount += 1 + array [i].frameIndex;
+ }
+
+ int [] linePC = new int [interpreterFrameCount];
+ // Fill linePC with pc positions from all interpreter frames.
+ // Start from the most nested frame
+ int linePCIndex = interpreterFrameCount;
+ for (int i = array.Length; i != 0; ) {
+ --i;
+ CallFrame frame = array [i];
+ while (frame != null) {
+ --linePCIndex;
+ linePC [linePCIndex] = frame.pcSourceLineStart;
+ frame = frame.parentFrame;
+ }
+ }
+ if (linePCIndex != 0)
+ Context.CodeBug ();
+
+ ex.m_InterpreterStackInfo = array;
+ ex.m_InterpreterLineData = linePC;
+ }
+
+ internal static string GetSourcePositionFromStack (Context cx, int [] linep)
+ {
+ CallFrame frame = (CallFrame)cx.lastInterpreterFrame;
+ InterpreterData idata = frame.idata;
+ if (frame.pcSourceLineStart >= 0) {
+ linep [0] = GetIndex (idata.itsICode, frame.pcSourceLineStart);
+ }
+ else {
+ linep [0] = 0;
+ }
+ return idata.itsSourceFile;
+ }
+
+
+ internal static string GetStack (EcmaScriptException ex)
+ {
+ System.Text.StringBuilder sb = new System.Text.StringBuilder ();
+
+ CallFrame [] array = (CallFrame [])ex.m_InterpreterStackInfo;
+ if (array == null) // TODO: When does this happen?
+ return sb.ToString ();
+
+ int [] linePC = ex.m_InterpreterLineData;
+ int arrayIndex = array.Length;
+ int linePCIndex = linePC.Length;
+
+ while (arrayIndex != 0) {
+ --arrayIndex;
+
+ CallFrame frame = array [arrayIndex];
+ while (frame != null) {
+ if (linePCIndex == 0)
+ Context.CodeBug ();
+ --linePCIndex;
+ InterpreterData idata = frame.idata;
+
+ if (sb.Length > 0)
+ sb.Append (Environment.NewLine);
+ sb.Append ("\tat script");
+ if (idata.itsName != null && idata.itsName.Length != 0) {
+ sb.Append ('.');
+ sb.Append (idata.itsName);
+ }
+ sb.Append ('(');
+ sb.Append (idata.itsSourceFile);
+ int pc = linePC [linePCIndex];
+ if (pc >= 0) {
+ // Include line info only if available
+ sb.Append (':');
+ sb.Append (GetIndex (idata.itsICode, pc));
+ }
+ sb.Append (')');
+
+
+ frame = frame.parentFrame;
+
+
+ }
+ }
+
+ return sb.ToString ();
+ }
+
+ internal static string getPatchedStack (EcmaScriptException ex, string nativeStackTrace)
+ {
+ string tag = "EcmaScript.NET.Interpreter.interpretLoop";
+ System.Text.StringBuilder sb = new System.Text.StringBuilder (nativeStackTrace.Length + 1000);
+ string lineSeparator = System.Environment.NewLine;
+
+ CallFrame [] array = (CallFrame [])ex.m_InterpreterStackInfo;
+ if (array == null) // TODO: when does this happen?
+ return sb.ToString ();
+
+ int [] linePC = ex.m_InterpreterLineData;
+ int arrayIndex = array.Length;
+ int linePCIndex = linePC.Length;
+ int offset = 0;
+ while (arrayIndex != 0) {
+ --arrayIndex;
+ int pos = nativeStackTrace.IndexOf (tag, offset);
+ if (pos < 0) {
+ break;
+ }
+
+ // Skip tag length
+ pos += tag.Length;
+ // Skip until the end of line
+ for (; pos != nativeStackTrace.Length; ++pos) {
+ char c = nativeStackTrace [pos];
+ if (c == '\n' || c == '\r') {
+ break;
+ }
+ }
+ sb.Append (nativeStackTrace.Substring (offset, (pos) - (offset)));
+ offset = pos;
+
+ CallFrame frame = array [arrayIndex];
+ while (frame != null) {
+ if (linePCIndex == 0)
+ Context.CodeBug ();
+ --linePCIndex;
+ InterpreterData idata = frame.idata;
+ sb.Append (lineSeparator);
+ sb.Append ("\tat script");
+ if (idata.itsName != null && idata.itsName.Length != 0) {
+ sb.Append ('.');
+ sb.Append (idata.itsName);
+ }
+ sb.Append ('(');
+ sb.Append (idata.itsSourceFile);
+ int pc = linePC [linePCIndex];
+ if (pc >= 0) {
+ // Include line info only if available
+ sb.Append (':');
+ sb.Append (GetIndex (idata.itsICode, pc));
+ }
+ sb.Append (')');
+ frame = frame.parentFrame;
+ }
+ }
+ sb.Append (nativeStackTrace.Substring (offset));
+
+ return sb.ToString ();
+ }
+
+ internal static string GetEncodedSource (InterpreterData idata)
+ {
+ if (idata.encodedSource == null) {
+ return null;
+ }
+ return idata.encodedSource.Substring (idata.encodedSourceStart, (idata.encodedSourceEnd) - (idata.encodedSourceStart));
+ }
+
+ static void initFunction (Context cx, IScriptable scope, InterpretedFunction parent, int index)
+ {
+ InterpretedFunction fn;
+ fn = InterpretedFunction.createFunction (cx, scope, parent, index);
+ ScriptRuntime.initFunction (cx, scope, fn, fn.idata.itsFunctionType, parent.idata.evalScriptFlag);
+ }
+
+ internal static object Interpret (InterpretedFunction ifun, Context cx, IScriptable scope, IScriptable thisObj, object [] args)
+ {
+ using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier (128)) {
+ if (!ScriptRuntime.hasTopCall (cx))
+ Context.CodeBug ();
+
+ if (cx.interpreterSecurityDomain != ifun.securityDomain) {
+ object savedDomain = cx.interpreterSecurityDomain;
+ cx.interpreterSecurityDomain = ifun.securityDomain;
+ try {
+ return ifun.securityController.callWithDomain (ifun.securityDomain, cx, ifun, scope, thisObj, args);
+ }
+ finally {
+ cx.interpreterSecurityDomain = savedDomain;
+ }
+ }
+
+ CallFrame frame = new CallFrame ();
+ initFrame (cx, scope, thisObj, args, null, 0, args.Length, ifun, null, frame);
+
+ return InterpretLoop (cx, frame, (object)null);
+ }
+ }
+
+ public static object restartContinuation (Continuation c, Context cx, IScriptable scope, object [] args)
+ {
+ if (!ScriptRuntime.hasTopCall (cx)) {
+ return ScriptRuntime.DoTopCall (c, cx, scope, null, args);
+ }
+
+ object arg;
+ if (args.Length == 0) {
+ arg = Undefined.Value;
+ }
+ else {
+ arg = args [0];
+ }
+
+ CallFrame capturedFrame = (CallFrame)c.Implementation;
+ if (capturedFrame == null) {
+ // No frames to restart
+ return arg;
+ }
+
+ ContinuationJump cjump = new ContinuationJump (c, null);
+
+ cjump.result = arg;
+ return InterpretLoop (cx, null, cjump);
+ }
+
+ static object InterpretLoop (Context cx, CallFrame frame, object throwable)
+ {
+ // throwable holds exception object to rethrow or catch
+ // It is also used for continuation restart in which case
+ // it holds ContinuationJump
+
+ object DBL_MRK = UniqueTag.DoubleMark;
+ object undefined = Undefined.Value;
+
+ bool instructionCounting = (cx.instructionThreshold != 0);
+ // arbitrary number to add to instructionCount when calling
+ // other functions
+ const int INVOCATION_COST = 100;
+
+ // arbitrary exception cost for instruction counting
+ const int EXCEPTION_COST = 100;
+
+ string stringReg = null;
+ int indexReg = -1;
+
+ if (cx.lastInterpreterFrame != null) {
+ // save the top frame from the previous interpreterLoop
+ // invocation on the stack
+ if (cx.previousInterpreterInvocations == null) {
+ cx.previousInterpreterInvocations = new ObjArray ();
+ }
+ cx.previousInterpreterInvocations.push (cx.lastInterpreterFrame);
+ }
+
+ // When restarting continuation throwable is not null and to jump
+ // to the code that rewind continuation state indexReg should be set
+ // to -1.
+ // With the normal call throable == null and indexReg == -1 allows to
+ // catch bugs with using indeReg to access array eleemnts before
+ // initializing indexReg.
+
+ if (throwable != null) {
+ // Assert assumptions
+ if (!(throwable is ContinuationJump)) {
+ // It should be continuation
+ Context.CodeBug ();
+ }
+ }
+
+ object interpreterResult = null;
+ double interpreterResultDbl = 0.0;
+
+ for (; ; ) {
+
+ try {
+
+ if (throwable != null) {
+ // Recovering from exception, indexReg contains
+ // the index of handler
+
+ if (indexReg >= 0) {
+ // Normal excepton handler, transfer
+ // control appropriately
+
+ if (frame.frozen) {
+ // TODO: Deal with exceptios!!!
+ frame = frame.cloneFrozen ();
+ }
+
+ int [] table = frame.idata.itsExceptionTable;
+
+ frame.pc = table [indexReg + EXCEPTION_HANDLER_SLOT];
+ if (instructionCounting) {
+ frame.pcPrevBranch = frame.pc;
+ }
+
+ frame.savedStackTop = frame.emptyStackTop;
+ int scopeLocal = frame.localShift + table [indexReg + EXCEPTION_SCOPE_SLOT];
+ int exLocal = frame.localShift + table [indexReg + EXCEPTION_LOCAL_SLOT];
+ frame.scope = (IScriptable)frame.stack [scopeLocal];
+ frame.stack [exLocal] = throwable;
+
+ throwable = null;
+ }
+ else {
+ // Continuation restoration
+ ContinuationJump cjump = (ContinuationJump)throwable;
+
+ // Clear throwable to indicate that execptions are OK
+ throwable = null;
+
+ if (cjump.branchFrame != frame)
+ Context.CodeBug ();
+
+ // Check that we have at least one frozen frame
+ // in the case of detached continuation restoration:
+ // unwind code ensure that
+ if (cjump.capturedFrame == null)
+ Context.CodeBug ();
+
+ // Need to rewind branchFrame, capturedFrame
+ // and all frames in between
+ int rewindCount = cjump.capturedFrame.frameIndex + 1;
+ if (cjump.branchFrame != null) {
+ rewindCount -= cjump.branchFrame.frameIndex;
+ }
+
+ int enterCount = 0;
+ CallFrame [] enterFrames = null;
+
+ CallFrame x = cjump.capturedFrame;
+ for (int i = 0; i != rewindCount; ++i) {
+ if (!x.frozen)
+ Context.CodeBug ();
+ if (isFrameEnterExitRequired (x)) {
+ if (enterFrames == null) {
+ // Allocate enough space to store the rest
+ // of rewind frames in case all of them
+ // would require to enter
+ enterFrames = new CallFrame [rewindCount - i];
+ }
+ enterFrames [enterCount] = x;
+ ++enterCount;
+ }
+ x = x.parentFrame;
+ }
+
+ while (enterCount != 0) {
+ // execute enter: walk enterFrames in the reverse
+ // order since they were stored starting from
+ // the capturedFrame, not branchFrame
+ --enterCount;
+ x = enterFrames [enterCount];
+ EnterFrame (cx, x, ScriptRuntime.EmptyArgs);
+ }
+
+ // Continuation jump is almost done: capturedFrame
+ // points to the call to the function that captured
+ // continuation, so clone capturedFrame and
+ // emulate return that function with the suplied result
+ frame = cjump.capturedFrame.cloneFrozen ();
+ setCallResult (frame, cjump.result, cjump.resultDbl);
+ // restart the execution
+ }
+
+ // Should be already cleared
+ if (throwable != null)
+ Context.CodeBug ();
+ }
+ else {
+ if (frame.frozen)
+ Context.CodeBug ();
+ }
+
+ // Use local variables for constant values in frame
+ // for faster access
+ object [] stack = frame.stack;
+ double [] sDbl = frame.sDbl;
+ object [] vars = frame.varSource.stack;
+ double [] varDbls = frame.varSource.sDbl;
+
+ sbyte [] iCode = frame.idata.itsICode;
+ string [] strings = frame.idata.itsStringTable;
+
+ // Use local for stackTop as well. Since execption handlers
+ // can only exist at statement level where stack is empty,
+ // it is necessary to save/restore stackTop only accross
+ // function calls and normal returns.
+ int stackTop = frame.savedStackTop;
+
+ // Store new frame in cx which is used for error reporting etc.
+ cx.lastInterpreterFrame = frame;
+
+ for (; ; ) {
+
+ // Exception handler assumes that PC is already incremented
+ // pass the instruction start when it searches the
+ // exception handler
+ int op = iCode [frame.pc++];
+ {
+ switch (op) {
+
+ case Token.THROW: {
+ object value = stack [stackTop];
+ if (value == DBL_MRK)
+ value = sDbl [stackTop];
+ stackTop--;
+
+ int sourceLine = GetIndex (iCode, frame.pc);
+ throwable = new EcmaScriptThrow (
+ value, frame.idata.itsSourceFile, sourceLine);
+ goto withoutExceptions_brk;
+ }
+
+ case Token.RETHROW: {
+ indexReg += frame.localShift;
+ throwable = stack [indexReg];
+ break;
+ }
+
+ case Token.GE:
+ case Token.LE:
+ case Token.GT:
+ case Token.LT: {
+ --stackTop;
+ object rhs = stack [stackTop + 1];
+ object lhs = stack [stackTop];
+ bool valBln;
+ {
+ {
+ double rDbl, lDbl;
+ if (rhs == DBL_MRK) {
+ rDbl = sDbl [stackTop + 1];
+ lDbl = stack_double (frame, stackTop);
+ }
+ else if (lhs == DBL_MRK) {
+ rDbl = ScriptConvert.ToNumber (rhs);
+ lDbl = sDbl [stackTop];
+ }
+ else {
+
+ goto number_compare_brk;
+ }
+ switch (op) {
+
+ case Token.GE:
+ valBln = (lDbl >= rDbl);
+
+ goto object_compare_brk;
+
+ case Token.LE:
+ valBln = (lDbl <= rDbl);
+
+ goto object_compare_brk;
+
+ case Token.GT:
+ valBln = (lDbl > rDbl);
+
+ goto object_compare_brk;
+
+ case Token.LT:
+ valBln = (lDbl < rDbl);
+
+ goto object_compare_brk;
+
+ default:
+ throw Context.CodeBug ();
+
+ }
+ }
+
+ number_compare_brk:
+ ;
+
+ switch (op) {
+
+ case Token.GE:
+ valBln = ScriptRuntime.cmp_LE (rhs, lhs);
+ break;
+
+ case Token.LE:
+ valBln = ScriptRuntime.cmp_LE (lhs, rhs);
+ break;
+
+ case Token.GT:
+ valBln = ScriptRuntime.cmp_LT (rhs, lhs);
+ break;
+
+ case Token.LT:
+ valBln = ScriptRuntime.cmp_LT (lhs, rhs);
+ break;
+
+ default:
+ throw Context.CodeBug ();
+
+ }
+ }
+
+ object_compare_brk:
+ ;
+
+ stack [stackTop] = valBln;
+
+ goto Loop;
+ }
+ goto case Token.IN;
+
+ case Token.IN:
+ case Token.INSTANCEOF: {
+ object rhs = stack [stackTop];
+ if (rhs == DBL_MRK)
+ rhs = sDbl [stackTop];
+ --stackTop;
+ object lhs = stack [stackTop];
+ if (lhs == DBL_MRK)
+ lhs = sDbl [stackTop];
+ bool valBln;
+ if (op == Token.IN) {
+ valBln = ScriptRuntime.In (lhs, rhs, cx);
+ }
+ else {
+ valBln = ScriptRuntime.InstanceOf (lhs, rhs, cx);
+ }
+ stack [stackTop] = valBln;
+
+ goto Loop;
+ }
+ goto case Token.EQ;
+
+ case Token.EQ:
+ case Token.NE: {
+ --stackTop;
+ bool valBln;
+ object rhs = stack [stackTop + 1];
+ object lhs = stack [stackTop];
+ if (rhs == DBL_MRK) {
+ if (lhs == DBL_MRK) {
+ valBln = (sDbl [stackTop] == sDbl [stackTop + 1]);
+ }
+ else {
+ valBln = ScriptRuntime.eqNumber (sDbl [stackTop + 1], lhs);
+ }
+ }
+ else {
+ if (lhs == DBL_MRK) {
+ valBln = ScriptRuntime.eqNumber (sDbl [stackTop], rhs);
+ }
+ else {
+ valBln = ScriptRuntime.eq (lhs, rhs);
+ }
+ }
+ valBln ^= (op == Token.NE);
+ stack [stackTop] = valBln;
+
+ goto Loop;
+ }
+ goto case Token.SHEQ;
+
+ case Token.SHEQ:
+ case Token.SHNE: {
+ --stackTop;
+ object rhs = stack [stackTop + 1];
+ object lhs = stack [stackTop];
+ bool valBln;
+ {
+ double rdbl, ldbl;
+ if (rhs == DBL_MRK) {
+ rdbl = sDbl [stackTop + 1];
+ if (lhs == DBL_MRK) {
+ ldbl = sDbl [stackTop];
+ }
+ else if (CliHelper.IsNumber (lhs)) {
+ ldbl = Convert.ToDouble (lhs);
+ }
+ else {
+ valBln = false;
+
+ goto shallow_compare_brk;
+ }
+ }
+ else if (lhs == DBL_MRK) {
+ ldbl = sDbl [stackTop];
+ if (rhs == DBL_MRK) {
+ rdbl = sDbl [stackTop + 1];
+ }
+ else if (CliHelper.IsNumber (rhs)) {
+ rdbl = Convert.ToDouble (rhs);
+ }
+ else {
+ valBln = false;
+
+ goto shallow_compare_brk;
+ }
+ }
+ else {
+ valBln = ScriptRuntime.shallowEq (lhs, rhs);
+
+ goto shallow_compare_brk;
+ }
+ valBln = (ldbl == rdbl);
+ }
+
+ shallow_compare_brk:
+ ;
+
+ valBln ^= (op == Token.SHNE);
+ stack [stackTop] = valBln;
+
+ goto Loop;
+ }
+ goto case Token.IFNE;
+
+ case Token.IFNE:
+ if (stack_boolean (frame, stackTop--)) {
+ frame.pc += 2;
+
+ goto Loop;
+ }
+
+ goto jumplessRun_brk;
+
+ case Token.IFEQ:
+ if (!stack_boolean (frame, stackTop--)) {
+ frame.pc += 2;
+
+ goto Loop;
+ }
+
+ goto jumplessRun_brk;
+
+ case Icode_IFEQ_POP:
+ if (!stack_boolean (frame, stackTop--)) {
+ frame.pc += 2;
+
+ goto Loop;
+ }
+ stack [stackTop--] = null;
+
+ goto jumplessRun_brk;
+
+ case Token.GOTO:
+
+ goto jumplessRun_brk;
+
+ case Icode_GOSUB:
+ ++stackTop;
+ stack [stackTop] = DBL_MRK;
+ sDbl [stackTop] = frame.pc + 2;
+
+ goto jumplessRun_brk;
+
+ case Icode_STARTSUB:
+ if (stackTop == frame.emptyStackTop + 1) {
+ // Call from Icode_GOSUB: store return PC address in the local
+ indexReg += frame.localShift;
+ stack [indexReg] = stack [stackTop];
+ sDbl [indexReg] = sDbl [stackTop];
+ --stackTop;
+ }
+ else {
+ // Call from exception handler: exception object is already stored
+ // in the local
+ if (stackTop != frame.emptyStackTop)
+ Context.CodeBug ();
+ }
+
+ goto Loop;
+ goto case Icode_RETSUB;
+
+ case Icode_RETSUB: {
+ // indexReg: local to store return address
+ if (instructionCounting) {
+ addInstructionCount (cx, frame, 0);
+ }
+ indexReg += frame.localShift;
+ object value = stack [indexReg];
+ if (value != DBL_MRK) {
+ // Invocation from exception handler, restore object to rethrow
+ throwable = value;
+ goto withoutExceptions_brk;
+ }
+ // Normal return from GOSUB
+ frame.pc = (int)sDbl [indexReg];
+ if (instructionCounting) {
+ frame.pcPrevBranch = frame.pc;
+ }
+
+ goto Loop;
+ }
+ goto case Icode_POP;
+
+ case Icode_POP:
+ stack [stackTop] = null;
+ stackTop--;
+
+ goto Loop;
+ goto case Icode_POP_RESULT;
+
+ case Icode_POP_RESULT:
+ frame.result = stack [stackTop];
+ frame.resultDbl = sDbl [stackTop];
+ stack [stackTop] = null;
+ --stackTop;
+
+ goto Loop;
+ goto case Icode_DUP;
+
+ case Icode_DUP:
+ stack [stackTop + 1] = stack [stackTop];
+ sDbl [stackTop + 1] = sDbl [stackTop];
+ stackTop++;
+
+ goto Loop;
+ goto case Icode_DUP2;
+
+ case Icode_DUP2:
+ stack [stackTop + 1] = stack [stackTop - 1];
+ sDbl [stackTop + 1] = sDbl [stackTop - 1];
+ stack [stackTop + 2] = stack [stackTop];
+ sDbl [stackTop + 2] = sDbl [stackTop];
+ stackTop += 2;
+
+ goto Loop;
+ goto case Icode_SWAP;
+
+ case Icode_SWAP: {
+ object o = stack [stackTop];
+ stack [stackTop] = stack [stackTop - 1];
+ stack [stackTop - 1] = o;
+ double d = sDbl [stackTop];
+ sDbl [stackTop] = sDbl [stackTop - 1];
+ sDbl [stackTop - 1] = d;
+
+ goto Loop;
+ }
+ goto case Token.RETURN;
+
+ case Token.RETURN:
+ frame.result = stack [stackTop];
+ frame.resultDbl = sDbl [stackTop];
+ --stackTop;
+
+ goto Loop_brk;
+
+ case Token.RETURN_RESULT:
+
+ goto Loop_brk;
+
+ case Icode_RETUNDEF:
+ frame.result = undefined;
+
+ goto Loop_brk;
+
+ case Token.BITNOT: {
+ int rIntValue = stack_int32 (frame, stackTop);
+ stack [stackTop] = DBL_MRK;
+ sDbl [stackTop] = ~rIntValue;
+
+ goto Loop;
+ }
+ goto case Token.BITAND;
+
+ case Token.BITAND:
+ case Token.BITOR:
+ case Token.BITXOR:
+ case Token.LSH:
+ case Token.RSH: {
+ int rIntValue = stack_int32 (frame, stackTop);
+ --stackTop;
+ int lIntValue = stack_int32 (frame, stackTop);
+ stack [stackTop] = DBL_MRK;
+ switch (op) {
+
+ case Token.BITAND:
+ lIntValue &= rIntValue;
+ break;
+
+ case Token.BITOR:
+ lIntValue |= rIntValue;
+ break;
+
+ case Token.BITXOR:
+ lIntValue ^= rIntValue;
+ break;
+
+ case Token.LSH:
+ lIntValue <<= rIntValue;
+ break;
+
+ case Token.RSH:
+ lIntValue >>= rIntValue;
+ break;
+ }
+ sDbl [stackTop] = lIntValue;
+
+ goto Loop;
+ }
+ goto case Token.URSH;
+
+ case Token.URSH: {
+ int rIntValue = stack_int32 (frame, stackTop) & 0x1F;
+ --stackTop;
+ double lDbl = stack_double (frame, stackTop);
+ stack [stackTop] = DBL_MRK;
+ uint i = (uint)ScriptConvert.ToUint32 (lDbl);
+ sDbl [stackTop] = i >> rIntValue;
+
+ goto Loop;
+ }
+ goto case Token.NEG;
+
+ case Token.NEG:
+ case Token.POS: {
+ double rDbl = stack_double (frame, stackTop);
+ stack [stackTop] = DBL_MRK;
+ if (op == Token.NEG) {
+ rDbl = -rDbl;
+ }
+ sDbl [stackTop] = rDbl;
+
+ goto Loop;
+ }
+ goto case Token.ADD;
+
+ case Token.ADD:
+ --stackTop;
+ DoAdd (stack, sDbl, stackTop, cx);
+
+ goto Loop;
+ goto case Token.SUB;
+
+ case Token.SUB:
+ case Token.MUL:
+ case Token.DIV:
+ case Token.MOD: {
+ double rDbl = stack_double (frame, stackTop);
+ --stackTop;
+ double lDbl = stack_double (frame, stackTop);
+ stack [stackTop] = DBL_MRK;
+ switch (op) {
+
+ case Token.SUB:
+ lDbl -= rDbl;
+ break;
+
+ case Token.MUL:
+ lDbl *= rDbl;
+ break;
+
+ case Token.DIV:
+ lDbl /= rDbl;
+ break;
+
+ case Token.MOD:
+ lDbl %= rDbl;
+ break;
+ }
+ sDbl [stackTop] = lDbl;
+
+ goto Loop;
+ }
+ goto case Token.NOT;
+
+ case Token.NOT:
+ stack [stackTop] = !stack_boolean (frame, stackTop);
+
+ goto Loop;
+ goto case Token.BINDNAME;
+
+ case Token.BINDNAME:
+ stack [++stackTop] = ScriptRuntime.bind (cx, frame.scope, stringReg);
+
+ goto Loop;
+ goto case Token.SETNAME;
+
+ case Token.SETNAME: {
+ object rhs = stack [stackTop];
+ if (rhs == DBL_MRK)
+ rhs = sDbl [stackTop];
+ --stackTop;
+ IScriptable lhs = (IScriptable)stack [stackTop];
+ stack [stackTop] = ScriptRuntime.setName (lhs, rhs, cx, frame.scope, stringReg);
+
+ goto Loop;
+ }
+ goto case Token.DELPROP;
+
+ case Token.DELPROP: {
+ object rhs = stack [stackTop];
+ if (rhs == DBL_MRK)
+ rhs = sDbl [stackTop];
+ --stackTop;
+ object lhs = stack [stackTop];
+ if (lhs == DBL_MRK)
+ lhs = sDbl [stackTop];
+ stack [stackTop] = ScriptRuntime.delete (lhs, rhs, cx);
+
+ goto Loop;
+ }
+ goto case Token.GETPROP;
+
+ case Token.GETPROP: {
+ object lhs = stack [stackTop];
+ if (lhs == DBL_MRK)
+ lhs = sDbl [stackTop];
+ stack [stackTop] = ScriptRuntime.getObjectProp (lhs, stringReg, cx);
+
+ goto Loop;
+ }
+ goto case Token.SETPROP;
+
+ case Token.SETPROP_GETTER:
+ case Token.SETPROP_SETTER:
+ case Token.SETPROP: {
+ object rhs = stack [stackTop];
+ if (rhs == DBL_MRK)
+ rhs = sDbl [stackTop];
+ --stackTop;
+ object lhs = stack [stackTop];
+ if (lhs == DBL_MRK)
+ lhs = sDbl [stackTop];
+
+ switch (op) {
+ case Token.SETPROP_GETTER:
+ ((ScriptableObject)lhs).DefineGetter(stringReg, ((ICallable)rhs));
+ stack[stackTop] = rhs;
+ break;
+
+ case Token.SETPROP_SETTER:
+ ((ScriptableObject)lhs).DefineSetter(stringReg, ((ICallable)rhs));
+ stack[stackTop] = rhs;
+ break;
+
+
+ default:
+ stack [stackTop] = ScriptRuntime.setObjectProp (lhs, stringReg, rhs, cx);
+ break;
+ }
+
+ goto Loop;
+ }
+ goto case Icode_PROP_INC_DEC;
+
+ case Icode_PROP_INC_DEC: {
+ object lhs = stack [stackTop];
+ if (lhs == DBL_MRK)
+ lhs = sDbl [stackTop];
+ stack [stackTop] = ScriptRuntime.propIncrDecr (lhs, stringReg, cx, iCode [frame.pc]);
+ ++frame.pc;
+
+ goto Loop;
+ }
+ goto case Token.GETELEM;
+
+ case Token.GETELEM: {
+ --stackTop;
+ object lhs = stack [stackTop];
+ if (lhs == DBL_MRK) {
+ lhs = sDbl [stackTop];
+ }
+ object value;
+ object id = stack [stackTop + 1];
+ if (id != DBL_MRK) {
+ value = ScriptRuntime.getObjectElem (lhs, id, cx);
+ }
+ else {
+ double d = sDbl [stackTop + 1];
+ value = ScriptRuntime.getObjectIndex (lhs, d, cx);
+ }
+ stack [stackTop] = value;
+
+ goto Loop;
+ }
+ goto case Token.SETELEM;
+
+ case Token.SETELEM: {
+ stackTop -= 2;
+ object rhs = stack [stackTop + 2];
+ if (rhs == DBL_MRK) {
+ rhs = sDbl [stackTop + 2];
+ }
+ object lhs = stack [stackTop];
+ if (lhs == DBL_MRK) {
+ lhs = sDbl [stackTop];
+ }
+ object value;
+ object id = stack [stackTop + 1];
+ if (id != DBL_MRK) {
+ value = ScriptRuntime.setObjectElem (lhs, id, rhs, cx);
+ }
+ else {
+ double d = sDbl [stackTop + 1];
+ value = ScriptRuntime.setObjectIndex (lhs, d, rhs, cx);
+ }
+ stack [stackTop] = value;
+
+ goto Loop;
+ }
+ goto case Icode_ELEM_INC_DEC;
+
+ case Icode_ELEM_INC_DEC: {
+ object rhs = stack [stackTop];
+ if (rhs == DBL_MRK)
+ rhs = sDbl [stackTop];
+ --stackTop;
+ object lhs = stack [stackTop];
+ if (lhs == DBL_MRK)
+ lhs = sDbl [stackTop];
+ stack [stackTop] = ScriptRuntime.elemIncrDecr (lhs, rhs, cx, iCode [frame.pc]);
+ ++frame.pc;
+
+ goto Loop;
+ }
+ goto case Token.GET_REF;
+
+ case Token.GET_REF: {
+ IRef rf = (IRef)stack [stackTop];
+ stack [stackTop] = ScriptRuntime.refGet (rf, cx);
+
+ goto Loop;
+ }
+ goto case Token.SET_REF;
+
+ case Token.SET_REF: {
+ object value = stack [stackTop];
+ if (value == DBL_MRK)
+ value = sDbl [stackTop];
+ --stackTop;
+ IRef rf = (IRef)stack [stackTop];
+ stack [stackTop] = ScriptRuntime.refSet (rf, value, cx);
+
+ goto Loop;
+ }
+ goto case Token.DEL_REF;
+
+ case Token.DEL_REF: {
+ IRef rf = (IRef)stack [stackTop];
+ stack [stackTop] = ScriptRuntime.refDel (rf, cx);
+
+ goto Loop;
+ }
+ goto case Icode_REF_INC_DEC;
+
+ case Icode_REF_INC_DEC: {
+ IRef rf = (IRef)stack [stackTop];
+ stack [stackTop] = ScriptRuntime.refIncrDecr (rf, cx, iCode [frame.pc]);
+ ++frame.pc;
+
+ goto Loop;
+ }
+ goto case Token.LOCAL_LOAD;
+
+ case Token.LOCAL_LOAD:
+ ++stackTop;
+ indexReg += frame.localShift;
+ stack [stackTop] = stack [indexReg];
+ sDbl [stackTop] = sDbl [indexReg];
+
+ goto Loop;
+ goto case Icode_LOCAL_CLEAR;
+
+ case Icode_LOCAL_CLEAR:
+ indexReg += frame.localShift;
+ stack [indexReg] = null;
+
+ goto Loop;
+ goto case Icode_NAME_AND_THIS;
+
+ case Icode_NAME_AND_THIS:
+ // stringReg: name
+ ++stackTop;
+ stack [stackTop] = ScriptRuntime.getNameFunctionAndThis (stringReg, cx, frame.scope);
+ ++stackTop;
+ stack [stackTop] = ScriptRuntime.lastStoredScriptable (cx);
+
+ goto Loop;
+ goto case Icode_PROP_AND_THIS;
+
+ case Icode_PROP_AND_THIS: {
+ object obj = stack [stackTop];
+ if (obj == DBL_MRK)
+ obj = sDbl [stackTop];
+ // stringReg: property
+ stack [stackTop] = ScriptRuntime.getPropFunctionAndThis (obj, stringReg, cx);
+ ++stackTop;
+ stack [stackTop] = ScriptRuntime.lastStoredScriptable (cx);
+
+ goto Loop;
+ }
+ goto case Icode_ELEM_AND_THIS;
+
+ case Icode_ELEM_AND_THIS: {
+ object obj = stack [stackTop - 1];
+ if (obj == DBL_MRK)
+ obj = sDbl [stackTop - 1];
+ object id = stack [stackTop];
+ if (id == DBL_MRK)
+ id = sDbl [stackTop];
+ stack [stackTop - 1] = ScriptRuntime.GetElemFunctionAndThis (obj, id, cx);
+ stack [stackTop] = ScriptRuntime.lastStoredScriptable (cx);
+
+ goto Loop;
+ }
+ goto case Icode_VALUE_AND_THIS;
+
+ case Icode_VALUE_AND_THIS: {
+ object value = stack [stackTop];
+ if (value == DBL_MRK)
+ value = sDbl [stackTop];
+ stack [stackTop] = ScriptRuntime.getValueFunctionAndThis (value, cx);
+ ++stackTop;
+ stack [stackTop] = ScriptRuntime.lastStoredScriptable (cx);
+
+ goto Loop;
+ }
+ goto case Icode_CALLSPECIAL;
+
+ case Icode_CALLSPECIAL: {
+ if (instructionCounting) {
+ cx.instructionCount += INVOCATION_COST;
+ }
+ int callType = iCode [frame.pc] & 0xFF;
+ bool isNew = (iCode [frame.pc + 1] != 0);
+ int sourceLine = GetIndex (iCode, frame.pc + 2);
+
+ // indexReg: number of arguments
+ if (isNew) {
+ // stack change: function arg0 .. argN -> newResult
+ stackTop -= indexReg;
+
+ object function = stack [stackTop];
+ if (function == DBL_MRK)
+ function = sDbl [stackTop];
+ object [] outArgs = GetArgsArray (stack, sDbl, stackTop + 1, indexReg);
+ stack [stackTop] = ScriptRuntime.newSpecial (cx, function, outArgs, frame.scope, callType);
+ }
+ else {
+ // stack change: function thisObj arg0 .. argN -> result
+ stackTop -= (1 + indexReg);
+
+ // Call code generation ensure that stack here
+ // is ... Callable Scriptable
+ IScriptable functionThis = (IScriptable)stack [stackTop + 1];
+ ICallable function = (ICallable)stack [stackTop];
+ object [] outArgs = GetArgsArray (stack, sDbl, stackTop + 2, indexReg);
+ stack [stackTop] = ScriptRuntime.callSpecial (cx, function, functionThis, outArgs, frame.scope, frame.thisObj, callType, frame.idata.itsSourceFile, sourceLine);
+ }
+ frame.pc += 4;
+
+ goto Loop;
+ }
+ goto case Token.CALL;
+
+ case Token.CALL:
+ case Icode_TAIL_CALL:
+ case Token.REF_CALL: {
+ if (instructionCounting) {
+ cx.instructionCount += INVOCATION_COST;
+ }
+ // stack change: function thisObj arg0 .. argN -> result
+ // indexReg: number of arguments
+ stackTop -= (1 + indexReg);
+
+ // CALL generation ensures that fun and funThisObj
+ // are already Scriptable and Callable objects respectively
+ ICallable fun = (ICallable)stack [stackTop];
+ IScriptable funThisObj = (IScriptable)stack [stackTop + 1];
+ if (op == Token.REF_CALL) {
+ object [] outArgs = GetArgsArray (stack, sDbl, stackTop + 2, indexReg);
+ stack [stackTop] = ScriptRuntime.callRef (fun, funThisObj, outArgs, cx);
+
+ goto Loop;
+ }
+ IScriptable calleeScope = frame.scope;
+ if (frame.useActivation) {
+ calleeScope = ScriptableObject.GetTopLevelScope (frame.scope);
+ }
+ if (fun is InterpretedFunction) {
+ InterpretedFunction ifun = (InterpretedFunction)fun;
+ if (frame.fnOrScript.securityDomain == ifun.securityDomain) {
+ CallFrame callParentFrame = frame;
+ CallFrame calleeFrame = new CallFrame ();
+ if (op == Icode_TAIL_CALL) {
+ // In principle tail call can re-use the current
+ // frame and its stack arrays but it is hard to
+ // do properly. Any exceptions that can legally
+ // happen during frame re-initialization including
+ // StackOverflowException during innocent looking
+ // System.arraycopy may leave the current frame
+ // data corrupted leading to undefined behaviour
+ // in the catch code bellow that unwinds JS stack
+ // on exceptions. Then there is issue about frame release
+ // end exceptions there.
+ // To avoid frame allocation a released frame
+ // can be cached for re-use which would also benefit
+ // non-tail calls but it is not clear that this caching
+ // would gain in performance due to potentially
+ // bad iteraction with GC.
+ callParentFrame = frame.parentFrame;
+ }
+ initFrame (cx, calleeScope, funThisObj, stack, sDbl, stackTop + 2, indexReg, ifun, callParentFrame, calleeFrame);
+ if (op == Icode_TAIL_CALL) {
+ // Release the parent
+ ExitFrame (cx, frame, (object)null);
+ }
+ else {
+ frame.savedStackTop = stackTop;
+ frame.savedCallOp = op;
+ }
+ frame = calleeFrame;
+
+ goto StateLoop;
+ }
+ }
+
+ if (fun is Continuation) {
+ // Jump to the captured continuation
+ ContinuationJump cjump;
+ cjump = new ContinuationJump ((Continuation)fun, frame);
+
+ // continuation result is the first argument if any
+ // of contination call
+ if (indexReg == 0) {
+ cjump.result = undefined;
+ }
+ else {
+ cjump.result = stack [stackTop + 2];
+ cjump.resultDbl = sDbl [stackTop + 2];
+ }
+
+ // Start the real unwind job
+ throwable = cjump;
+ break;
+ }
+
+ if (fun is IdFunctionObject) {
+ IdFunctionObject ifun = (IdFunctionObject)fun;
+ if (Continuation.IsContinuationConstructor (ifun)) {
+ captureContinuation (cx, frame, stackTop);
+
+ goto Loop;
+ }
+ }
+
+ object [] outArgs2 = GetArgsArray (stack, sDbl, stackTop + 2, indexReg);
+ stack [stackTop] = fun.Call (cx, calleeScope, funThisObj, outArgs2);
+
+
+ goto Loop;
+ }
+ goto case Token.NEW;
+
+ case Token.NEW: {
+ if (instructionCounting) {
+ cx.instructionCount += INVOCATION_COST;
+ }
+ // stack change: function arg0 .. argN -> newResult
+ // indexReg: number of arguments
+ stackTop -= indexReg;
+
+ object lhs = stack [stackTop];
+ if (lhs is InterpretedFunction) {
+ InterpretedFunction f = (InterpretedFunction)lhs;
+ if (frame.fnOrScript.securityDomain == f.securityDomain) {
+ IScriptable newInstance = f.CreateObject (cx, frame.scope);
+ CallFrame calleeFrame = new CallFrame ();
+ initFrame (cx, frame.scope, newInstance, stack, sDbl, stackTop + 1, indexReg, f, frame, calleeFrame);
+
+ stack [stackTop] = newInstance;
+ frame.savedStackTop = stackTop;
+ frame.savedCallOp = op;
+ frame = calleeFrame;
+
+ goto StateLoop;
+ }
+ }
+ if (!(lhs is IFunction)) {
+ if (lhs == DBL_MRK)
+ lhs = sDbl [stackTop];
+ throw ScriptRuntime.NotFunctionError (lhs);
+ }
+ IFunction fun = (IFunction)lhs;
+
+ if (fun is IdFunctionObject) {
+ IdFunctionObject ifun = (IdFunctionObject)fun;
+ if (Continuation.IsContinuationConstructor (ifun)) {
+ captureContinuation (cx, frame, stackTop);
+
+ goto Loop;
+ }
+ }
+
+ object [] outArgs = GetArgsArray (stack, sDbl, stackTop + 1, indexReg);
+ stack [stackTop] = fun.Construct (cx, frame.scope, outArgs);
+
+ goto Loop;
+ }
+ goto case Token.TYPEOF;
+
+ case Token.TYPEOF: {
+ object lhs = stack [stackTop];
+ if (lhs == DBL_MRK)
+ lhs = sDbl [stackTop];
+ stack [stackTop] = ScriptRuntime.Typeof (lhs);
+
+ goto Loop;
+ }
+ goto case Icode_TYPEOFNAME;
+
+ case Icode_TYPEOFNAME:
+ stack [++stackTop] = ScriptRuntime.TypeofName (frame.scope, stringReg);
+
+ goto Loop;
+ goto case Token.STRING;
+
+ case Token.STRING:
+ stack [++stackTop] = stringReg;
+
+ goto Loop;
+ goto case Icode_SHORTNUMBER;
+
+ case Icode_SHORTNUMBER:
+ ++stackTop;
+ stack [stackTop] = DBL_MRK;
+ sDbl [stackTop] = GetShort (iCode, frame.pc);
+ frame.pc += 2;
+
+ goto Loop;
+ goto case Icode_INTNUMBER;
+
+ case Icode_INTNUMBER:
+ ++stackTop;
+ stack [stackTop] = DBL_MRK;
+ sDbl [stackTop] = GetInt (iCode, frame.pc);
+ frame.pc += 4;
+
+ goto Loop;
+ goto case Token.NUMBER;
+
+ case Token.NUMBER:
+ ++stackTop;
+ stack [stackTop] = DBL_MRK;
+ sDbl [stackTop] = frame.idata.itsDoubleTable [indexReg];
+
+ goto Loop;
+ goto case Token.NAME;
+
+ case Token.NAME:
+ stack [++stackTop] = ScriptRuntime.name (cx, frame.scope, stringReg);
+
+ goto Loop;
+ goto case Icode_NAME_INC_DEC;
+
+ case Icode_NAME_INC_DEC:
+ stack [++stackTop] = ScriptRuntime.nameIncrDecr (frame.scope, stringReg, iCode [frame.pc]);
+ ++frame.pc;
+
+ goto Loop;
+ goto case Icode_SETVAR1;
+
+ case Icode_SETVAR1:
+ indexReg = iCode [frame.pc++];
+ // fallthrough
+ goto case Token.SETVAR;
+
+ case Token.SETVAR:
+ if (!frame.useActivation) {
+ vars [indexReg] = stack [stackTop];
+ varDbls [indexReg] = sDbl [stackTop];
+ }
+ else {
+ object val = stack [stackTop];
+ if (val == DBL_MRK)
+ val = sDbl [stackTop];
+ stringReg = frame.idata.argNames [indexReg];
+ frame.scope.Put (stringReg, frame.scope, val);
+ }
+
+ goto Loop;
+ goto case Icode_GETVAR1;
+
+ case Icode_GETVAR1:
+ indexReg = iCode [frame.pc++];
+ // fallthrough
+ goto case Token.GETVAR;
+
+ case Token.GETVAR:
+ ++stackTop;
+ if (!frame.useActivation) {
+ stack [stackTop] = vars [indexReg];
+ sDbl [stackTop] = varDbls [indexReg];
+ }
+ else {
+ stringReg = frame.idata.argNames [indexReg];
+ stack [stackTop] = frame.scope.Get (stringReg, frame.scope);
+ }
+
+ goto Loop;
+ goto case Icode_VAR_INC_DEC;
+
+ case Icode_VAR_INC_DEC: {
+ // indexReg : varindex
+ ++stackTop;
+ int incrDecrMask = iCode [frame.pc];
+ if (!frame.useActivation) {
+ stack [stackTop] = DBL_MRK;
+ object varValue = vars [indexReg];
+ double d;
+ if (varValue == DBL_MRK) {
+ d = varDbls [indexReg];
+ }
+ else {
+ d = ScriptConvert.ToNumber (varValue);
+ vars [indexReg] = DBL_MRK;
+ }
+ double d2 = ((incrDecrMask & Node.DECR_FLAG) == 0) ? d + 1.0 : d - 1.0;
+ varDbls [indexReg] = d2;
+ sDbl [stackTop] = ((incrDecrMask & Node.POST_FLAG) == 0) ? d2 : d;
+ }
+ else {
+ string varName = frame.idata.argNames [indexReg];
+ stack [stackTop] = ScriptRuntime.nameIncrDecr (frame.scope, varName, incrDecrMask);
+ }
+ ++frame.pc;
+
+ goto Loop;
+ }
+ goto case Icode_ZERO;
+
+ case Icode_ZERO:
+ ++stackTop;
+ stack [stackTop] = DBL_MRK;
+ sDbl [stackTop] = 0;
+
+ goto Loop;
+ goto case Icode_ONE;
+
+ case Icode_ONE:
+ ++stackTop;
+ stack [stackTop] = DBL_MRK;
+ sDbl [stackTop] = 1;
+
+ goto Loop;
+ goto case Token.NULL;
+
+ case Token.NULL:
+ stack [++stackTop] = null;
+
+ goto Loop;
+ goto case Token.THIS;
+
+ case Token.THIS:
+ stack [++stackTop] = frame.thisObj;
+
+ goto Loop;
+ goto case Token.THISFN;
+
+ case Token.THISFN:
+ stack [++stackTop] = frame.fnOrScript;
+
+ goto Loop;
+ goto case Token.FALSE;
+
+ case Token.FALSE:
+ stack [++stackTop] = false;
+
+ goto Loop;
+ goto case Token.TRUE;
+
+ case Token.TRUE:
+ stack [++stackTop] = true;
+
+ goto Loop;
+ goto case Icode_UNDEF;
+
+ case Icode_UNDEF:
+ stack [++stackTop] = undefined;
+
+ goto Loop;
+ goto case Token.ENTERWITH;
+
+ case Token.ENTERWITH: {
+ object lhs = stack [stackTop];
+ if (lhs == DBL_MRK)
+ lhs = sDbl [stackTop];
+ --stackTop;
+ frame.scope = ScriptRuntime.enterWith (lhs, cx, frame.scope);
+
+ goto Loop;
+ }
+ goto case Token.LEAVEWITH;
+
+ case Token.LEAVEWITH:
+ frame.scope = ScriptRuntime.leaveWith (frame.scope);
+
+ goto Loop;
+ goto case Token.CATCH_SCOPE;
+
+ case Token.CATCH_SCOPE: {
+ // stack top: exception object
+ // stringReg: name of exception variable
+ // indexReg: local for exception scope
+ --stackTop;
+ indexReg += frame.localShift;
+
+ bool afterFirstScope = (frame.idata.itsICode [frame.pc] != 0);
+
+ Exception caughtException = (Exception)stack [stackTop + 1];
+ IScriptable lastCatchScope;
+ if (!afterFirstScope) {
+ lastCatchScope = null;
+ }
+ else {
+ lastCatchScope = (IScriptable)stack [indexReg];
+ }
+ stack [indexReg] = ScriptRuntime.NewCatchScope (caughtException, lastCatchScope, stringReg, cx, frame.scope);
+ ++frame.pc;
+
+ goto Loop;
+ }
+ goto case Token.ENUM_INIT_KEYS;
+
+ case Token.ENUM_INIT_KEYS:
+ case Token.ENUM_INIT_VALUES: {
+ object lhs = stack [stackTop];
+ if (lhs == DBL_MRK)
+ lhs = sDbl [stackTop];
+ --stackTop;
+ indexReg += frame.localShift;
+
+ if (lhs is IIdEnumerable) {
+ stack [indexReg] = ((IIdEnumerable)lhs).GetEnumeration (cx, (op == Token.ENUM_INIT_VALUES));
+ }
+ else {
+ stack [indexReg] = new IdEnumeration (lhs, cx, (op == Token.ENUM_INIT_VALUES));
+ }
+
+
+ goto Loop;
+ }
+ goto case Token.ENUM_NEXT;
+
+ case Token.ENUM_NEXT:
+ case Token.ENUM_ID: {
+ indexReg += frame.localShift;
+ IdEnumeration val = (IdEnumeration)stack [indexReg];
+ ++stackTop;
+ stack [stackTop] = (op == Token.ENUM_NEXT) ? val.MoveNext () : val.Current (cx);
+
+ goto Loop;
+ }
+ goto case Token.REF_SPECIAL;
+
+ case Token.REF_SPECIAL: {
+ //stringReg: name of special property
+ object obj = stack [stackTop];
+ if (obj == DBL_MRK)
+ obj = sDbl [stackTop];
+ stack [stackTop] = ScriptRuntime.specialRef (obj, stringReg, cx);
+
+ goto Loop;
+ }
+ goto case Token.REF_MEMBER;
+
+ case Token.REF_MEMBER: {
+ //indexReg: flags
+ object elem = stack [stackTop];
+ if (elem == DBL_MRK)
+ elem = sDbl [stackTop];
+ --stackTop;
+ object obj = stack [stackTop];
+ if (obj == DBL_MRK)
+ obj = sDbl [stackTop];
+ stack [stackTop] = ScriptRuntime.memberRef (obj, elem, cx, indexReg);
+
+ goto Loop;
+ }
+ goto case Token.REF_NS_MEMBER;
+
+ case Token.REF_NS_MEMBER: {
+ //indexReg: flags
+ object elem = stack [stackTop];
+ if (elem == DBL_MRK)
+ elem = sDbl [stackTop];
+ --stackTop;
+ object ns = stack [stackTop];
+ if (ns == DBL_MRK)
+ ns = sDbl [stackTop];
+ --stackTop;
+ object obj = stack [stackTop];
+ if (obj == DBL_MRK)
+ obj = sDbl [stackTop];
+ stack [stackTop] = ScriptRuntime.memberRef (obj, ns, elem, cx, indexReg);
+
+ goto Loop;
+ }
+ goto case Token.REF_NAME;
+
+ case Token.REF_NAME: {
+ //indexReg: flags
+ object name = stack [stackTop];
+ if (name == DBL_MRK)
+ name = sDbl [stackTop];
+ stack [stackTop] = ScriptRuntime.nameRef (name, cx, frame.scope, indexReg);
+
+ goto Loop;
+ }
+ goto case Token.REF_NS_NAME;
+
+ case Token.REF_NS_NAME: {
+ //indexReg: flags
+ object name = stack [stackTop];
+ if (name == DBL_MRK)
+ name = sDbl [stackTop];
+ --stackTop;
+ object ns = stack [stackTop];
+ if (ns == DBL_MRK)
+ ns = sDbl [stackTop];
+ stack [stackTop] = ScriptRuntime.nameRef (ns, name, cx, frame.scope, indexReg);
+
+ goto Loop;
+ }
+ goto case Icode_SCOPE_LOAD;
+
+ case Icode_SCOPE_LOAD:
+ indexReg += frame.localShift;
+ frame.scope = (IScriptable)stack [indexReg];
+
+ goto Loop;
+ goto case Icode_SCOPE_SAVE;
+
+ case Icode_SCOPE_SAVE:
+ indexReg += frame.localShift;
+ stack [indexReg] = frame.scope;
+
+ goto Loop;
+ goto case Icode_CLOSURE_EXPR;
+
+ case Icode_CLOSURE_EXPR: {
+ InterpretedFunction fun = InterpretedFunction.createFunction (cx, frame.scope, frame.fnOrScript, indexReg);
+ stack [++stackTop] = fun;
+ }
+ goto Loop;
+ goto case Icode_CLOSURE_STMT;
+
+ case Icode_CLOSURE_STMT:
+ initFunction (cx, frame.scope, frame.fnOrScript, indexReg);
+
+ goto Loop;
+ goto case Token.REGEXP;
+
+ case Token.REGEXP:
+ stack [++stackTop] = frame.scriptRegExps [indexReg];
+
+ goto Loop;
+ goto case Icode_LITERAL_NEW;
+
+ case Icode_LITERAL_NEW:
+ // indexReg: number of values in the literal
+ ++stackTop;
+ stack [stackTop] = new object [indexReg];
+ sDbl [stackTop] = 0;
+
+ goto Loop;
+ goto case Icode_LITERAL_SET;
+
+ case Icode_LITERAL_SET: {
+ object value = stack [stackTop];
+ if (value == DBL_MRK)
+ value = sDbl [stackTop];
+ --stackTop;
+ int i = (int)sDbl [stackTop];
+ ((object [])stack [stackTop]) [i] = value;
+ sDbl [stackTop] = i + 1;
+
+ goto Loop;
+ }
+ goto case Token.ARRAYLIT;
+
+ case Token.ARRAYLIT:
+ case Icode_SPARE_ARRAYLIT:
+ case Token.OBJECTLIT: {
+ object [] data = (object [])stack [stackTop];
+ object val;
+ if (op == Token.OBJECTLIT) {
+ object [] ids = (object [])frame.idata.literalIds [indexReg];
+ val = ScriptRuntime.newObjectLiteral (ids, data, cx, frame.scope);
+ }
+ else {
+ int [] skipIndexces = null;
+ if (op == Icode_SPARE_ARRAYLIT) {
+ skipIndexces = (int [])frame.idata.literalIds [indexReg];
+ }
+ val = ScriptRuntime.newArrayLiteral (data, skipIndexces, cx, frame.scope);
+ }
+ stack [stackTop] = val;
+
+ goto Loop;
+ }
+ goto case Icode_ENTERDQ;
+
+ case Icode_ENTERDQ: {
+ object lhs = stack [stackTop];
+ if (lhs == DBL_MRK)
+ lhs = sDbl [stackTop];
+ --stackTop;
+ frame.scope = ScriptRuntime.enterDotQuery (lhs, frame.scope);
+
+ goto Loop;
+ }
+ goto case Icode_LEAVEDQ;
+
+ case Icode_LEAVEDQ: {
+ bool valBln = stack_boolean (frame, stackTop);
+ object x = ScriptRuntime.updateDotQuery (valBln, frame.scope);
+ if (x != null) {
+ stack [stackTop] = x;
+ frame.scope = ScriptRuntime.leaveDotQuery (frame.scope);
+ frame.pc += 2;
+
+ goto Loop;
+ }
+ // reset stack and PC to code after ENTERDQ
+ --stackTop;
+
+ goto jumplessRun_brk;
+ }
+
+ case Token.DEFAULTNAMESPACE: {
+ object value = stack [stackTop];
+ if (value == DBL_MRK)
+ value = sDbl [stackTop];
+ stack [stackTop] = ScriptRuntime.setDefaultNamespace (value, cx);
+
+ goto Loop;
+ }
+ goto case Token.ESCXMLATTR;
+
+ case Token.ESCXMLATTR: {
+ object value = stack [stackTop];
+ if (value != DBL_MRK) {
+ stack [stackTop] = ScriptRuntime.escapeAttributeValue (value, cx);
+ }
+
+ goto Loop;
+ }
+ goto case Token.ESCXMLTEXT;
+
+ case Token.ESCXMLTEXT: {
+ object value = stack [stackTop];
+ if (value != DBL_MRK) {
+ stack [stackTop] = ScriptRuntime.escapeTextValue (value, cx);
+ }
+
+ goto Loop;
+ }
+ goto case Icode_LINE;
+
+ case Icode_DEBUGGER: {
+ if (frame.debuggerFrame != null) {
+ frame.debuggerFrame.OnDebuggerStatement(cx);
+ }
+ break;
+ }
+
+ case Icode_LINE:
+ frame.pcSourceLineStart = frame.pc;
+ if (frame.debuggerFrame != null) {
+ int line = GetIndex (iCode, frame.pc);
+ frame.debuggerFrame.OnLineChange (cx, line);
+ }
+ frame.pc += 2;
+
+ goto Loop;
+ goto case Icode_REG_IND_C0;
+
+ case Icode_REG_IND_C0:
+ indexReg = 0;
+
+ goto Loop;
+ goto case Icode_REG_IND_C1;
+
+ case Icode_REG_IND_C1:
+ indexReg = 1;
+
+ goto Loop;
+ goto case Icode_REG_IND_C2;
+
+ case Icode_REG_IND_C2:
+ indexReg = 2;
+
+ goto Loop;
+ goto case Icode_REG_IND_C3;
+
+ case Icode_REG_IND_C3:
+ indexReg = 3;
+
+ goto Loop;
+ goto case Icode_REG_IND_C4;
+
+ case Icode_REG_IND_C4:
+ indexReg = 4;
+
+ goto Loop;
+ goto case Icode_REG_IND_C5;
+
+ case Icode_REG_IND_C5:
+ indexReg = 5;
+
+ goto Loop;
+ goto case Icode_REG_IND1;
+
+ case Icode_REG_IND1:
+ indexReg = 0xFF & iCode [frame.pc];
+ ++frame.pc;
+
+ goto Loop;
+ goto case Icode_REG_IND2;
+
+ case Icode_REG_IND2:
+ indexReg = GetIndex (iCode, frame.pc);
+ frame.pc += 2;
+
+ goto Loop;
+ goto case Icode_REG_IND4;
+
+ case Icode_REG_IND4:
+ indexReg = GetInt (iCode, frame.pc);
+ frame.pc += 4;
+
+ goto Loop;
+ goto case Icode_REG_STR_C0;
+
+ case Icode_REG_STR_C0:
+ stringReg = strings [0];
+
+ goto Loop;
+ goto case Icode_REG_STR_C1;
+
+ case Icode_REG_STR_C1:
+ stringReg = strings [1];
+
+ goto Loop;
+ goto case Icode_REG_STR_C2;
+
+ case Icode_REG_STR_C2:
+ stringReg = strings [2];
+
+ goto Loop;
+ goto case Icode_REG_STR_C3;
+
+ case Icode_REG_STR_C3:
+ stringReg = strings [3];
+
+ goto Loop;
+ goto case Icode_REG_STR1;
+
+ case Icode_REG_STR1:
+ stringReg = strings [0xFF & iCode [frame.pc]];
+ ++frame.pc;
+
+ goto Loop;
+ goto case Icode_REG_STR2;
+
+ case Icode_REG_STR2:
+ stringReg = strings [GetIndex (iCode, frame.pc)];
+ frame.pc += 2;
+
+ goto Loop;
+ goto case Icode_REG_STR4;
+
+ case Icode_REG_STR4:
+ stringReg = strings [GetInt (iCode, frame.pc)];
+ frame.pc += 4;
+
+ goto Loop;
+ goto default;
+
+ default:
+ dumpICode (frame.idata);
+ throw new Exception ("Unknown icode : " + op + " @ pc : " + (frame.pc - 1));
+
+ } // end of interpreter switch
+ }
+
+ jumplessRun_brk:
+ ;
+ // end of jumplessRun label block
+
+ // This should be reachable only for jump implementation
+ // when pc points to encoded target offset
+ if (instructionCounting) {
+ addInstructionCount (cx, frame, 2);
+ }
+ int offset = GetShort (iCode, frame.pc);
+ if (offset != 0) {
+ // -1 accounts for pc pointing to jump opcode + 1
+ frame.pc += offset - 1;
+ }
+ else {
+ frame.pc = frame.idata.longJumps.getExistingInt (frame.pc);
+ }
+ if (instructionCounting) {
+ frame.pcPrevBranch = frame.pc;
+ }
+
+ goto Loop;
+
+ Loop:
+ ;
+ }
+
+ Loop_brk:
+ ;
+ // end of Loop: for
+
+ ExitFrame (cx, frame, (object)null);
+ interpreterResult = frame.result;
+ interpreterResultDbl = frame.resultDbl;
+ if (frame.parentFrame != null) {
+ frame = frame.parentFrame;
+ if (frame.frozen) {
+ frame = frame.cloneFrozen ();
+ }
+ setCallResult (frame, interpreterResult, interpreterResultDbl);
+ interpreterResult = null; // Help GC
+
+ goto StateLoop;
+ }
+
+ goto StateLoop_brk;
+ }
+ // end of interpreter withoutExceptions: try
+ catch (Exception ex) {
+ if (throwable != null) {
+ // This is serious bug and it is better to track it ASAP
+ throw new Exception ();
+ }
+ throwable = ex;
+ }
+
+ withoutExceptions_brk:
+
+ // This should be reachable only after above catch or from
+ // finally when it needs to propagate exception or from
+ // explicit throw
+ if (throwable == null)
+ Context.CodeBug ();
+
+ // Exception type
+ const int EX_CATCH_STATE = 2; // Can execute JS catch
+ const int EX_FINALLY_STATE = 1; // Can execute JS finally
+ const int EX_NO_JS_STATE = 0; // Terminate JS execution
+
+ int exState;
+ ContinuationJump cjump2 = null;
+
+ if (throwable is EcmaScriptThrow) {
+ exState = EX_CATCH_STATE;
+ }
+ else if (throwable is EcmaScriptError) {
+ // an offical ECMA error object,
+ exState = EX_CATCH_STATE;
+ }
+ else if (throwable is EcmaScriptRuntimeException) {
+ exState = EX_CATCH_STATE;
+ }
+ else if (throwable is EcmaScriptException) {
+ exState = EX_FINALLY_STATE;
+ }
+ else if (throwable is Exception) {
+ exState = EX_NO_JS_STATE;
+ }
+ else {
+ // It must be ContinuationJump
+ exState = EX_FINALLY_STATE;
+ cjump2 = (ContinuationJump)throwable;
+ }
+
+ if (instructionCounting) {
+ try {
+ addInstructionCount (cx, frame, EXCEPTION_COST);
+ }
+ catch (Exception ex) {
+ // Error from instruction counting
+ // => unconditionally terminate JS
+ throwable = ex;
+ cjump2 = null;
+ exState = EX_NO_JS_STATE;
+ }
+ }
+ if (frame.debuggerFrame != null && throwable is Exception) {
+ // Call debugger only for RuntimeException
+ Exception rex = (Exception)throwable;
+ try {
+ frame.debuggerFrame.OnExceptionThrown (cx, rex);
+ }
+ catch (Exception ex) {
+ // Any exception from debugger
+ // => unconditionally terminate JS
+ throwable = ex;
+ cjump2 = null;
+ exState = EX_NO_JS_STATE;
+ }
+ }
+
+ for (; ; ) {
+ if (exState != EX_NO_JS_STATE) {
+ bool onlyFinally = (exState != EX_CATCH_STATE);
+ indexReg = getExceptionHandler (frame, onlyFinally);
+ if (indexReg >= 0) {
+ // We caught an exception, restart the loop
+ // with exception pending the processing at the loop
+ // start
+
+ goto StateLoop;
+ }
+ }
+ // No allowed execption handlers in this frame, unwind
+ // to parent and try to look there
+
+ ExitFrame (cx, frame, throwable);
+
+ frame = frame.parentFrame;
+ if (frame == null) {
+ break;
+ }
+ if (cjump2 != null && cjump2.branchFrame == frame) {
+ // Continuation branch point was hit,
+ // restart the state loop to reenter continuation
+ indexReg = -1;
+
+ goto StateLoop;
+ }
+ }
+
+ // No more frames, rethrow the exception or deal with continuation
+ if (cjump2 != null) {
+ if (cjump2.branchFrame != null) {
+ // The above loop should locate the top frame
+ Context.CodeBug ();
+ }
+ if (cjump2.capturedFrame != null) {
+ // Restarting detached continuation
+ indexReg = -1;
+
+ goto StateLoop;
+ }
+ // Return continuation result to the caller
+ interpreterResult = cjump2.result;
+ interpreterResultDbl = cjump2.resultDbl;
+ throwable = null;
+ }
+
+ goto StateLoop_brk;
+
+ StateLoop:
+ ;
+ }
+
+ StateLoop_brk:
+ ;
+ // end of StateLoop: for(;;)
+
+ // Do cleanups/restorations before the final return or throw
+
+ if (cx.previousInterpreterInvocations != null && cx.previousInterpreterInvocations.size () != 0) {
+ cx.lastInterpreterFrame = cx.previousInterpreterInvocations.pop ();
+ }
+ else {
+ // It was the last interpreter frame on the stack
+ cx.lastInterpreterFrame = null;
+ // Force GC of the value cx.previousInterpreterInvocations
+ cx.previousInterpreterInvocations = null;
+ }
+
+ if (throwable != null) {
+ if (throwable is Helpers.StackOverflowVerifierException) {
+ throw Context.ReportRuntimeError (
+ ScriptRuntime.GetMessage ("mag.too.deep.parser.recursion"));
+ }
+ throw (Exception)throwable;
+ }
+
+ return (interpreterResult != DBL_MRK) ? interpreterResult :
+ interpreterResultDbl;
+ }
+
+ static void initFrame (Context cx, IScriptable callerScope, IScriptable thisObj, object [] args, double [] argsDbl, int argShift, int argCount, InterpretedFunction fnOrScript, CallFrame parentFrame, CallFrame frame)
+ {
+ InterpreterData idata = fnOrScript.idata;
+
+ bool useActivation = idata.itsNeedsActivation;
+ DebugFrame debuggerFrame = null;
+ if (cx.m_Debugger != null) {
+ debuggerFrame = cx.m_Debugger.GetFrame (cx, idata);
+ if (debuggerFrame != null) {
+ useActivation = true;
+ }
+ }
+
+ if (useActivation) {
+ // Copy args to new array to pass to enterActivationFunction
+ // or debuggerFrame.onEnter
+ if (argsDbl != null) {
+ args = GetArgsArray (args, argsDbl, argShift, argCount);
+ }
+ argShift = 0;
+ argsDbl = null;
+ }
+
+ IScriptable scope;
+ if (idata.itsFunctionType != 0) {
+ if (!idata.useDynamicScope) {
+ scope = fnOrScript.ParentScope;
+ }
+ else {
+ scope = callerScope;
+ }
+
+ if (useActivation) {
+ scope = ScriptRuntime.createFunctionActivation (fnOrScript, scope, args);
+ }
+ }
+ else {
+ scope = callerScope;
+ ScriptRuntime.initScript (fnOrScript, thisObj, cx, scope, fnOrScript.idata.evalScriptFlag);
+ }
+
+ if (idata.itsNestedFunctions != null) {
+ if (idata.itsFunctionType != 0 && !idata.itsNeedsActivation)
+ Context.CodeBug ();
+ for (int i = 0; i < idata.itsNestedFunctions.Length; i++) {
+ InterpreterData fdata = idata.itsNestedFunctions [i];
+ if (fdata.itsFunctionType == FunctionNode.FUNCTION_STATEMENT) {
+ initFunction (cx, scope, fnOrScript, i);
+ }
+ }
+ }
+
+ IScriptable [] scriptRegExps = null;
+ if (idata.itsRegExpLiterals != null) {
+ // Wrapped regexps for functions are stored in
+ // InterpretedFunction
+ // but for script which should not contain references to scope
+ // the regexps re-wrapped during each script execution
+ if (idata.itsFunctionType != 0) {
+ scriptRegExps = fnOrScript.functionRegExps;
+ }
+ else {
+ scriptRegExps = fnOrScript.createRegExpWraps (cx, scope);
+ }
+ }
+
+ // Initialize args, vars, locals and stack
+
+ int emptyStackTop = idata.itsMaxVars + idata.itsMaxLocals - 1;
+ int maxFrameArray = idata.itsMaxFrameArray;
+ if (maxFrameArray != emptyStackTop + idata.itsMaxStack + 1)
+ Context.CodeBug ();
+
+ object [] stack;
+ double [] sDbl;
+ bool stackReuse;
+ if (frame.stack != null && maxFrameArray <= frame.stack.Length) {
+ // Reuse stacks from old frame
+ stackReuse = true;
+ stack = frame.stack;
+ sDbl = frame.sDbl;
+ }
+ else {
+ stackReuse = false;
+ stack = new object [maxFrameArray];
+ sDbl = new double [maxFrameArray];
+ }
+
+ int definedArgs = idata.argCount;
+ if (definedArgs > argCount) {
+ definedArgs = argCount;
+ }
+
+ // Fill the frame structure
+
+ frame.parentFrame = parentFrame;
+ frame.frameIndex = (parentFrame == null) ? 0 : parentFrame.frameIndex + 1;
+ if (frame.frameIndex > cx.MaximumInterpreterStackDepth)
+ throw ScriptRuntime.TypeErrorById ("msg.stackoverflow");
+ frame.frozen = false;
+
+ frame.fnOrScript = fnOrScript;
+ frame.idata = idata;
+
+ frame.stack = stack;
+ frame.sDbl = sDbl;
+ frame.varSource = frame;
+ frame.localShift = idata.itsMaxVars;
+ frame.emptyStackTop = emptyStackTop;
+
+ frame.debuggerFrame = debuggerFrame;
+ frame.useActivation = useActivation;
+
+ frame.thisObj = thisObj;
+ frame.scriptRegExps = scriptRegExps;
+
+ // Initialize initial values of variables that change during
+ // interpretation.
+ frame.result = Undefined.Value;
+ frame.pc = 0;
+ frame.pcPrevBranch = 0;
+ frame.pcSourceLineStart = idata.firstLinePC;
+ frame.scope = scope;
+
+ frame.savedStackTop = emptyStackTop;
+ frame.savedCallOp = 0;
+
+ Array.Copy (args, argShift, stack, 0, definedArgs);
+ if (argsDbl != null) {
+ Array.Copy (argsDbl, argShift, sDbl, 0, definedArgs);
+ }
+ for (int i = definedArgs; i != idata.itsMaxVars; ++i) {
+ stack [i] = Undefined.Value;
+ }
+ if (stackReuse) {
+ // Clean the stack part and space beyond stack if any
+ // of the old array to allow to GC objects there
+ for (int i = emptyStackTop + 1; i != stack.Length; ++i) {
+ stack [i] = null;
+ }
+ }
+
+ EnterFrame (cx, frame, args);
+ }
+
+ static bool isFrameEnterExitRequired (CallFrame frame)
+ {
+ return frame.debuggerFrame != null || frame.idata.itsNeedsActivation;
+ }
+
+ static void EnterFrame (Context cx, CallFrame frame, object [] args)
+ {
+ if (frame.debuggerFrame != null) {
+ frame.debuggerFrame.OnEnter (cx, frame.scope, frame.thisObj, args);
+ }
+ if (frame.idata.itsNeedsActivation) {
+ // Enter activation only when itsNeedsActivation true, not when
+ // useActivation holds since debugger should not interfere
+ // with activation chaining
+ ScriptRuntime.enterActivationFunction (cx, frame.scope);
+ }
+ }
+
+ static void ExitFrame (Context cx, CallFrame frame, object throwable)
+ {
+ if (frame.idata.itsNeedsActivation) {
+ ScriptRuntime.exitActivationFunction (cx);
+ }
+
+ if (frame.debuggerFrame != null) {
+ try {
+ if (throwable is Exception) {
+ frame.debuggerFrame.OnExit (cx, true, throwable);
+ }
+ else {
+ object result;
+ ContinuationJump cjump = (ContinuationJump)throwable;
+ if (cjump == null) {
+ result = frame.result;
+ }
+ else {
+ result = cjump.result;
+ }
+ if (result == UniqueTag.DoubleMark) {
+ double resultDbl;
+ if (cjump == null) {
+ resultDbl = frame.resultDbl;
+ }
+ else {
+ resultDbl = cjump.resultDbl;
+ }
+ result = resultDbl;
+ }
+ frame.debuggerFrame.OnExit (cx, false, result);
+ }
+ }
+ catch (Exception ex) {
+ Console.Error.WriteLine ("USAGE WARNING: onExit terminated with exception");
+ Console.Error.WriteLine (ex.ToString ());
+ }
+ }
+ }
+
+ static void setCallResult (CallFrame frame, object callResult, double callResultDbl)
+ {
+ if (frame.savedCallOp == Token.CALL) {
+ frame.stack [frame.savedStackTop] = callResult;
+ frame.sDbl [frame.savedStackTop] = callResultDbl;
+ }
+ else if (frame.savedCallOp == Token.NEW) {
+ // If construct returns scriptable,
+ // then it replaces on stack top saved original instance
+ // of the object.
+ if (callResult is IScriptable) {
+ frame.stack [frame.savedStackTop] = callResult;
+ }
+ }
+ else {
+ Context.CodeBug ();
+ }
+ frame.savedCallOp = 0;
+ }
+
+ static void captureContinuation (Context cx, CallFrame frame, int stackTop)
+ {
+ Continuation c = new Continuation ();
+ ScriptRuntime.setObjectProtoAndParent (c, ScriptRuntime.getTopCallScope (cx));
+
+ // Make sure that all frames upstack frames are frozen
+ CallFrame x = frame.parentFrame;
+ while (x != null && !x.frozen) {
+ x.frozen = true;
+ // Allow to GC unused stack space
+ for (int i = x.savedStackTop + 1; i != x.stack.Length; ++i) {
+ // Allow to GC unused stack space
+ x.stack [i] = null;
+ }
+ if (x.savedCallOp == Token.CALL) {
+ // the call will always overwrite the stack top with the result
+ x.stack [x.savedStackTop] = null;
+ }
+ else {
+ if (x.savedCallOp != Token.NEW)
+ Context.CodeBug ();
+ // the new operator uses stack top to store the constructed
+ // object so it shall not be cleared: see comments in
+ // setCallResult
+ }
+ x = x.parentFrame;
+ }
+
+ c.initImplementation (frame.parentFrame);
+ frame.stack [stackTop] = c;
+ }
+
+ static int stack_int32 (CallFrame frame, int i)
+ {
+ object x = frame.stack [i];
+ double value;
+ if (x == UniqueTag.DoubleMark) {
+ value = frame.sDbl [i];
+ }
+ else {
+ value = ScriptConvert.ToNumber (x);
+ }
+ return ScriptConvert.ToInt32 (value);
+ }
+
+ static double stack_double (CallFrame frame, int i)
+ {
+ object x = frame.stack [i];
+ if (x != UniqueTag.DoubleMark) {
+ return ScriptConvert.ToNumber (x);
+ }
+ else {
+ return frame.sDbl [i];
+ }
+ }
+
+ static bool stack_boolean (CallFrame frame, int i)
+ {
+ object x = frame.stack [i];
+ if (x is bool) {
+ return (bool)x;
+ }
+ else if (x == UniqueTag.DoubleMark) {
+ double d = frame.sDbl [i];
+ return !double.IsNaN (d) && d != 0.0;
+ }
+ else if (x == null || x == Undefined.Value) {
+ return false;
+ }
+ else if (CliHelper.IsNumber (x)) {
+ double d = Convert.ToDouble (x);
+ return (!double.IsNaN (d) && d != 0.0);
+ }
+ else {
+ return ScriptConvert.ToBoolean (x);
+ }
+ }
+
+ static void DoAdd (object [] stack, double [] sDbl, int stackTop, Context cx)
+ {
+ object rhs = stack [stackTop + 1];
+ object lhs = stack [stackTop];
+ double d;
+ bool leftRightOrder;
+ if (rhs == UniqueTag.DoubleMark) {
+ d = sDbl [stackTop + 1];
+ if (lhs == UniqueTag.DoubleMark) {
+ sDbl [stackTop] += d;
+ return;
+ }
+ leftRightOrder = true;
+ // fallthrough to object + number code
+ }
+ else if (lhs == UniqueTag.DoubleMark) {
+ d = sDbl [stackTop];
+ lhs = rhs;
+ leftRightOrder = false;
+ // fallthrough to object + number code
+ }
+ else {
+ if (lhs is IScriptable || rhs is IScriptable) {
+ stack [stackTop] = ScriptRuntime.Add (lhs, rhs, cx);
+ }
+ else if (lhs is string) {
+ string lstr = (string)lhs;
+ string rstr = ScriptConvert.ToString (rhs);
+ stack [stackTop] = string.Concat (lstr, rstr);
+ }
+ else if (rhs is string) {
+ string lstr = ScriptConvert.ToString (lhs);
+ string rstr = (string)rhs;
+ stack [stackTop] = string.Concat (lstr, rstr);
+ }
+ else {
+ double lDbl = (CliHelper.IsNumber (lhs)) ? Convert.ToDouble (lhs) : ScriptConvert.ToNumber (lhs);
+ double rDbl = (CliHelper.IsNumber (rhs)) ? Convert.ToDouble (rhs) : ScriptConvert.ToNumber (rhs);
+ stack [stackTop] = UniqueTag.DoubleMark;
+ sDbl [stackTop] = lDbl + rDbl;
+ }
+ return;
+ }
+
+ // handle object(lhs) + number(d) code
+ if (lhs is IScriptable) {
+ rhs = d;
+ if (!leftRightOrder) {
+ object tmp = lhs;
+ lhs = rhs;
+ rhs = tmp;
+ }
+ stack [stackTop] = ScriptRuntime.Add (lhs, rhs, cx);
+ }
+ else if (lhs is string) {
+ string lstr = (string)lhs;
+ string rstr = ScriptConvert.ToString (d);
+ if (leftRightOrder) {
+ stack [stackTop] = string.Concat (lstr, rstr);
+ }
+ else {
+ stack [stackTop] = string.Concat (rstr, lstr);
+ }
+ }
+ else {
+ double lDbl = (CliHelper.IsNumber (lhs)) ? Convert.ToDouble (lhs) : ScriptConvert.ToNumber (lhs);
+ stack [stackTop] = UniqueTag.DoubleMark;
+ sDbl [stackTop] = lDbl + d;
+ }
+ }
+
+ void addGotoOp (int gotoOp)
+ {
+ sbyte [] array = itsData.itsICode;
+ int top = itsICodeTop;
+ if (top + 3 > array.Length) {
+ array = increaseICodeCapasity (3);
+ }
+ array [top] = (sbyte)gotoOp;
+ // Offset would written later
+ itsICodeTop = top + 1 + 2;
+ }
+
+
+ static object [] GetArgsArray (object [] stack, double [] sDbl, int shift, int count)
+ {
+ if (count == 0) {
+ return ScriptRuntime.EmptyArgs;
+ }
+ object [] args = new object [count];
+ for (int i = 0; i != count; ++i, ++shift) {
+ object val = stack [shift];
+ if (val == UniqueTag.DoubleMark) {
+ val = sDbl [shift];
+ }
+ args [i] = val;
+ }
+ return args;
+ }
+
+ static void addInstructionCount (Context cx, CallFrame frame, int extra)
+ {
+ cx.instructionCount += frame.pc - frame.pcPrevBranch + extra;
+ if (cx.instructionCount > cx.instructionThreshold) {
+ cx.ObserveInstructionCount (cx.instructionCount);
+ cx.instructionCount = 0;
+ }
+ }
+
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/InterpreterData.cs b/src/EcmaScript.NET/InterpreterData.cs
similarity index 96%
rename from Code/EcmaScript.NET/InterpreterData.cs
rename to src/EcmaScript.NET/InterpreterData.cs
index c610843..d75dcb8 100644
--- a/Code/EcmaScript.NET/InterpreterData.cs
+++ b/src/EcmaScript.NET/InterpreterData.cs
@@ -1,186 +1,186 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-using EcmaScript.NET.Debugging;
-using EcmaScript.NET.Collections;
-
-namespace EcmaScript.NET
-{
-
- internal sealed class InterpreterData : DebuggableScript
- {
- public bool TopLevel
- {
- get
- {
- return topLevel;
- }
-
- }
- public string FunctionName
- {
- get
- {
- return itsName;
- }
-
- }
- public int ParamCount
- {
- get
- {
- return argCount;
- }
-
- }
- public int ParamAndVarCount
- {
- get
- {
- return argNames.Length;
- }
-
- }
- public string SourceName
- {
- get
- {
- return itsSourceFile;
- }
-
- }
- public bool GeneratedScript
- {
- get
- {
- return ScriptRuntime.isGeneratedScript (itsSourceFile);
- }
-
- }
- public int [] LineNumbers
- {
- get
- {
- return Interpreter.getLineNumbers (this);
- }
-
- }
- public int FunctionCount
- {
- get
- {
- return (itsNestedFunctions == null) ? 0 : itsNestedFunctions.Length;
- }
-
- }
- public DebuggableScript Parent
- {
- get
- {
- return parentData;
- }
-
- }
-
- internal const int INITIAL_MAX_ICODE_LENGTH = 1024;
- internal const int INITIAL_STRINGTABLE_SIZE = 64;
- internal const int INITIAL_NUMBERTABLE_SIZE = 64;
-
- internal InterpreterData (Context.Versions languageVersion, string sourceFile, string encodedSource)
- {
- this.languageVersion = languageVersion;
- this.itsSourceFile = sourceFile;
- this.encodedSource = encodedSource;
-
- Init ();
- }
-
- internal InterpreterData (InterpreterData parent)
- {
- this.parentData = parent;
- this.languageVersion = parent.languageVersion;
- this.itsSourceFile = parent.itsSourceFile;
- this.encodedSource = parent.encodedSource;
-
- Init ();
- }
-
- private void Init ()
- {
- itsICode = new sbyte [INITIAL_MAX_ICODE_LENGTH];
- itsStringTable = new string [INITIAL_STRINGTABLE_SIZE];
- }
-
- internal string itsName;
- internal string itsSourceFile;
- internal bool itsNeedsActivation;
- internal int itsFunctionType;
-
- internal string [] itsStringTable;
- internal double [] itsDoubleTable;
- internal InterpreterData [] itsNestedFunctions;
- internal object [] itsRegExpLiterals;
-
- internal sbyte [] itsICode;
-
- internal int [] itsExceptionTable;
-
- internal int itsMaxVars;
- internal int itsMaxLocals;
- internal int itsMaxStack;
- internal int itsMaxFrameArray;
-
- // see comments in NativeFuncion for definition of argNames and argCount
- internal string [] argNames;
- internal int argCount;
-
- internal int itsMaxCalleeArgs;
-
- internal string encodedSource;
- internal int encodedSourceStart;
- internal int encodedSourceEnd;
-
- internal Context.Versions languageVersion;
-
- internal bool useDynamicScope;
-
- internal bool topLevel;
-
- internal object [] literalIds;
-
- internal UintMap longJumps;
-
- internal int firstLinePC = -1; // PC for the first LINE icode
-
- internal InterpreterData parentData;
-
- internal bool evalScriptFlag; // true if script corresponds to eval() code
-
- public bool IsFunction ()
- {
- return itsFunctionType != 0;
- }
-
- public string GetParamOrVarName (int index)
- {
- return argNames [index];
- }
-
- public DebuggableScript GetFunction (int index)
- {
- return itsNestedFunctions [index];
- }
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+using EcmaScript.NET.Debugging;
+using EcmaScript.NET.Collections;
+
+namespace EcmaScript.NET
+{
+
+ internal sealed class InterpreterData : DebuggableScript
+ {
+ public bool TopLevel
+ {
+ get
+ {
+ return topLevel;
+ }
+
+ }
+ public string FunctionName
+ {
+ get
+ {
+ return itsName;
+ }
+
+ }
+ public int ParamCount
+ {
+ get
+ {
+ return argCount;
+ }
+
+ }
+ public int ParamAndVarCount
+ {
+ get
+ {
+ return argNames.Length;
+ }
+
+ }
+ public string SourceName
+ {
+ get
+ {
+ return itsSourceFile;
+ }
+
+ }
+ public bool GeneratedScript
+ {
+ get
+ {
+ return ScriptRuntime.isGeneratedScript (itsSourceFile);
+ }
+
+ }
+ public int [] LineNumbers
+ {
+ get
+ {
+ return Interpreter.getLineNumbers (this);
+ }
+
+ }
+ public int FunctionCount
+ {
+ get
+ {
+ return (itsNestedFunctions == null) ? 0 : itsNestedFunctions.Length;
+ }
+
+ }
+ public DebuggableScript Parent
+ {
+ get
+ {
+ return parentData;
+ }
+
+ }
+
+ internal const int INITIAL_MAX_ICODE_LENGTH = 1024;
+ internal const int INITIAL_STRINGTABLE_SIZE = 64;
+ internal const int INITIAL_NUMBERTABLE_SIZE = 64;
+
+ internal InterpreterData (Context.Versions languageVersion, string sourceFile, string encodedSource)
+ {
+ this.languageVersion = languageVersion;
+ this.itsSourceFile = sourceFile;
+ this.encodedSource = encodedSource;
+
+ Init ();
+ }
+
+ internal InterpreterData (InterpreterData parent)
+ {
+ this.parentData = parent;
+ this.languageVersion = parent.languageVersion;
+ this.itsSourceFile = parent.itsSourceFile;
+ this.encodedSource = parent.encodedSource;
+
+ Init ();
+ }
+
+ private void Init ()
+ {
+ itsICode = new sbyte [INITIAL_MAX_ICODE_LENGTH];
+ itsStringTable = new string [INITIAL_STRINGTABLE_SIZE];
+ }
+
+ internal string itsName;
+ internal string itsSourceFile;
+ internal bool itsNeedsActivation;
+ internal int itsFunctionType;
+
+ internal string [] itsStringTable;
+ internal double [] itsDoubleTable;
+ internal InterpreterData [] itsNestedFunctions;
+ internal object [] itsRegExpLiterals;
+
+ internal sbyte [] itsICode;
+
+ internal int [] itsExceptionTable;
+
+ internal int itsMaxVars;
+ internal int itsMaxLocals;
+ internal int itsMaxStack;
+ internal int itsMaxFrameArray;
+
+ // see comments in NativeFuncion for definition of argNames and argCount
+ internal string [] argNames;
+ internal int argCount;
+
+ internal int itsMaxCalleeArgs;
+
+ internal string encodedSource;
+ internal int encodedSourceStart;
+ internal int encodedSourceEnd;
+
+ internal Context.Versions languageVersion;
+
+ internal bool useDynamicScope;
+
+ internal bool topLevel;
+
+ internal object [] literalIds;
+
+ internal UintMap longJumps;
+
+ internal int firstLinePC = -1; // PC for the first LINE icode
+
+ internal InterpreterData parentData;
+
+ internal bool evalScriptFlag; // true if script corresponds to eval() code
+
+ public bool IsFunction ()
+ {
+ return itsFunctionType != 0;
+ }
+
+ public string GetParamOrVarName (int index)
+ {
+ return argNames [index];
+ }
+
+ public DebuggableScript GetFunction (int index)
+ {
+ return itsNestedFunctions [index];
+ }
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/Node.cs b/src/EcmaScript.NET/Node.cs
similarity index 96%
rename from Code/EcmaScript.NET/Node.cs
rename to src/EcmaScript.NET/Node.cs
index 2dd2a3e..d803cae 100644
--- a/Code/EcmaScript.NET/Node.cs
+++ b/src/EcmaScript.NET/Node.cs
@@ -1,919 +1,919 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-using EcmaScript.NET.Collections;
-
-namespace EcmaScript.NET
-{
-
- /// This class implements the root of the intermediate representation.
- ///
- ///
- public class Node
- {
-
- internal class GetterPropertyLiteral
- {
- internal object Property;
-
- public GetterPropertyLiteral (object property)
- {
- Property = property;
- }
- }
-
- internal class SetterPropertyLiteral
- {
- internal object Property;
-
- public SetterPropertyLiteral (object property)
- {
- Property = property;
- }
- }
-
- public Node FirstChild
- {
- get
- {
- return first;
- }
-
- }
- public Node LastChild
- {
- get
- {
- return last;
- }
-
- }
- public Node Next
- {
- get
- {
- return next;
- }
-
- }
- public Node LastSibling
- {
- get
- {
- Node n = this;
- while (n.next != null) {
- n = n.next;
- }
- return n;
- }
-
- }
- public int Lineno
- {
- get
- {
- return lineno;
- }
-
- }
- /// Can only be called when getType() == Token.NUMBER
- public double Double
- {
- get
- {
- return ((NumberNode)this).number;
- }
-
- set
- {
- ((NumberNode)this).number = value;
- }
-
- }
- /// Can only be called when node has String context.
- public string String
- {
- get
- {
- return ((StringNode)this).str;
- }
-
- set
- {
- if (value == null)
- Context.CodeBug ();
- ((StringNode)this).str = value;
- }
-
- }
-
- public const int FUNCTION_PROP = 1;
- public const int LOCAL_PROP = 2;
- public const int LOCAL_BLOCK_PROP = 3;
- public const int REGEXP_PROP = 4;
- public const int CASEARRAY_PROP = 5;
- public const int TARGETBLOCK_PROP = 6;
- public const int VARIABLE_PROP = 7;
- public const int ISNUMBER_PROP = 8;
- public const int DIRECTCALL_PROP = 9;
- public const int SPECIALCALL_PROP = 10;
- public const int SKIP_INDEXES_PROP = 11;
- public const int OBJECT_IDS_PROP = 12;
- public const int INCRDECR_PROP = 13;
- public const int CATCH_SCOPE_PROP = 14;
- public const int LABEL_ID_PROP = 15;
- public const int MEMBER_TYPE_PROP = 16;
- public const int NAME_PROP = 17;
- public const int LAST_PROP = NAME_PROP;
-
- // values of ISNUMBER_PROP to specify
- // which of the children are Number Types
- public const int BOTH = 0;
- public const int LEFT = 1;
- public const int RIGHT = 2;
-
- public const int NON_SPECIALCALL = 0;
- public const int SPECIALCALL_EVAL = 1;
- public const int SPECIALCALL_WITH = 2;
-
- public const int DECR_FLAG = 0x1;
- public const int POST_FLAG = 0x2;
-
- public const int PROPERTY_FLAG = 0x1;
- public const int ATTRIBUTE_FLAG = 0x2;
- public const int DESCENDANTS_FLAG = 0x4; // x..y or x..@i
-
-
- private class NumberNode : Node
- {
- internal NumberNode (double number)
- : base (Token.NUMBER)
- {
- this.number = number;
- }
-
- internal double number;
- }
-
- private class StringNode : Node
- {
- internal StringNode (int Type, string str)
- : base (Type)
- {
- this.str = str;
- }
-
- internal string str;
- }
-
- public class Jump : Node
- {
- public Jump JumpStatement
- {
- get
- {
- if (!(Type == Token.BREAK || Type == Token.CONTINUE))
- Context.CodeBug ();
- return jumpNode;
- }
-
- set
- {
- if (!(Type == Token.BREAK || Type == Token.CONTINUE))
- Context.CodeBug ();
- if (value == null)
- Context.CodeBug ();
- if (this.jumpNode != null)
- Context.CodeBug (); //only once
- this.jumpNode = value;
- }
-
- }
- public Node Default
- {
- get
- {
- if (!(Type == Token.SWITCH))
- Context.CodeBug ();
- return target2;
- }
-
- set
- {
- if (!(Type == Token.SWITCH))
- Context.CodeBug ();
- if (value.Type != Token.TARGET)
- Context.CodeBug ();
- if (target2 != null)
- Context.CodeBug (); //only once
- target2 = value;
- }
-
- }
- public Node Finally
- {
- get
- {
- if (!(Type == Token.TRY))
- Context.CodeBug ();
- return target2;
- }
-
- set
- {
- if (!(Type == Token.TRY))
- Context.CodeBug ();
- if (value.Type != Token.TARGET)
- Context.CodeBug ();
- if (target2 != null)
- Context.CodeBug (); //only once
- target2 = value;
- }
-
- }
- public Jump Loop
- {
- get
- {
- if (!(Type == Token.LABEL))
- Context.CodeBug ();
- return jumpNode;
- }
-
- set
- {
- if (!(Type == Token.LABEL))
- Context.CodeBug ();
- if (value == null)
- Context.CodeBug ();
- if (jumpNode != null)
- Context.CodeBug (); //only once
- jumpNode = value;
- }
-
- }
- public Node Continue
- {
- get
- {
- if (Type != Token.LOOP)
- Context.CodeBug ();
- return target2;
- }
-
- set
- {
- if (Type != Token.LOOP)
- Context.CodeBug ();
- if (value.Type != Token.TARGET)
- Context.CodeBug ();
- if (target2 != null)
- Context.CodeBug (); //only once
- target2 = value;
- }
-
- }
- public Jump (int Type)
- : base (Type)
- {
- }
-
- internal Jump (int Type, int lineno)
- : base (Type, lineno)
- {
- }
-
- internal Jump (int Type, Node child)
- : base (Type, child)
- {
- }
-
- internal Jump (int Type, Node child, int lineno)
- : base (Type, child, lineno)
- {
- }
-
- public Node target;
- private Node target2;
- private Jump jumpNode;
- }
-
- private class PropListItem
- {
- internal PropListItem next;
- internal int Type;
- internal int intValue;
- internal object objectValue;
- }
-
-
- public Node (int nodeType)
- {
- Type = nodeType;
- }
-
- public Node (int nodeType, Node child)
- {
- Type = nodeType;
- first = last = child;
- child.next = null;
- }
-
- public Node (int nodeType, Node left, Node right)
- {
- Type = nodeType;
- first = left;
- last = right;
- left.next = right;
- right.next = null;
- }
-
- public Node (int nodeType, Node left, Node mid, Node right)
- {
- Type = nodeType;
- first = left;
- last = right;
- left.next = mid;
- mid.next = right;
- right.next = null;
- }
-
- public Node (int nodeType, int line)
- {
- Type = nodeType;
- lineno = line;
- }
-
- public Node (int nodeType, Node child, int line)
- : this (nodeType, child)
- {
- lineno = line;
- }
-
- public Node (int nodeType, Node left, Node right, int line)
- : this (nodeType, left, right)
- {
- lineno = line;
- }
-
- public Node (int nodeType, Node left, Node mid, Node right, int line)
- : this (nodeType, left, mid, right)
- {
- lineno = line;
- }
-
- public static Node newNumber (double number)
- {
- return new NumberNode (number);
- }
-
- public static Node newString (string str)
- {
- return new StringNode (Token.STRING, str);
- }
-
- public static Node newString (int Type, string str)
- {
- return new StringNode (Type, str);
- }
-
- public bool hasChildren ()
- {
- return first != null;
- }
-
- public Node getChildBefore (Node child)
- {
- if (child == first)
- return null;
- Node n = first;
- while (n.next != child) {
- n = n.next;
- if (n == null)
- throw new ApplicationException ("node is not a child");
- }
- return n;
- }
-
- public void addChildToFront (Node child)
- {
- child.next = first;
- first = child;
- if (last == null) {
- last = child;
- }
- }
-
- public void addChildToBack (Node child)
- {
- child.next = null;
- if (last == null) {
- first = last = child;
- return;
- }
- last.next = child;
- last = child;
- }
-
- public void addChildrenToFront (Node children)
- {
- Node lastSib = children.LastSibling;
- lastSib.next = first;
- first = children;
- if (last == null) {
- last = lastSib;
- }
- }
-
- public void addChildrenToBack (Node children)
- {
- if (last != null) {
- last.next = children;
- }
- last = children.LastSibling;
- if (first == null) {
- first = children;
- }
- }
-
- /// Add 'child' before 'node'.
- public void addChildBefore (Node newChild, Node node)
- {
- if (newChild.next != null)
- throw new ApplicationException ("newChild had siblings in addChildBefore");
- if (first == node) {
- newChild.next = first;
- first = newChild;
- return;
- }
- Node prev = getChildBefore (node);
- addChildAfter (newChild, prev);
- }
-
- /// Add 'child' after 'node'.
- public void addChildAfter (Node newChild, Node node)
- {
- if (newChild.next != null)
- throw new ApplicationException ("newChild had siblings in addChildAfter");
- newChild.next = node.next;
- node.next = newChild;
- if (last == node)
- last = newChild;
- }
-
- public void removeChild (Node child)
- {
- Node prev = getChildBefore (child);
- if (prev == null)
- first = first.next;
- else
- prev.next = child.next;
- if (child == last)
- last = prev;
- child.next = null;
- }
-
- public void replaceChild (Node child, Node newChild)
- {
- newChild.next = child.next;
- if (child == first) {
- first = newChild;
- }
- else {
- Node prev = getChildBefore (child);
- prev.next = newChild;
- }
- if (child == last)
- last = newChild;
- child.next = null;
- }
-
- public void replaceChildAfter (Node prevChild, Node newChild)
- {
- Node child = prevChild.next;
- newChild.next = child.next;
- prevChild.next = newChild;
- if (child == last)
- last = newChild;
- child.next = null;
- }
-
- private static string propToString (int propType)
- {
- if (Token.printTrees) {
- // If Context.printTrees is false, the compiler
- // can remove all these strings.
- switch (propType) {
-
- case FUNCTION_PROP:
- return "function";
-
- case LOCAL_PROP:
- return "local";
-
- case LOCAL_BLOCK_PROP:
- return "local_block";
-
- case REGEXP_PROP:
- return "regexp";
-
- case CASEARRAY_PROP:
- return "casearray";
-
-
- case TARGETBLOCK_PROP:
- return "targetblock";
-
- case VARIABLE_PROP:
- return "variable";
-
- case ISNUMBER_PROP:
- return "isnumber";
-
- case DIRECTCALL_PROP:
- return "directcall";
-
-
- case SPECIALCALL_PROP:
- return "specialcall";
-
- case SKIP_INDEXES_PROP:
- return "skip_indexes";
-
- case OBJECT_IDS_PROP:
- return "object_ids_prop";
-
- case INCRDECR_PROP:
- return "incrdecr_prop";
-
- case CATCH_SCOPE_PROP:
- return "catch_scope_prop";
-
- case LABEL_ID_PROP:
- return "label_id_prop";
-
- case MEMBER_TYPE_PROP:
- return "member_Type_prop";
-
- case NAME_PROP:
- return "name_prop";
-
-
- default:
- Context.CodeBug ();
- break;
-
- }
- }
- return null;
- }
-
- private PropListItem lookupProperty (int propType)
- {
- PropListItem x = propListHead;
- while (x != null && propType != x.Type) {
- x = x.next;
- }
- return x;
- }
-
- private PropListItem ensureProperty (int propType)
- {
- PropListItem item = lookupProperty (propType);
- if (item == null) {
- item = new PropListItem ();
- item.Type = propType;
- item.next = propListHead;
- propListHead = item;
- }
- return item;
- }
-
- public void removeProp (int propType)
- {
- PropListItem x = propListHead;
- if (x != null) {
- PropListItem prev = null;
- while (x.Type != propType) {
- prev = x;
- x = x.next;
- if (x == null) {
- return;
- }
- }
- if (prev == null) {
- propListHead = x.next;
- }
- else {
- prev.next = x.next;
- }
- }
- }
-
- public object getProp (int propType)
- {
- PropListItem item = lookupProperty (propType);
- if (item == null) {
- return null;
- }
- return item.objectValue;
- }
-
- public int getIntProp (int propType, int defaultValue)
- {
- PropListItem item = lookupProperty (propType);
- if (item == null) {
- return defaultValue;
- }
- return item.intValue;
- }
-
- public int getExistingIntProp (int propType)
- {
- PropListItem item = lookupProperty (propType);
- if (item == null) {
- Context.CodeBug ();
- }
- return item.intValue;
- }
-
- public void putProp (int propType, object prop)
- {
- if (prop == null) {
- removeProp (propType);
- }
- else {
- PropListItem item = ensureProperty (propType);
- item.objectValue = prop;
- }
- }
-
- public void putIntProp (int propType, int prop)
- {
- PropListItem item = ensureProperty (propType);
- item.intValue = prop;
- }
-
- public static Node newTarget ()
- {
- return new Node (Token.TARGET);
- }
-
- public int labelId ()
- {
- if (Type != Token.TARGET)
- Context.CodeBug ();
- return getIntProp (LABEL_ID_PROP, -1);
- }
-
- public void labelId (int labelId)
- {
- if (Type != Token.TARGET)
- Context.CodeBug ();
- putIntProp (LABEL_ID_PROP, labelId);
- }
-
- public override string ToString ()
- {
- if (Token.printTrees) {
- System.Text.StringBuilder sb = new System.Text.StringBuilder ();
- toString (new ObjToIntMap (), sb);
- return sb.ToString ();
- }
- return Convert.ToString (Type);
- }
-
- private void toString (ObjToIntMap printIds, System.Text.StringBuilder sb)
- {
- if (Token.printTrees) {
- sb.Append (Token.name (this.Type));
- if (this is StringNode) {
- sb.Append (' ');
- sb.Append (String);
- }
- else if (this is ScriptOrFnNode) {
- ScriptOrFnNode sof = (ScriptOrFnNode)this;
- if (this is FunctionNode) {
- FunctionNode fn = (FunctionNode)this;
- sb.Append (' ');
- sb.Append (fn.FunctionName);
- }
- sb.Append (" [source name: ");
- sb.Append (sof.SourceName);
- sb.Append ("] [encoded source length: ");
- sb.Append (sof.EncodedSourceEnd - sof.EncodedSourceStart);
- sb.Append ("] [base line: ");
- sb.Append (sof.BaseLineno);
- sb.Append ("] [end line: ");
- sb.Append (sof.EndLineno);
- sb.Append (']');
- }
- else if (this is Jump) {
- Jump jump = (Jump)this;
- if (this.Type == Token.BREAK || this.Type == Token.CONTINUE) {
- sb.Append (" [label: ");
- appendPrintId (jump.JumpStatement, printIds, sb);
- sb.Append (']');
- }
- else if (this.Type == Token.TRY) {
- Node catchNode = jump.target;
- Node finallyTarget = jump.Finally;
- if (catchNode != null) {
- sb.Append (" [catch: ");
- appendPrintId (catchNode, printIds, sb);
- sb.Append (']');
- }
- if (finallyTarget != null) {
- sb.Append (" [finally: ");
- appendPrintId (finallyTarget, printIds, sb);
- sb.Append (']');
- }
- }
- else if (this.Type == Token.LABEL || this.Type == Token.LOOP || this.Type == Token.SWITCH) {
- sb.Append (" [break: ");
- appendPrintId (jump.target, printIds, sb);
- sb.Append (']');
- if (this.Type == Token.LOOP) {
- sb.Append (" [continue: ");
- appendPrintId (jump.Continue, printIds, sb);
- sb.Append (']');
- }
- }
- else {
- sb.Append (" [target: ");
- appendPrintId (jump.target, printIds, sb);
- sb.Append (']');
- }
- }
- else if (this.Type == Token.NUMBER) {
- sb.Append (' ');
- sb.Append (Double);
- }
- else if (this.Type == Token.TARGET) {
- sb.Append (' ');
- appendPrintId (this, printIds, sb);
- }
- if (lineno != -1) {
- sb.Append (' ');
- sb.Append (lineno);
- }
-
- for (PropListItem x = propListHead; x != null; x = x.next) {
- int Type = x.Type;
- sb.Append (" [");
- sb.Append (propToString (Type));
- sb.Append (": ");
- string value;
- switch (Type) {
-
- case TARGETBLOCK_PROP: // can't add this as it recurses
- value = "target block property";
- break;
-
- case LOCAL_BLOCK_PROP: // can't add this as it is dull
- value = "last local block";
- break;
-
- case ISNUMBER_PROP:
- switch (x.intValue) {
-
- case BOTH:
- value = "both";
- break;
-
- case RIGHT:
- value = "right";
- break;
-
- case LEFT:
- value = "left";
- break;
-
- default:
- throw Context.CodeBug ();
-
- }
- break;
-
- case SPECIALCALL_PROP:
- switch (x.intValue) {
-
- case SPECIALCALL_EVAL:
- value = "eval";
- break;
-
- case SPECIALCALL_WITH:
- value = "with";
- break;
-
- default:
- // NON_SPECIALCALL should not be stored
- throw Context.CodeBug ();
-
- }
- break;
-
- default:
- object obj = x.objectValue;
- if (obj != null) {
- value = obj.ToString ();
- }
- else {
- value = Convert.ToString (x.intValue);
- }
- break;
-
- }
- sb.Append (value);
- sb.Append (']');
- }
- }
- }
-
- public string toStringTree (ScriptOrFnNode treeTop)
- {
- if (Token.printTrees) {
- System.Text.StringBuilder sb = new System.Text.StringBuilder ();
- toStringTreeHelper (treeTop, this, null, 0, sb);
- return sb.ToString ();
- }
- return null;
- }
-
- private static void toStringTreeHelper (ScriptOrFnNode treeTop, Node n, ObjToIntMap printIds, int level, System.Text.StringBuilder sb)
- {
- if (Token.printTrees) {
- if (printIds == null) {
- printIds = new ObjToIntMap ();
- generatePrintIds (treeTop, printIds);
- }
- for (int i = 0; i != level; ++i) {
- sb.Append (" ");
- }
- n.toString (printIds, sb);
- sb.Append ('\n');
- for (Node cursor = n.FirstChild; cursor != null; cursor = cursor.Next) {
- if (cursor.Type == Token.FUNCTION) {
- int fnIndex = cursor.getExistingIntProp (Node.FUNCTION_PROP);
- FunctionNode fn = treeTop.getFunctionNode (fnIndex);
- toStringTreeHelper (fn, fn, null, level + 1, sb);
- }
- else {
- toStringTreeHelper (treeTop, cursor, printIds, level + 1, sb);
- }
- }
- }
- }
-
- private static void generatePrintIds (Node n, ObjToIntMap map)
- {
- if (Token.printTrees) {
- map.put (n, map.size ());
- for (Node cursor = n.FirstChild; cursor != null; cursor = cursor.Next) {
- generatePrintIds (cursor, map);
- }
- }
- }
-
- private static void appendPrintId (Node n, ObjToIntMap printIds, System.Text.StringBuilder sb)
- {
- if (Token.printTrees) {
- if (n != null) {
- int id = printIds.Get (n, -1);
- sb.Append ('#');
- if (id != -1) {
- sb.Append (id + 1);
- }
- else {
- sb.Append ("");
- }
- }
- }
- }
-
- internal int Type; // Type of the node; Token.NAME for example
- internal Node next; // next sibling
- private Node first; // first element of a linked list of children
- private Node last; // last element of a linked list of children
- private int lineno = -1; // encapsulated int data; depends on Type
-
- /// Linked list of properties. Since vast majority of nodes would have
- /// no more then 2 properties, linked list saves memory and provides
- /// fast lookup. If this does not holds, propListHead can be replaced
- /// by UintMap.
- ///
- private PropListItem propListHead;
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+using EcmaScript.NET.Collections;
+
+namespace EcmaScript.NET
+{
+
+ /// This class implements the root of the intermediate representation.
+ ///
+ ///
+ public class Node
+ {
+
+ internal class GetterPropertyLiteral
+ {
+ internal object Property;
+
+ public GetterPropertyLiteral (object property)
+ {
+ Property = property;
+ }
+ }
+
+ internal class SetterPropertyLiteral
+ {
+ internal object Property;
+
+ public SetterPropertyLiteral (object property)
+ {
+ Property = property;
+ }
+ }
+
+ public Node FirstChild
+ {
+ get
+ {
+ return first;
+ }
+
+ }
+ public Node LastChild
+ {
+ get
+ {
+ return last;
+ }
+
+ }
+ public Node Next
+ {
+ get
+ {
+ return next;
+ }
+
+ }
+ public Node LastSibling
+ {
+ get
+ {
+ Node n = this;
+ while (n.next != null) {
+ n = n.next;
+ }
+ return n;
+ }
+
+ }
+ public int Lineno
+ {
+ get
+ {
+ return lineno;
+ }
+
+ }
+ /// Can only be called when getType() == Token.NUMBER
+ public double Double
+ {
+ get
+ {
+ return ((NumberNode)this).number;
+ }
+
+ set
+ {
+ ((NumberNode)this).number = value;
+ }
+
+ }
+ /// Can only be called when node has String context.
+ public string String
+ {
+ get
+ {
+ return ((StringNode)this).str;
+ }
+
+ set
+ {
+ if (value == null)
+ Context.CodeBug ();
+ ((StringNode)this).str = value;
+ }
+
+ }
+
+ public const int FUNCTION_PROP = 1;
+ public const int LOCAL_PROP = 2;
+ public const int LOCAL_BLOCK_PROP = 3;
+ public const int REGEXP_PROP = 4;
+ public const int CASEARRAY_PROP = 5;
+ public const int TARGETBLOCK_PROP = 6;
+ public const int VARIABLE_PROP = 7;
+ public const int ISNUMBER_PROP = 8;
+ public const int DIRECTCALL_PROP = 9;
+ public const int SPECIALCALL_PROP = 10;
+ public const int SKIP_INDEXES_PROP = 11;
+ public const int OBJECT_IDS_PROP = 12;
+ public const int INCRDECR_PROP = 13;
+ public const int CATCH_SCOPE_PROP = 14;
+ public const int LABEL_ID_PROP = 15;
+ public const int MEMBER_TYPE_PROP = 16;
+ public const int NAME_PROP = 17;
+ public const int LAST_PROP = NAME_PROP;
+
+ // values of ISNUMBER_PROP to specify
+ // which of the children are Number Types
+ public const int BOTH = 0;
+ public const int LEFT = 1;
+ public const int RIGHT = 2;
+
+ public const int NON_SPECIALCALL = 0;
+ public const int SPECIALCALL_EVAL = 1;
+ public const int SPECIALCALL_WITH = 2;
+
+ public const int DECR_FLAG = 0x1;
+ public const int POST_FLAG = 0x2;
+
+ public const int PROPERTY_FLAG = 0x1;
+ public const int ATTRIBUTE_FLAG = 0x2;
+ public const int DESCENDANTS_FLAG = 0x4; // x..y or x..@i
+
+
+ private class NumberNode : Node
+ {
+ internal NumberNode (double number)
+ : base (Token.NUMBER)
+ {
+ this.number = number;
+ }
+
+ internal double number;
+ }
+
+ private class StringNode : Node
+ {
+ internal StringNode (int Type, string str)
+ : base (Type)
+ {
+ this.str = str;
+ }
+
+ internal string str;
+ }
+
+ public class Jump : Node
+ {
+ public Jump JumpStatement
+ {
+ get
+ {
+ if (!(Type == Token.BREAK || Type == Token.CONTINUE))
+ Context.CodeBug ();
+ return jumpNode;
+ }
+
+ set
+ {
+ if (!(Type == Token.BREAK || Type == Token.CONTINUE))
+ Context.CodeBug ();
+ if (value == null)
+ Context.CodeBug ();
+ if (this.jumpNode != null)
+ Context.CodeBug (); //only once
+ this.jumpNode = value;
+ }
+
+ }
+ public Node Default
+ {
+ get
+ {
+ if (!(Type == Token.SWITCH))
+ Context.CodeBug ();
+ return target2;
+ }
+
+ set
+ {
+ if (!(Type == Token.SWITCH))
+ Context.CodeBug ();
+ if (value.Type != Token.TARGET)
+ Context.CodeBug ();
+ if (target2 != null)
+ Context.CodeBug (); //only once
+ target2 = value;
+ }
+
+ }
+ public Node Finally
+ {
+ get
+ {
+ if (!(Type == Token.TRY))
+ Context.CodeBug ();
+ return target2;
+ }
+
+ set
+ {
+ if (!(Type == Token.TRY))
+ Context.CodeBug ();
+ if (value.Type != Token.TARGET)
+ Context.CodeBug ();
+ if (target2 != null)
+ Context.CodeBug (); //only once
+ target2 = value;
+ }
+
+ }
+ public Jump Loop
+ {
+ get
+ {
+ if (!(Type == Token.LABEL))
+ Context.CodeBug ();
+ return jumpNode;
+ }
+
+ set
+ {
+ if (!(Type == Token.LABEL))
+ Context.CodeBug ();
+ if (value == null)
+ Context.CodeBug ();
+ if (jumpNode != null)
+ Context.CodeBug (); //only once
+ jumpNode = value;
+ }
+
+ }
+ public Node Continue
+ {
+ get
+ {
+ if (Type != Token.LOOP)
+ Context.CodeBug ();
+ return target2;
+ }
+
+ set
+ {
+ if (Type != Token.LOOP)
+ Context.CodeBug ();
+ if (value.Type != Token.TARGET)
+ Context.CodeBug ();
+ if (target2 != null)
+ Context.CodeBug (); //only once
+ target2 = value;
+ }
+
+ }
+ public Jump (int Type)
+ : base (Type)
+ {
+ }
+
+ internal Jump (int Type, int lineno)
+ : base (Type, lineno)
+ {
+ }
+
+ internal Jump (int Type, Node child)
+ : base (Type, child)
+ {
+ }
+
+ internal Jump (int Type, Node child, int lineno)
+ : base (Type, child, lineno)
+ {
+ }
+
+ public Node target;
+ private Node target2;
+ private Jump jumpNode;
+ }
+
+ private class PropListItem
+ {
+ internal PropListItem next;
+ internal int Type;
+ internal int intValue;
+ internal object objectValue;
+ }
+
+
+ public Node (int nodeType)
+ {
+ Type = nodeType;
+ }
+
+ public Node (int nodeType, Node child)
+ {
+ Type = nodeType;
+ first = last = child;
+ child.next = null;
+ }
+
+ public Node (int nodeType, Node left, Node right)
+ {
+ Type = nodeType;
+ first = left;
+ last = right;
+ left.next = right;
+ right.next = null;
+ }
+
+ public Node (int nodeType, Node left, Node mid, Node right)
+ {
+ Type = nodeType;
+ first = left;
+ last = right;
+ left.next = mid;
+ mid.next = right;
+ right.next = null;
+ }
+
+ public Node (int nodeType, int line)
+ {
+ Type = nodeType;
+ lineno = line;
+ }
+
+ public Node (int nodeType, Node child, int line)
+ : this (nodeType, child)
+ {
+ lineno = line;
+ }
+
+ public Node (int nodeType, Node left, Node right, int line)
+ : this (nodeType, left, right)
+ {
+ lineno = line;
+ }
+
+ public Node (int nodeType, Node left, Node mid, Node right, int line)
+ : this (nodeType, left, mid, right)
+ {
+ lineno = line;
+ }
+
+ public static Node newNumber (double number)
+ {
+ return new NumberNode (number);
+ }
+
+ public static Node newString (string str)
+ {
+ return new StringNode (Token.STRING, str);
+ }
+
+ public static Node newString (int Type, string str)
+ {
+ return new StringNode (Type, str);
+ }
+
+ public bool hasChildren ()
+ {
+ return first != null;
+ }
+
+ public Node getChildBefore (Node child)
+ {
+ if (child == first)
+ return null;
+ Node n = first;
+ while (n.next != child) {
+ n = n.next;
+ if (n == null)
+ throw new Exception ("node is not a child");
+ }
+ return n;
+ }
+
+ public void addChildToFront (Node child)
+ {
+ child.next = first;
+ first = child;
+ if (last == null) {
+ last = child;
+ }
+ }
+
+ public void addChildToBack (Node child)
+ {
+ child.next = null;
+ if (last == null) {
+ first = last = child;
+ return;
+ }
+ last.next = child;
+ last = child;
+ }
+
+ public void addChildrenToFront (Node children)
+ {
+ Node lastSib = children.LastSibling;
+ lastSib.next = first;
+ first = children;
+ if (last == null) {
+ last = lastSib;
+ }
+ }
+
+ public void addChildrenToBack (Node children)
+ {
+ if (last != null) {
+ last.next = children;
+ }
+ last = children.LastSibling;
+ if (first == null) {
+ first = children;
+ }
+ }
+
+ /// Add 'child' before 'node'.
+ public void addChildBefore (Node newChild, Node node)
+ {
+ if (newChild.next != null)
+ throw new Exception ("newChild had siblings in addChildBefore");
+ if (first == node) {
+ newChild.next = first;
+ first = newChild;
+ return;
+ }
+ Node prev = getChildBefore (node);
+ addChildAfter (newChild, prev);
+ }
+
+ /// Add 'child' after 'node'.
+ public void addChildAfter (Node newChild, Node node)
+ {
+ if (newChild.next != null)
+ throw new Exception ("newChild had siblings in addChildAfter");
+ newChild.next = node.next;
+ node.next = newChild;
+ if (last == node)
+ last = newChild;
+ }
+
+ public void removeChild (Node child)
+ {
+ Node prev = getChildBefore (child);
+ if (prev == null)
+ first = first.next;
+ else
+ prev.next = child.next;
+ if (child == last)
+ last = prev;
+ child.next = null;
+ }
+
+ public void replaceChild (Node child, Node newChild)
+ {
+ newChild.next = child.next;
+ if (child == first) {
+ first = newChild;
+ }
+ else {
+ Node prev = getChildBefore (child);
+ prev.next = newChild;
+ }
+ if (child == last)
+ last = newChild;
+ child.next = null;
+ }
+
+ public void replaceChildAfter (Node prevChild, Node newChild)
+ {
+ Node child = prevChild.next;
+ newChild.next = child.next;
+ prevChild.next = newChild;
+ if (child == last)
+ last = newChild;
+ child.next = null;
+ }
+
+ private static string propToString (int propType)
+ {
+ if (Token.printTrees) {
+ // If Context.printTrees is false, the compiler
+ // can remove all these strings.
+ switch (propType) {
+
+ case FUNCTION_PROP:
+ return "function";
+
+ case LOCAL_PROP:
+ return "local";
+
+ case LOCAL_BLOCK_PROP:
+ return "local_block";
+
+ case REGEXP_PROP:
+ return "regexp";
+
+ case CASEARRAY_PROP:
+ return "casearray";
+
+
+ case TARGETBLOCK_PROP:
+ return "targetblock";
+
+ case VARIABLE_PROP:
+ return "variable";
+
+ case ISNUMBER_PROP:
+ return "isnumber";
+
+ case DIRECTCALL_PROP:
+ return "directcall";
+
+
+ case SPECIALCALL_PROP:
+ return "specialcall";
+
+ case SKIP_INDEXES_PROP:
+ return "skip_indexes";
+
+ case OBJECT_IDS_PROP:
+ return "object_ids_prop";
+
+ case INCRDECR_PROP:
+ return "incrdecr_prop";
+
+ case CATCH_SCOPE_PROP:
+ return "catch_scope_prop";
+
+ case LABEL_ID_PROP:
+ return "label_id_prop";
+
+ case MEMBER_TYPE_PROP:
+ return "member_Type_prop";
+
+ case NAME_PROP:
+ return "name_prop";
+
+
+ default:
+ Context.CodeBug ();
+ break;
+
+ }
+ }
+ return null;
+ }
+
+ private PropListItem lookupProperty (int propType)
+ {
+ PropListItem x = propListHead;
+ while (x != null && propType != x.Type) {
+ x = x.next;
+ }
+ return x;
+ }
+
+ private PropListItem ensureProperty (int propType)
+ {
+ PropListItem item = lookupProperty (propType);
+ if (item == null) {
+ item = new PropListItem ();
+ item.Type = propType;
+ item.next = propListHead;
+ propListHead = item;
+ }
+ return item;
+ }
+
+ public void removeProp (int propType)
+ {
+ PropListItem x = propListHead;
+ if (x != null) {
+ PropListItem prev = null;
+ while (x.Type != propType) {
+ prev = x;
+ x = x.next;
+ if (x == null) {
+ return;
+ }
+ }
+ if (prev == null) {
+ propListHead = x.next;
+ }
+ else {
+ prev.next = x.next;
+ }
+ }
+ }
+
+ public object getProp (int propType)
+ {
+ PropListItem item = lookupProperty (propType);
+ if (item == null) {
+ return null;
+ }
+ return item.objectValue;
+ }
+
+ public int getIntProp (int propType, int defaultValue)
+ {
+ PropListItem item = lookupProperty (propType);
+ if (item == null) {
+ return defaultValue;
+ }
+ return item.intValue;
+ }
+
+ public int getExistingIntProp (int propType)
+ {
+ PropListItem item = lookupProperty (propType);
+ if (item == null) {
+ Context.CodeBug ();
+ }
+ return item.intValue;
+ }
+
+ public void putProp (int propType, object prop)
+ {
+ if (prop == null) {
+ removeProp (propType);
+ }
+ else {
+ PropListItem item = ensureProperty (propType);
+ item.objectValue = prop;
+ }
+ }
+
+ public void putIntProp (int propType, int prop)
+ {
+ PropListItem item = ensureProperty (propType);
+ item.intValue = prop;
+ }
+
+ public static Node newTarget ()
+ {
+ return new Node (Token.TARGET);
+ }
+
+ public int labelId ()
+ {
+ if (Type != Token.TARGET)
+ Context.CodeBug ();
+ return getIntProp (LABEL_ID_PROP, -1);
+ }
+
+ public void labelId (int labelId)
+ {
+ if (Type != Token.TARGET)
+ Context.CodeBug ();
+ putIntProp (LABEL_ID_PROP, labelId);
+ }
+
+ public override string ToString ()
+ {
+ if (Token.printTrees) {
+ System.Text.StringBuilder sb = new System.Text.StringBuilder ();
+ toString (new ObjToIntMap (), sb);
+ return sb.ToString ();
+ }
+ return Convert.ToString (Type);
+ }
+
+ private void toString (ObjToIntMap printIds, System.Text.StringBuilder sb)
+ {
+ if (Token.printTrees) {
+ sb.Append (Token.name (this.Type));
+ if (this is StringNode) {
+ sb.Append (' ');
+ sb.Append (String);
+ }
+ else if (this is ScriptOrFnNode) {
+ ScriptOrFnNode sof = (ScriptOrFnNode)this;
+ if (this is FunctionNode) {
+ FunctionNode fn = (FunctionNode)this;
+ sb.Append (' ');
+ sb.Append (fn.FunctionName);
+ }
+ sb.Append (" [source name: ");
+ sb.Append (sof.SourceName);
+ sb.Append ("] [encoded source length: ");
+ sb.Append (sof.EncodedSourceEnd - sof.EncodedSourceStart);
+ sb.Append ("] [base line: ");
+ sb.Append (sof.BaseLineno);
+ sb.Append ("] [end line: ");
+ sb.Append (sof.EndLineno);
+ sb.Append (']');
+ }
+ else if (this is Jump) {
+ Jump jump = (Jump)this;
+ if (this.Type == Token.BREAK || this.Type == Token.CONTINUE) {
+ sb.Append (" [label: ");
+ appendPrintId (jump.JumpStatement, printIds, sb);
+ sb.Append (']');
+ }
+ else if (this.Type == Token.TRY) {
+ Node catchNode = jump.target;
+ Node finallyTarget = jump.Finally;
+ if (catchNode != null) {
+ sb.Append (" [catch: ");
+ appendPrintId (catchNode, printIds, sb);
+ sb.Append (']');
+ }
+ if (finallyTarget != null) {
+ sb.Append (" [finally: ");
+ appendPrintId (finallyTarget, printIds, sb);
+ sb.Append (']');
+ }
+ }
+ else if (this.Type == Token.LABEL || this.Type == Token.LOOP || this.Type == Token.SWITCH) {
+ sb.Append (" [break: ");
+ appendPrintId (jump.target, printIds, sb);
+ sb.Append (']');
+ if (this.Type == Token.LOOP) {
+ sb.Append (" [continue: ");
+ appendPrintId (jump.Continue, printIds, sb);
+ sb.Append (']');
+ }
+ }
+ else {
+ sb.Append (" [target: ");
+ appendPrintId (jump.target, printIds, sb);
+ sb.Append (']');
+ }
+ }
+ else if (this.Type == Token.NUMBER) {
+ sb.Append (' ');
+ sb.Append (Double);
+ }
+ else if (this.Type == Token.TARGET) {
+ sb.Append (' ');
+ appendPrintId (this, printIds, sb);
+ }
+ if (lineno != -1) {
+ sb.Append (' ');
+ sb.Append (lineno);
+ }
+
+ for (PropListItem x = propListHead; x != null; x = x.next) {
+ int Type = x.Type;
+ sb.Append (" [");
+ sb.Append (propToString (Type));
+ sb.Append (": ");
+ string value;
+ switch (Type) {
+
+ case TARGETBLOCK_PROP: // can't add this as it recurses
+ value = "target block property";
+ break;
+
+ case LOCAL_BLOCK_PROP: // can't add this as it is dull
+ value = "last local block";
+ break;
+
+ case ISNUMBER_PROP:
+ switch (x.intValue) {
+
+ case BOTH:
+ value = "both";
+ break;
+
+ case RIGHT:
+ value = "right";
+ break;
+
+ case LEFT:
+ value = "left";
+ break;
+
+ default:
+ throw Context.CodeBug ();
+
+ }
+ break;
+
+ case SPECIALCALL_PROP:
+ switch (x.intValue) {
+
+ case SPECIALCALL_EVAL:
+ value = "eval";
+ break;
+
+ case SPECIALCALL_WITH:
+ value = "with";
+ break;
+
+ default:
+ // NON_SPECIALCALL should not be stored
+ throw Context.CodeBug ();
+
+ }
+ break;
+
+ default:
+ object obj = x.objectValue;
+ if (obj != null) {
+ value = obj.ToString ();
+ }
+ else {
+ value = Convert.ToString (x.intValue);
+ }
+ break;
+
+ }
+ sb.Append (value);
+ sb.Append (']');
+ }
+ }
+ }
+
+ public string toStringTree (ScriptOrFnNode treeTop)
+ {
+ if (Token.printTrees) {
+ System.Text.StringBuilder sb = new System.Text.StringBuilder ();
+ toStringTreeHelper (treeTop, this, null, 0, sb);
+ return sb.ToString ();
+ }
+ return null;
+ }
+
+ private static void toStringTreeHelper (ScriptOrFnNode treeTop, Node n, ObjToIntMap printIds, int level, System.Text.StringBuilder sb)
+ {
+ if (Token.printTrees) {
+ if (printIds == null) {
+ printIds = new ObjToIntMap ();
+ generatePrintIds (treeTop, printIds);
+ }
+ for (int i = 0; i != level; ++i) {
+ sb.Append (" ");
+ }
+ n.toString (printIds, sb);
+ sb.Append ('\n');
+ for (Node cursor = n.FirstChild; cursor != null; cursor = cursor.Next) {
+ if (cursor.Type == Token.FUNCTION) {
+ int fnIndex = cursor.getExistingIntProp (Node.FUNCTION_PROP);
+ FunctionNode fn = treeTop.getFunctionNode (fnIndex);
+ toStringTreeHelper (fn, fn, null, level + 1, sb);
+ }
+ else {
+ toStringTreeHelper (treeTop, cursor, printIds, level + 1, sb);
+ }
+ }
+ }
+ }
+
+ private static void generatePrintIds (Node n, ObjToIntMap map)
+ {
+ if (Token.printTrees) {
+ map.put (n, map.size ());
+ for (Node cursor = n.FirstChild; cursor != null; cursor = cursor.Next) {
+ generatePrintIds (cursor, map);
+ }
+ }
+ }
+
+ private static void appendPrintId (Node n, ObjToIntMap printIds, System.Text.StringBuilder sb)
+ {
+ if (Token.printTrees) {
+ if (n != null) {
+ int id = printIds.Get (n, -1);
+ sb.Append ('#');
+ if (id != -1) {
+ sb.Append (id + 1);
+ }
+ else {
+ sb.Append ("");
+ }
+ }
+ }
+ }
+
+ internal int Type; // Type of the node; Token.NAME for example
+ internal Node next; // next sibling
+ private Node first; // first element of a linked list of children
+ private Node last; // last element of a linked list of children
+ private int lineno = -1; // encapsulated int data; depends on Type
+
+ /// Linked list of properties. Since vast majority of nodes would have
+ /// no more then 2 properties, linked list saves memory and provides
+ /// fast lookup. If this does not holds, propListHead can be replaced
+ /// by UintMap.
+ ///
+ private PropListItem propListHead;
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/NodeFactory.cs b/src/EcmaScript.NET/NodeFactory.cs
similarity index 97%
rename from Code/EcmaScript.NET/NodeFactory.cs
rename to src/EcmaScript.NET/NodeFactory.cs
index e0efb67..0221f88 100644
--- a/Code/EcmaScript.NET/NodeFactory.cs
+++ b/src/EcmaScript.NET/NodeFactory.cs
@@ -1,1429 +1,1429 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-using EcmaScript.NET.Collections;
-
-namespace EcmaScript.NET
-{
-
- /// This class allows the creation of nodes, and follows the Factory pattern.
- ///
- ///
- sealed class NodeFactory
- {
- internal NodeFactory (Parser parser)
- {
- this.parser = parser;
- }
-
- internal ScriptOrFnNode CreateScript ()
- {
- return new ScriptOrFnNode (Token.SCRIPT);
- }
-
- /// Script (for associating file/url names with toplevel scripts.)
- internal void initScript (ScriptOrFnNode scriptNode, Node body)
- {
- Node children = body.FirstChild;
- if (children != null) {
- scriptNode.addChildrenToBack (children);
- }
- }
-
- /// Leaf
- internal Node CreateLeaf (int nodeType)
- {
- return new Node (nodeType);
- }
-
- internal Node CreateLeaf (int nodeType, int nodeOp)
- {
- return new Node (nodeType, nodeOp);
- }
-
- /// Statement leaf nodes.
-
- internal Node CreateSwitch (Node expr, int lineno)
- {
- //
- // The switch will be rewritten from:
- //
- // switch (expr) {
- // case test1: statements1;
- // ...
- // default: statementsDefault;
- // ...
- // case testN: statementsN;
- // }
- //
- // to:
- //
- // {
- // switch (expr) {
- // case test1: goto label1;
- // ...
- // case testN: goto labelN;
- // }
- // goto labelDefault;
- // label1:
- // statements1;
- // ...
- // labelDefault:
- // statementsDefault;
- // ...
- // labelN:
- // statementsN;
- // breakLabel:
- // }
- //
- // where inside switch each "break;" without label will be replaced
- // by "goto breakLabel".
- //
- // If the original switch does not have the default label, then
- // the transformed code would contain after the switch instead of
- // goto labelDefault;
- // the following goto:
- // goto breakLabel;
- //
-
- Node.Jump switchNode = new Node.Jump (Token.SWITCH, expr, lineno);
- Node block = new Node (Token.BLOCK, switchNode);
- return block;
- }
-
- /// If caseExpression argument is null it indicate default label.
- internal void addSwitchCase (Node switchBlock, Node caseExpression, Node statements)
- {
- if (switchBlock.Type != Token.BLOCK)
- throw Context.CodeBug ();
- Node.Jump switchNode = (Node.Jump)switchBlock.FirstChild;
- if (switchNode.Type != Token.SWITCH)
- throw Context.CodeBug ();
-
- Node gotoTarget = Node.newTarget ();
- if (caseExpression != null) {
- Node.Jump caseNode = new Node.Jump (Token.CASE, caseExpression);
- caseNode.target = gotoTarget;
- switchNode.addChildToBack (caseNode);
- }
- else {
- switchNode.Default = gotoTarget;
- }
- switchBlock.addChildToBack (gotoTarget);
- switchBlock.addChildToBack (statements);
- }
-
- internal void closeSwitch (Node switchBlock)
- {
- if (switchBlock.Type != Token.BLOCK)
- throw Context.CodeBug ();
- Node.Jump switchNode = (Node.Jump)switchBlock.FirstChild;
- if (switchNode.Type != Token.SWITCH)
- throw Context.CodeBug ();
-
- Node switchBreakTarget = Node.newTarget ();
- // switchNode.target is only used by NodeTransformer
- // to detect switch end
- switchNode.target = switchBreakTarget;
-
- Node defaultTarget = switchNode.Default;
- if (defaultTarget == null) {
- defaultTarget = switchBreakTarget;
- }
-
- switchBlock.addChildAfter (makeJump (Token.GOTO, defaultTarget), switchNode);
- switchBlock.addChildToBack (switchBreakTarget);
- }
-
- internal Node CreateVariables (int lineno)
- {
- return new Node (Token.VAR, lineno);
- }
-
- internal Node CreateExprStatement (Node expr, int lineno)
- {
- int type;
- if (parser.insideFunction ()) {
- type = Token.EXPR_VOID;
- }
- else {
- type = Token.EXPR_RESULT;
- }
- return new Node (type, expr, lineno);
- }
-
- internal Node CreateExprStatementNoReturn (Node expr, int lineno)
- {
- return new Node (Token.EXPR_VOID, expr, lineno);
- }
-
- internal Node CreateDefaultNamespace (Node expr, int lineno)
- {
- // default xml namespace requires activation
- setRequiresActivation ();
- Node n = CreateUnary (Token.DEFAULTNAMESPACE, expr);
- Node result = CreateExprStatement (n, lineno);
- return result;
- }
-
- /// Name
- internal Node CreateName (string name)
- {
- checkActivationName (name, Token.NAME);
- return Node.newString (Token.NAME, name);
- }
-
- /// String (for literals)
- internal Node CreateString (string str)
- {
- return Node.newString (str);
- }
-
- /// Number (for literals)
- internal Node CreateNumber (double number)
- {
- return Node.newNumber (number);
- }
-
- /// Catch clause of try/catch/finally
- /// the name of the variable to bind to the exception
- ///
- /// the condition under which to catch the exception.
- /// May be null if no condition is given.
- ///
- /// the statements in the catch clause
- ///
- /// the starting line number of the catch clause
- ///
- internal Node CreateCatch (string varName, Node catchCond, Node stmts, int lineno)
- {
- if (catchCond == null) {
- catchCond = new Node (Token.EMPTY);
- }
- return new Node (Token.CATCH, CreateName (varName), catchCond, stmts, lineno);
- }
-
- /// Throw
- internal Node CreateThrow (Node expr, int lineno)
- {
- return new Node (Token.THROW, expr, lineno);
- }
-
- /// Return
- internal Node CreateReturn (Node expr, int lineno)
- {
- return expr == null ? new Node (Token.RETURN, lineno) : new Node (Token.RETURN, expr, lineno);
- }
-
- /// Debugger
- internal Node CreateDebugger(int lineno)
- {
- return new Node(Token.DEBUGGER, lineno);
- }
-
- /// Label
- internal Node CreateLabel (int lineno)
- {
- return new Node.Jump (Token.LABEL, lineno);
- }
-
- internal Node getLabelLoop (Node label)
- {
- return ((Node.Jump)label).Loop;
- }
-
- /// Label
- internal Node CreateLabeledStatement (Node labelArg, Node statement)
- {
- Node.Jump label = (Node.Jump)labelArg;
-
- // Make a target and put it _after_ the statement
- // node. And in the LABEL node, so breaks get the
- // right target.
-
- Node breakTarget = Node.newTarget ();
- Node block = new Node (Token.BLOCK, label, statement, breakTarget);
- label.target = breakTarget;
-
- return block;
- }
-
- /// Break (possibly labeled)
- internal Node CreateBreak (Node breakStatement, int lineno)
- {
- Node.Jump n = new Node.Jump (Token.BREAK, lineno);
- Node.Jump jumpStatement;
- int t = breakStatement.Type;
- if (t == Token.LOOP || t == Token.LABEL) {
- jumpStatement = (Node.Jump)breakStatement;
- }
- else if (t == Token.BLOCK && breakStatement.FirstChild.Type == Token.SWITCH) {
- jumpStatement = (Node.Jump)breakStatement.FirstChild;
- }
- else {
- throw Context.CodeBug ();
- }
- n.JumpStatement = jumpStatement;
- return n;
- }
-
- /// Continue (possibly labeled)
- internal Node CreateContinue (Node loop, int lineno)
- {
- if (loop.Type != Token.LOOP)
- Context.CodeBug ();
- Node.Jump n = new Node.Jump (Token.CONTINUE, lineno);
- n.JumpStatement = (Node.Jump)loop;
- return n;
- }
-
- /// Statement block
- /// Creates the empty statement block
- /// Must make subsequent calls to add statements to the node
- ///
- internal Node CreateBlock (int lineno)
- {
- return new Node (Token.BLOCK, lineno);
- }
-
- internal FunctionNode CreateFunction (string name)
- {
- return new FunctionNode (name);
- }
-
- internal Node initFunction (FunctionNode fnNode, int functionIndex, Node statements, int functionType)
- {
- fnNode.itsFunctionType = functionType;
- fnNode.addChildToBack (statements);
-
- int functionCount = fnNode.FunctionCount;
- if (functionCount != 0) {
- // Functions containing other functions require activation objects
- fnNode.itsNeedsActivation = true;
- for (int i = 0; i != functionCount; ++i) {
- FunctionNode fn = fnNode.getFunctionNode (i);
- // nested function expression statements overrides var
- if (fn.FunctionType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) {
- string name = fn.FunctionName;
- if (name != null && name.Length != 0) {
- fnNode.removeParamOrVar (name);
- }
- }
- }
- }
-
- if (functionType == FunctionNode.FUNCTION_EXPRESSION) {
- string name = fnNode.FunctionName;
- if (name != null && name.Length != 0 && !fnNode.hasParamOrVar (name)) {
- // A function expression needs to have its name as a
- // variable (if it isn't already allocated as a variable).
- // See ECMA Ch. 13. We add code to the beginning of the
- // function to initialize a local variable of the
- // function's name to the function value.
- fnNode.addVar (name);
- Node setFn = new Node (Token.EXPR_VOID, new Node (Token.SETNAME, Node.newString (Token.BINDNAME, name), new Node (Token.THISFN)));
- statements.addChildrenToFront (setFn);
- }
- }
-
- // Add return to end if needed.
- Node lastStmt = statements.LastChild;
- if (lastStmt == null || lastStmt.Type != Token.RETURN) {
- statements.addChildToBack (new Node (Token.RETURN));
- }
-
- Node result = Node.newString (Token.FUNCTION, fnNode.FunctionName);
- result.putIntProp (Node.FUNCTION_PROP, functionIndex);
- return result;
- }
-
- /// Add a child to the back of the given node. This function
- /// breaks the Factory abstraction, but it removes a requirement
- /// from implementors of Node.
- ///
- internal void addChildToBack (Node parent, Node child)
- {
- parent.addChildToBack (child);
- }
-
- /// Create loop node. The parser will later call
- /// CreateWhile|CreateDoWhile|CreateFor|CreateForIn
- /// to finish loop generation.
- ///
- internal Node CreateLoopNode (Node loopLabel, int lineno)
- {
- Node.Jump result = new Node.Jump (Token.LOOP, lineno);
- if (loopLabel != null) {
- ((Node.Jump)loopLabel).Loop = result;
- }
- return result;
- }
-
- /// While
- internal Node CreateWhile (Node loop, Node cond, Node body)
- {
- return CreateLoop ((Node.Jump)loop, LOOP_WHILE, body, cond, null, null);
- }
-
- /// DoWhile
- internal Node CreateDoWhile (Node loop, Node body, Node cond)
- {
- return CreateLoop ((Node.Jump)loop, LOOP_DO_WHILE, body, cond, null, null);
- }
-
- /// For
- internal Node CreateFor (Node loop, Node init, Node test, Node incr, Node body)
- {
- return CreateLoop ((Node.Jump)loop, LOOP_FOR, body, test, init, incr);
- }
-
- private Node CreateLoop (Node.Jump loop, int loopType, Node body, Node cond, Node init, Node incr)
- {
- Node bodyTarget = Node.newTarget ();
- Node condTarget = Node.newTarget ();
- if (loopType == LOOP_FOR && cond.Type == Token.EMPTY) {
- cond = new Node (Token.TRUE);
- }
- Node.Jump IFEQ = new Node.Jump (Token.IFEQ, cond);
- IFEQ.target = bodyTarget;
- Node breakTarget = Node.newTarget ();
-
- loop.addChildToBack (bodyTarget);
- loop.addChildrenToBack (body);
- if (loopType == LOOP_WHILE || loopType == LOOP_FOR) {
- // propagate lineno to condition
- loop.addChildrenToBack (new Node (Token.EMPTY, loop.Lineno));
- }
- loop.addChildToBack (condTarget);
- loop.addChildToBack (IFEQ);
- loop.addChildToBack (breakTarget);
-
- loop.target = breakTarget;
- Node continueTarget = condTarget;
-
- if (loopType == LOOP_WHILE || loopType == LOOP_FOR) {
- // Just add a GOTO to the condition in the do..while
- loop.addChildToFront (makeJump (Token.GOTO, condTarget));
-
- if (loopType == LOOP_FOR) {
- if (init.Type != Token.EMPTY) {
- if (init.Type != Token.VAR) {
- init = new Node (Token.EXPR_VOID, init);
- }
- loop.addChildToFront (init);
- }
- Node incrTarget = Node.newTarget ();
- loop.addChildAfter (incrTarget, body);
- if (incr.Type != Token.EMPTY) {
- incr = new Node (Token.EXPR_VOID, incr);
- loop.addChildAfter (incr, incrTarget);
- }
- continueTarget = incrTarget;
- }
- }
-
- loop.Continue = continueTarget;
-
- return loop;
- }
-
- /// For .. In
- ///
- ///
- internal Node CreateForIn (Node loop, Node lhs, Node obj, Node body, bool isForEach)
- {
- int type = lhs.Type;
-
- Node lvalue;
- if (type == Token.VAR) {
- /*
- * check that there was only one variable given.
- * we can't do this in the parser, because then the
- * parser would have to know something about the
- * 'init' node of the for-in loop.
- */
- Node lastChild = lhs.LastChild;
- if (lhs.FirstChild != lastChild) {
- parser.ReportError ("msg.mult.index");
- }
- lvalue = Node.newString (Token.NAME, lastChild.String);
- }
- else {
- lvalue = makeReference (lhs);
- if (lvalue == null) {
- parser.ReportError ("msg.bad.for.in.lhs");
- return obj;
- }
- }
-
- Node localBlock = new Node (Token.LOCAL_BLOCK);
-
- int initType = (isForEach) ? Token.ENUM_INIT_VALUES : Token.ENUM_INIT_KEYS;
- Node init = new Node (initType, obj);
- init.putProp (Node.LOCAL_BLOCK_PROP, localBlock);
- Node cond = new Node (Token.ENUM_NEXT);
- cond.putProp (Node.LOCAL_BLOCK_PROP, localBlock);
- Node id = new Node (Token.ENUM_ID);
- id.putProp (Node.LOCAL_BLOCK_PROP, localBlock);
-
- Node newBody = new Node (Token.BLOCK);
- Node assign = simpleAssignment (lvalue, id);
- newBody.addChildToBack (new Node (Token.EXPR_VOID, assign));
- newBody.addChildToBack (body);
-
- loop = CreateWhile (loop, cond, newBody);
- loop.addChildToFront (init);
- if (type == Token.VAR)
- loop.addChildToFront (lhs);
- localBlock.addChildToBack (loop);
-
- return localBlock;
- }
-
- /// Try/Catch/Finally
- ///
- /// The IRFactory tries to express as much as possible in the tree;
- /// the responsibilities remaining for Codegen are to add the Java
- /// handlers: (Either (but not both) of TARGET and FINALLY might not
- /// be defined)
- /// - a catch handler for javascript exceptions that unwraps the
- /// exception onto the stack and GOTOes to the catch target
- /// - a finally handler
- /// ... and a goto to GOTO around these handlers.
- ///
- internal Node CreateTryCatchFinally (Node tryBlock, Node catchBlocks, Node finallyBlock, int lineno)
- {
- bool hasFinally = (finallyBlock != null) && (finallyBlock.Type != Token.BLOCK || finallyBlock.hasChildren ());
-
- // short circuit
- if (tryBlock.Type == Token.BLOCK && !tryBlock.hasChildren () && !hasFinally) {
- return tryBlock;
- }
-
- bool hasCatch = catchBlocks.hasChildren ();
-
- // short circuit
- if (!hasFinally && !hasCatch) {
- // bc finally might be an empty block...
- return tryBlock;
- }
-
-
- Node handlerBlock = new Node (Token.LOCAL_BLOCK);
- Node.Jump pn = new Node.Jump (Token.TRY, tryBlock, lineno);
- pn.putProp (Node.LOCAL_BLOCK_PROP, handlerBlock);
-
- if (hasCatch) {
- // jump around catch code
- Node endCatch = Node.newTarget ();
- pn.addChildToBack (makeJump (Token.GOTO, endCatch));
-
- // make a TARGET for the catch that the tcf node knows about
- Node catchTarget = Node.newTarget ();
- pn.target = catchTarget;
- // mark it
- pn.addChildToBack (catchTarget);
-
- //
- // Given
- //
- // try {
- // tryBlock;
- // } catch (e if condition1) {
- // something1;
- // ...
- //
- // } catch (e if conditionN) {
- // somethingN;
- // } catch (e) {
- // somethingDefault;
- // }
- //
- // rewrite as
- //
- // try {
- // tryBlock;
- // goto after_catch:
- // } catch (x) {
- // with (newCatchScope(e, x)) {
- // if (condition1) {
- // something1;
- // goto after_catch;
- // }
- // }
- // ...
- // with (newCatchScope(e, x)) {
- // if (conditionN) {
- // somethingN;
- // goto after_catch;
- // }
- // }
- // with (newCatchScope(e, x)) {
- // somethingDefault;
- // goto after_catch;
- // }
- // }
- // after_catch:
- //
- // If there is no default catch, then the last with block
- // arround "somethingDefault;" is replaced by "rethrow;"
-
- // It is assumed that catch handler generation will store
- // exeception object in handlerBlock register
-
- // Block with local for exception scope objects
- Node catchScopeBlock = new Node (Token.LOCAL_BLOCK);
-
- // expects catchblocks children to be (cond block) pairs.
- Node cb = catchBlocks.FirstChild;
- bool hasDefault = false;
- int scopeIndex = 0;
- while (cb != null) {
- int catchLineNo = cb.Lineno;
-
- Node name = cb.FirstChild;
- Node cond = name.Next;
- Node catchStatement = cond.Next;
- cb.removeChild (name);
- cb.removeChild (cond);
- cb.removeChild (catchStatement);
-
- // Add goto to the catch statement to jump out of catch
- // but prefix it with LEAVEWITH since try..catch produces
- // "with"code in order to limit the scope of the exception
- // object.
- catchStatement.addChildToBack (new Node (Token.LEAVEWITH));
- catchStatement.addChildToBack (makeJump (Token.GOTO, endCatch));
-
- // Create condition "if" when present
- Node condStmt;
- if (cond.Type == Token.EMPTY) {
- condStmt = catchStatement;
- hasDefault = true;
- }
- else {
- condStmt = CreateIf (cond, catchStatement, null, catchLineNo);
- }
-
- // Generate code to Create the scope object and store
- // it in catchScopeBlock register
- Node catchScope = new Node (Token.CATCH_SCOPE, name, CreateUseLocal (handlerBlock));
- catchScope.putProp (Node.LOCAL_BLOCK_PROP, catchScopeBlock);
- catchScope.putIntProp (Node.CATCH_SCOPE_PROP, scopeIndex);
- catchScopeBlock.addChildToBack (catchScope);
-
- // Add with statement based on catch scope object
- catchScopeBlock.addChildToBack (CreateWith (CreateUseLocal (catchScopeBlock), condStmt, catchLineNo));
-
- // move to next cb
- cb = cb.Next;
- ++scopeIndex;
- }
- pn.addChildToBack (catchScopeBlock);
- if (!hasDefault) {
- // Generate code to rethrow if no catch clause was executed
- Node rethrow = new Node (Token.RETHROW);
- rethrow.putProp (Node.LOCAL_BLOCK_PROP, handlerBlock);
- pn.addChildToBack (rethrow);
- }
-
- pn.addChildToBack (endCatch);
- }
-
- if (hasFinally) {
- Node finallyTarget = Node.newTarget ();
- pn.Finally = finallyTarget;
-
- // add jsr finally to the try block
- pn.addChildToBack (makeJump (Token.JSR, finallyTarget));
-
- // jump around finally code
- Node finallyEnd = Node.newTarget ();
- pn.addChildToBack (makeJump (Token.GOTO, finallyEnd));
-
- pn.addChildToBack (finallyTarget);
- Node fBlock = new Node (Token.FINALLY, finallyBlock);
- fBlock.putProp (Node.LOCAL_BLOCK_PROP, handlerBlock);
- pn.addChildToBack (fBlock);
-
- pn.addChildToBack (finallyEnd);
- }
- handlerBlock.addChildToBack (pn);
- return handlerBlock;
- }
-
- /// Throw, Return, Label, Break and Continue are defined in ASTFactory.
-
- /// With
- internal Node CreateWith (Node obj, Node body, int lineno)
- {
- setRequiresActivation ();
- Node result = new Node (Token.BLOCK, lineno);
- result.addChildToBack (new Node (Token.ENTERWITH, obj));
- Node bodyNode = new Node (Token.WITH, body, lineno);
- result.addChildrenToBack (bodyNode);
- result.addChildToBack (new Node (Token.LEAVEWITH));
- return result;
- }
-
- /// DOTQUERY
- public Node CreateDotQuery (Node obj, Node body, int lineno)
- {
- setRequiresActivation ();
- Node result = new Node (Token.DOTQUERY, obj, body, lineno);
- return result;
- }
-
- internal Node CreateArrayLiteral (ObjArray elems, int skipCount)
- {
- int length = elems.size ();
- int [] skipIndexes = null;
- if (skipCount != 0) {
- skipIndexes = new int [skipCount];
- }
- Node array = new Node (Token.ARRAYLIT);
- for (int i = 0, j = 0; i != length; ++i) {
- Node elem = (Node)elems.Get (i);
- if (elem != null) {
- array.addChildToBack (elem);
- }
- else {
- skipIndexes [j] = i;
- ++j;
- }
- }
- if (skipCount != 0) {
- array.putProp (Node.SKIP_INDEXES_PROP, skipIndexes);
- }
- return array;
- }
-
- /// Object Literals
- ///
CreateObjectLiteral rewrites its argument as object
- /// creation plus object property entries, so later compiler
- /// stages don't need to know about object literals.
- ///
- internal Node CreateObjectLiteral (ObjArray elems)
- {
- int size = elems.size () / 2;
- Node obj = new Node (Token.OBJECTLIT);
- object [] properties;
- if (size == 0) {
- properties = ScriptRuntime.EmptyArgs;
- }
- else {
- properties = new object [size];
- for (int i = 0; i != size; ++i) {
- properties [i] = elems.Get (2 * i);
- Node value = (Node)elems.Get (2 * i + 1);
- obj.addChildToBack (value);
- }
- }
- obj.putProp (Node.OBJECT_IDS_PROP, properties);
- return obj;
- }
-
- /// Regular expressions
- internal Node CreateRegExp (int regexpIndex)
- {
- Node n = new Node (Token.REGEXP);
- n.putIntProp (Node.REGEXP_PROP, regexpIndex);
- return n;
- }
-
- /// If statement
- internal Node CreateIf (Node cond, Node ifTrue, Node ifFalse, int lineno)
- {
- int condStatus = isAlwaysDefinedBoolean (cond);
- if (condStatus == ALWAYS_TRUE_BOOLEAN) {
- return ifTrue;
- }
- else if (condStatus == ALWAYS_FALSE_BOOLEAN) {
- if (ifFalse != null) {
- return ifFalse;
- }
- return new Node (Token.BLOCK, lineno);
- }
-
- Node result = new Node (Token.BLOCK, lineno);
- Node ifNotTarget = Node.newTarget ();
- Node.Jump IFNE = new Node.Jump (Token.IFNE, cond);
- IFNE.target = ifNotTarget;
-
- result.addChildToBack (IFNE);
- result.addChildrenToBack (ifTrue);
-
- if (ifFalse != null) {
- Node endTarget = Node.newTarget ();
- result.addChildToBack (makeJump (Token.GOTO, endTarget));
- result.addChildToBack (ifNotTarget);
- result.addChildrenToBack (ifFalse);
- result.addChildToBack (endTarget);
- }
- else {
- result.addChildToBack (ifNotTarget);
- }
-
- return result;
- }
-
- internal Node CreateCondExpr (Node cond, Node ifTrue, Node ifFalse)
- {
- int condStatus = isAlwaysDefinedBoolean (cond);
- if (condStatus == ALWAYS_TRUE_BOOLEAN) {
- return ifTrue;
- }
- else if (condStatus == ALWAYS_FALSE_BOOLEAN) {
- return ifFalse;
- }
- return new Node (Token.HOOK, cond, ifTrue, ifFalse);
- }
-
- /// Unary
- internal Node CreateUnary (int nodeType, Node child)
- {
- int childType = child.Type;
- switch (nodeType) {
-
- case Token.DELPROP: {
- Node n;
- if (childType == Token.NAME) {
- // Transform Delete(Name "a")
- // to Delete(Bind("a"), String("a"))
- child.Type = Token.BINDNAME;
- Node left = child;
- Node right = Node.newString (child.String);
- n = new Node (nodeType, left, right);
- }
- else if (childType == Token.GETPROP || childType == Token.GETELEM) {
- Node left = child.FirstChild;
- Node right = child.LastChild;
- child.removeChild (left);
- child.removeChild (right);
- n = new Node (nodeType, left, right);
- }
- else if (childType == Token.GET_REF) {
- Node rf = child.FirstChild;
- child.removeChild (rf);
- n = new Node (Token.DEL_REF, rf);
- }
- else {
- n = new Node (Token.TRUE);
- }
- return n;
- }
-
- case Token.TYPEOF:
- if (childType == Token.NAME) {
- child.Type = Token.TYPEOFNAME;
- return child;
- }
- break;
-
- case Token.BITNOT:
- if (childType == Token.NUMBER) {
- int value = ScriptConvert.ToInt32 (child.Double);
- child.Double = ~value;
- return child;
- }
- break;
-
- case Token.NEG:
- if (childType == Token.NUMBER) {
- child.Double = -child.Double;
- return child;
- }
- break;
-
- case Token.NOT: {
- int status = isAlwaysDefinedBoolean (child);
- if (status != 0) {
- int type;
- if (status == ALWAYS_TRUE_BOOLEAN) {
- type = Token.FALSE;
- }
- else {
- type = Token.TRUE;
- }
- if (childType == Token.TRUE || childType == Token.FALSE) {
- child.Type = type;
- return child;
- }
- return new Node (type);
- }
- break;
- }
- }
- return new Node (nodeType, child);
- }
-
- internal Node CreateCallOrNew (int nodeType, Node child)
- {
- int type = Node.NON_SPECIALCALL;
- if (child.Type == Token.NAME) {
- string name = child.String;
- if (name.Equals ("eval")) {
- type = Node.SPECIALCALL_EVAL;
- }
- else if (name.Equals ("With")) {
- type = Node.SPECIALCALL_WITH;
- }
- }
- else if (child.Type == Token.GETPROP) {
- string name = child.LastChild.String;
- if (name.Equals ("eval")) {
- type = Node.SPECIALCALL_EVAL;
- }
- }
- Node node = new Node (nodeType, child);
- if (type != Node.NON_SPECIALCALL) {
- // Calls to these functions require activation objects.
- setRequiresActivation ();
- node.putIntProp (Node.SPECIALCALL_PROP, type);
- }
- return node;
- }
-
- internal Node CreateIncDec (int nodeType, bool post, Node child)
- {
- child = makeReference (child);
- if (child == null) {
- string msg;
- if (nodeType == Token.DEC) {
- msg = "msg.bad.decr";
- }
- else {
- msg = "msg.bad.incr";
- }
- parser.ReportError (msg);
- return null;
- }
-
- int childType = child.Type;
-
- switch (childType) {
-
- case Token.NAME:
- case Token.GETPROP:
- case Token.GETELEM:
- case Token.GET_REF: {
- Node n = new Node (nodeType, child);
- int incrDecrMask = 0;
- if (nodeType == Token.DEC) {
- incrDecrMask |= Node.DECR_FLAG;
- }
- if (post) {
- incrDecrMask |= Node.POST_FLAG;
- }
- n.putIntProp (Node.INCRDECR_PROP, incrDecrMask);
- return n;
- }
- }
- throw Context.CodeBug ();
- }
-
- internal Node CreatePropertyGet (Node target, string ns, string name, int memberTypeFlags)
- {
- if (ns == null && memberTypeFlags == 0) {
- if (target == null) {
- return CreateName (name);
- }
- checkActivationName (name, Token.GETPROP);
- if (ScriptRuntime.isSpecialProperty (name)) {
- Node rf = new Node (Token.REF_SPECIAL, target);
- rf.putProp (Node.NAME_PROP, name);
- return new Node (Token.GET_REF, rf);
- }
- return new Node (Token.GETPROP, target, CreateString (name));
- }
- Node elem = CreateString (name);
- memberTypeFlags |= Node.PROPERTY_FLAG;
- return CreateMemberRefGet (target, ns, elem, memberTypeFlags);
- }
-
- internal Node CreateElementGet (Node target, string ns, Node elem, int memberTypeFlags)
- {
- // OPT: could optimize to CreatePropertyGet
- // iff elem is string that can not be number
- if (ns == null && memberTypeFlags == 0) {
- // stand-alone [aaa] as primary expression is array literal
- // declaration and should not come here!
- if (target == null)
- throw Context.CodeBug ();
- return new Node (Token.GETELEM, target, elem);
- }
- return CreateMemberRefGet (target, ns, elem, memberTypeFlags);
- }
-
- private Node CreateMemberRefGet (Node target, string ns, Node elem, int memberTypeFlags)
- {
- Node nsNode = null;
- if (ns != null) {
- // See 11.1.2 in ECMA 357
- if (ns.Equals ("*")) {
- nsNode = new Node (Token.NULL);
- }
- else {
- nsNode = CreateName (ns);
- }
- }
- Node rf;
- if (target == null) {
- if (ns == null) {
- rf = new Node (Token.REF_NAME, elem);
- }
- else {
- rf = new Node (Token.REF_NS_NAME, nsNode, elem);
- }
- }
- else {
- if (ns == null) {
- rf = new Node (Token.REF_MEMBER, target, elem);
- }
- else {
- rf = new Node (Token.REF_NS_MEMBER, target, nsNode, elem);
- }
- }
- if (memberTypeFlags != 0) {
- rf.putIntProp (Node.MEMBER_TYPE_PROP, memberTypeFlags);
- }
- return new Node (Token.GET_REF, rf);
- }
-
- /// Binary
- internal Node CreateBinary (int nodeType, Node left, Node right)
- {
- switch (nodeType) {
-
-
- case Token.ADD:
- // numerical addition and string concatenation
- if (left.Type == Token.STRING) {
- string s2;
- if (right.Type == Token.STRING) {
- s2 = right.String;
- }
- else if (right.Type == Token.NUMBER) {
- s2 = ScriptConvert.ToString (right.Double, 10);
- }
- else {
- break;
- }
- string s1 = left.String;
- left.String = string.Concat (s1, s2);
- return left;
- }
- else if (left.Type == Token.NUMBER) {
- if (right.Type == Token.NUMBER) {
- left.Double = left.Double + right.Double;
- return left;
- }
- else if (right.Type == Token.STRING) {
- string s1, s2;
- s1 = ScriptConvert.ToString (left.Double, 10);
- s2 = right.String;
- right.String = string.Concat (s1, s2);
- return right;
- }
- }
- // can't do anything if we don't know both types - since
- // 0 + object is supposed to call toString on the object and do
- // string concantenation rather than addition
- break;
-
-
- case Token.SUB:
- // numerical subtraction
- if (left.Type == Token.NUMBER) {
- double ld = left.Double;
- if (right.Type == Token.NUMBER) {
- //both numbers
- left.Double = ld - right.Double;
- return left;
- }
- else if (ld == 0.0) {
- // first 0: 0-x -> -x
- return new Node (Token.NEG, right);
- }
- }
- else if (right.Type == Token.NUMBER) {
- if (right.Double == 0.0) {
- //second 0: x - 0 -> +x
- // can not make simply x because x - 0 must be number
- return new Node (Token.POS, left);
- }
- }
- break;
-
-
- case Token.MUL:
- // numerical multiplication
- if (left.Type == Token.NUMBER) {
- double ld = left.Double;
- if (right.Type == Token.NUMBER) {
- //both numbers
- left.Double = ld * right.Double;
- return left;
- }
- else if (ld == 1.0) {
- // first 1: 1 * x -> +x
- return new Node (Token.POS, right);
- }
- }
- else if (right.Type == Token.NUMBER) {
- if (right.Double == 1.0) {
- //second 1: x * 1 -> +x
- // can not make simply x because x - 0 must be number
- return new Node (Token.POS, left);
- }
- }
- // can't do x*0: Infinity * 0 gives NaN, not 0
- break;
-
-
- case Token.DIV:
- // number division
- if (right.Type == Token.NUMBER) {
- double rd = right.Double;
- if (left.Type == Token.NUMBER) {
- // both constants -- just divide, trust Java to handle x/0
- left.Double = left.Double / rd;
- return left;
- }
- else if (rd == 1.0) {
- // second 1: x/1 -> +x
- // not simply x to force number convertion
- return new Node (Token.POS, left);
- }
- }
- break;
-
-
- case Token.AND: {
- int leftStatus = isAlwaysDefinedBoolean (left);
- if (leftStatus == ALWAYS_FALSE_BOOLEAN) {
- // if the first one is false, replace with FALSE
- return new Node (Token.FALSE);
- }
- else if (leftStatus == ALWAYS_TRUE_BOOLEAN) {
- // if first is true, set to second
- return right;
- }
- int rightStatus = isAlwaysDefinedBoolean (right);
- if (rightStatus == ALWAYS_FALSE_BOOLEAN) {
- // if the second one is false, replace with FALSE
- if (!hasSideEffects (left)) {
- return new Node (Token.FALSE);
- }
- }
- else if (rightStatus == ALWAYS_TRUE_BOOLEAN) {
- // if second is true, set to first
- return left;
- }
- break;
- }
-
-
- case Token.OR: {
- int leftStatus = isAlwaysDefinedBoolean (left);
- if (leftStatus == ALWAYS_TRUE_BOOLEAN) {
- // if the first one is true, replace with TRUE
- return new Node (Token.TRUE);
- }
- else if (leftStatus == ALWAYS_FALSE_BOOLEAN) {
- // if first is false, set to second
- return right;
- }
- int rightStatus = isAlwaysDefinedBoolean (right);
- if (rightStatus == ALWAYS_TRUE_BOOLEAN) {
- // if the second one is true, replace with TRUE
- if (!hasSideEffects (left)) {
- return new Node (Token.TRUE);
- }
- }
- else if (rightStatus == ALWAYS_FALSE_BOOLEAN) {
- // if second is false, set to first
- return left;
- }
- break;
- }
- }
-
- return new Node (nodeType, left, right);
- }
-
- private Node simpleAssignment (Node left, Node right)
- {
- int nodeType = left.Type;
- switch (nodeType) {
-
- case Token.NAME:
- left.Type = Token.BINDNAME;
- return new Node (Token.SETNAME, left, right);
-
-
- case Token.GETPROP:
- case Token.GETELEM: {
- Node obj = left.FirstChild;
- Node id = left.LastChild;
- int type;
- if (nodeType == Token.GETPROP) {
- type = Token.SETPROP;
- }
- else {
- type = Token.SETELEM;
- }
- return new Node (type, obj, id, right);
- }
-
- case Token.GET_REF: {
- Node rf = left.FirstChild;
- checkMutableReference (rf);
- return new Node (Token.SET_REF, rf, right);
- }
- }
-
- throw Context.CodeBug ();
- }
-
- private void checkMutableReference (Node n)
- {
- int memberTypeFlags = n.getIntProp (Node.MEMBER_TYPE_PROP, 0);
- if ((memberTypeFlags & Node.DESCENDANTS_FLAG) != 0) {
- parser.ReportError ("msg.bad.assign.left");
- }
- }
-
- internal Node CreateAssignment (int assignType, Node left, Node right)
- {
- left = makeReference (left);
- if (left == null) {
- parser.ReportError ("msg.bad.assign.left");
- return right;
- }
-
- int assignOp;
- switch (assignType) {
-
- case Token.ASSIGN:
- return simpleAssignment (left, right);
-
- case Token.ASSIGN_BITOR:
- assignOp = Token.BITOR;
- break;
-
- case Token.ASSIGN_BITXOR:
- assignOp = Token.BITXOR;
- break;
-
- case Token.ASSIGN_BITAND:
- assignOp = Token.BITAND;
- break;
-
- case Token.ASSIGN_LSH:
- assignOp = Token.LSH;
- break;
-
- case Token.ASSIGN_RSH:
- assignOp = Token.RSH;
- break;
-
- case Token.ASSIGN_URSH:
- assignOp = Token.URSH;
- break;
-
- case Token.ASSIGN_ADD:
- assignOp = Token.ADD;
- break;
-
- case Token.ASSIGN_SUB:
- assignOp = Token.SUB;
- break;
-
- case Token.ASSIGN_MUL:
- assignOp = Token.MUL;
- break;
-
- case Token.ASSIGN_DIV:
- assignOp = Token.DIV;
- break;
-
- case Token.ASSIGN_MOD:
- assignOp = Token.MOD;
- break;
-
- default:
- throw Context.CodeBug ();
-
- }
-
- int nodeType = left.Type;
- switch (nodeType) {
-
- case Token.NAME: {
- string s = left.String;
-
- Node opLeft = Node.newString (Token.NAME, s);
- Node op = new Node (assignOp, opLeft, right);
- Node lvalueLeft = Node.newString (Token.BINDNAME, s);
- return new Node (Token.SETNAME, lvalueLeft, op);
- }
-
- case Token.GETPROP:
- case Token.GETELEM: {
- Node obj = left.FirstChild;
- Node id = left.LastChild;
-
- int type = nodeType == Token.GETPROP ? Token.SETPROP_OP : Token.SETELEM_OP;
-
- Node opLeft = new Node (Token.USE_STACK);
- Node op = new Node (assignOp, opLeft, right);
- return new Node (type, obj, id, op);
- }
-
- case Token.GET_REF: {
- Node rf = left.FirstChild;
- checkMutableReference (rf);
- Node opLeft = new Node (Token.USE_STACK);
- Node op = new Node (assignOp, opLeft, right);
- return new Node (Token.SET_REF_OP, rf, op);
- }
- }
-
- throw Context.CodeBug ();
- }
-
- internal Node CreateUseLocal (Node localBlock)
- {
- if (Token.LOCAL_BLOCK != localBlock.Type)
- throw Context.CodeBug ();
- Node result = new Node (Token.LOCAL_LOAD);
- result.putProp (Node.LOCAL_BLOCK_PROP, localBlock);
- return result;
- }
-
- private Node.Jump makeJump (int type, Node target)
- {
- Node.Jump n = new Node.Jump (type);
- n.target = target;
- return n;
- }
-
- private Node makeReference (Node node)
- {
- int type = node.Type;
- switch (type) {
-
- case Token.NAME:
- case Token.GETPROP:
- case Token.GETELEM:
- case Token.GET_REF:
- return node;
-
- case Token.CALL:
- node.Type = Token.REF_CALL;
- return new Node (Token.GET_REF, node);
- }
- // Signal caller to report error
- return null;
- }
-
- // Check if Node always mean true or false in boolean context
- private static int isAlwaysDefinedBoolean (Node node)
- {
- switch (node.Type) {
-
- case Token.FALSE:
- case Token.NULL:
- return ALWAYS_FALSE_BOOLEAN;
-
- case Token.TRUE:
- return ALWAYS_TRUE_BOOLEAN;
-
- case Token.NUMBER: {
- double num = node.Double;
- if (!double.IsNaN (num) && num != 0.0) {
- return ALWAYS_TRUE_BOOLEAN;
- }
- else {
- return ALWAYS_FALSE_BOOLEAN;
- }
- }
- }
- return 0;
- }
-
- private static bool hasSideEffects (Node exprTree)
- {
- switch (exprTree.Type) {
-
- case Token.INC:
- case Token.DEC:
- case Token.SETPROP:
- case Token.SETELEM:
- case Token.SETNAME:
- case Token.CALL:
- case Token.NEW:
- return true;
-
- default:
- Node child = exprTree.FirstChild;
- while (child != null) {
- if (hasSideEffects (child))
- return true;
- child = child.Next;
- }
- break;
-
- }
- return false;
- }
-
- private void checkActivationName (string name, int token)
- {
- if (parser.insideFunction ()) {
- bool activation = false;
- if ("arguments".Equals (name) || (parser.compilerEnv.activationNames != null && parser.compilerEnv.activationNames.ContainsKey (name))) {
- activation = true;
- }
- else if ("length".Equals (name)) {
- if (token == Token.GETPROP && parser.compilerEnv.LanguageVersion == Context.Versions.JS1_2) {
- // Use of "length" in 1.2 requires an activation object.
- activation = true;
- }
- }
- if (activation) {
- setRequiresActivation ();
- }
- }
- }
-
- private void setRequiresActivation ()
- {
- if (parser.insideFunction ()) {
- ((FunctionNode)parser.currentScriptOrFn).itsNeedsActivation = true;
- }
- }
-
- private Parser parser;
-
- private const int LOOP_DO_WHILE = 0;
- private const int LOOP_WHILE = 1;
- private const int LOOP_FOR = 2;
-
- private const int ALWAYS_TRUE_BOOLEAN = 1;
- private const int ALWAYS_FALSE_BOOLEAN = -1;
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+using EcmaScript.NET.Collections;
+
+namespace EcmaScript.NET
+{
+
+ /// This class allows the creation of nodes, and follows the Factory pattern.
+ ///
+ ///
+ sealed class NodeFactory
+ {
+ internal NodeFactory (Parser parser)
+ {
+ this.parser = parser;
+ }
+
+ internal ScriptOrFnNode CreateScript ()
+ {
+ return new ScriptOrFnNode (Token.SCRIPT);
+ }
+
+ /// Script (for associating file/url names with toplevel scripts.)
+ internal void initScript (ScriptOrFnNode scriptNode, Node body)
+ {
+ Node children = body.FirstChild;
+ if (children != null) {
+ scriptNode.addChildrenToBack (children);
+ }
+ }
+
+ /// Leaf
+ internal Node CreateLeaf (int nodeType)
+ {
+ return new Node (nodeType);
+ }
+
+ internal Node CreateLeaf (int nodeType, int nodeOp)
+ {
+ return new Node (nodeType, nodeOp);
+ }
+
+ /// Statement leaf nodes.
+
+ internal Node CreateSwitch (Node expr, int lineno)
+ {
+ //
+ // The switch will be rewritten from:
+ //
+ // switch (expr) {
+ // case test1: statements1;
+ // ...
+ // default: statementsDefault;
+ // ...
+ // case testN: statementsN;
+ // }
+ //
+ // to:
+ //
+ // {
+ // switch (expr) {
+ // case test1: goto label1;
+ // ...
+ // case testN: goto labelN;
+ // }
+ // goto labelDefault;
+ // label1:
+ // statements1;
+ // ...
+ // labelDefault:
+ // statementsDefault;
+ // ...
+ // labelN:
+ // statementsN;
+ // breakLabel:
+ // }
+ //
+ // where inside switch each "break;" without label will be replaced
+ // by "goto breakLabel".
+ //
+ // If the original switch does not have the default label, then
+ // the transformed code would contain after the switch instead of
+ // goto labelDefault;
+ // the following goto:
+ // goto breakLabel;
+ //
+
+ Node.Jump switchNode = new Node.Jump (Token.SWITCH, expr, lineno);
+ Node block = new Node (Token.BLOCK, switchNode);
+ return block;
+ }
+
+ /// If caseExpression argument is null it indicate default label.
+ internal void addSwitchCase (Node switchBlock, Node caseExpression, Node statements)
+ {
+ if (switchBlock.Type != Token.BLOCK)
+ throw Context.CodeBug ();
+ Node.Jump switchNode = (Node.Jump)switchBlock.FirstChild;
+ if (switchNode.Type != Token.SWITCH)
+ throw Context.CodeBug ();
+
+ Node gotoTarget = Node.newTarget ();
+ if (caseExpression != null) {
+ Node.Jump caseNode = new Node.Jump (Token.CASE, caseExpression);
+ caseNode.target = gotoTarget;
+ switchNode.addChildToBack (caseNode);
+ }
+ else {
+ switchNode.Default = gotoTarget;
+ }
+ switchBlock.addChildToBack (gotoTarget);
+ switchBlock.addChildToBack (statements);
+ }
+
+ internal void closeSwitch (Node switchBlock)
+ {
+ if (switchBlock.Type != Token.BLOCK)
+ throw Context.CodeBug ();
+ Node.Jump switchNode = (Node.Jump)switchBlock.FirstChild;
+ if (switchNode.Type != Token.SWITCH)
+ throw Context.CodeBug ();
+
+ Node switchBreakTarget = Node.newTarget ();
+ // switchNode.target is only used by NodeTransformer
+ // to detect switch end
+ switchNode.target = switchBreakTarget;
+
+ Node defaultTarget = switchNode.Default;
+ if (defaultTarget == null) {
+ defaultTarget = switchBreakTarget;
+ }
+
+ switchBlock.addChildAfter (makeJump (Token.GOTO, defaultTarget), switchNode);
+ switchBlock.addChildToBack (switchBreakTarget);
+ }
+
+ internal Node CreateVariables (int lineno)
+ {
+ return new Node (Token.VAR, lineno);
+ }
+
+ internal Node CreateExprStatement (Node expr, int lineno)
+ {
+ int type;
+ if (parser.insideFunction ()) {
+ type = Token.EXPR_VOID;
+ }
+ else {
+ type = Token.EXPR_RESULT;
+ }
+ return new Node (type, expr, lineno);
+ }
+
+ internal Node CreateExprStatementNoReturn (Node expr, int lineno)
+ {
+ return new Node (Token.EXPR_VOID, expr, lineno);
+ }
+
+ internal Node CreateDefaultNamespace (Node expr, int lineno)
+ {
+ // default xml namespace requires activation
+ setRequiresActivation ();
+ Node n = CreateUnary (Token.DEFAULTNAMESPACE, expr);
+ Node result = CreateExprStatement (n, lineno);
+ return result;
+ }
+
+ /// Name
+ internal Node CreateName (string name)
+ {
+ checkActivationName (name, Token.NAME);
+ return Node.newString (Token.NAME, name);
+ }
+
+ /// String (for literals)
+ internal Node CreateString (string str)
+ {
+ return Node.newString (str);
+ }
+
+ /// Number (for literals)
+ internal Node CreateNumber (double number)
+ {
+ return Node.newNumber (number);
+ }
+
+ /// Catch clause of try/catch/finally
+ /// the name of the variable to bind to the exception
+ ///
+ /// the condition under which to catch the exception.
+ /// May be null if no condition is given.
+ ///
+ /// the statements in the catch clause
+ ///
+ /// the starting line number of the catch clause
+ ///
+ internal Node CreateCatch (string varName, Node catchCond, Node stmts, int lineno)
+ {
+ if (catchCond == null) {
+ catchCond = new Node (Token.EMPTY);
+ }
+ return new Node (Token.CATCH, CreateName (varName), catchCond, stmts, lineno);
+ }
+
+ /// Throw
+ internal Node CreateThrow (Node expr, int lineno)
+ {
+ return new Node (Token.THROW, expr, lineno);
+ }
+
+ /// Return
+ internal Node CreateReturn (Node expr, int lineno)
+ {
+ return expr == null ? new Node (Token.RETURN, lineno) : new Node (Token.RETURN, expr, lineno);
+ }
+
+ /// Debugger
+ internal Node CreateDebugger(int lineno)
+ {
+ return new Node(Token.DEBUGGER, lineno);
+ }
+
+ /// Label
+ internal Node CreateLabel (int lineno)
+ {
+ return new Node.Jump (Token.LABEL, lineno);
+ }
+
+ internal Node getLabelLoop (Node label)
+ {
+ return ((Node.Jump)label).Loop;
+ }
+
+ /// Label
+ internal Node CreateLabeledStatement (Node labelArg, Node statement)
+ {
+ Node.Jump label = (Node.Jump)labelArg;
+
+ // Make a target and put it _after_ the statement
+ // node. And in the LABEL node, so breaks get the
+ // right target.
+
+ Node breakTarget = Node.newTarget ();
+ Node block = new Node (Token.BLOCK, label, statement, breakTarget);
+ label.target = breakTarget;
+
+ return block;
+ }
+
+ /// Break (possibly labeled)
+ internal Node CreateBreak (Node breakStatement, int lineno)
+ {
+ Node.Jump n = new Node.Jump (Token.BREAK, lineno);
+ Node.Jump jumpStatement;
+ int t = breakStatement.Type;
+ if (t == Token.LOOP || t == Token.LABEL) {
+ jumpStatement = (Node.Jump)breakStatement;
+ }
+ else if (t == Token.BLOCK && breakStatement.FirstChild.Type == Token.SWITCH) {
+ jumpStatement = (Node.Jump)breakStatement.FirstChild;
+ }
+ else {
+ throw Context.CodeBug ();
+ }
+ n.JumpStatement = jumpStatement;
+ return n;
+ }
+
+ /// Continue (possibly labeled)
+ internal Node CreateContinue (Node loop, int lineno)
+ {
+ if (loop.Type != Token.LOOP)
+ Context.CodeBug ();
+ Node.Jump n = new Node.Jump (Token.CONTINUE, lineno);
+ n.JumpStatement = (Node.Jump)loop;
+ return n;
+ }
+
+ /// Statement block
+ /// Creates the empty statement block
+ /// Must make subsequent calls to add statements to the node
+ ///
+ internal Node CreateBlock (int lineno)
+ {
+ return new Node (Token.BLOCK, lineno);
+ }
+
+ internal FunctionNode CreateFunction (string name)
+ {
+ return new FunctionNode (name);
+ }
+
+ internal Node initFunction (FunctionNode fnNode, int functionIndex, Node statements, int functionType)
+ {
+ fnNode.itsFunctionType = functionType;
+ fnNode.addChildToBack (statements);
+
+ int functionCount = fnNode.FunctionCount;
+ if (functionCount != 0) {
+ // Functions containing other functions require activation objects
+ fnNode.itsNeedsActivation = true;
+ for (int i = 0; i != functionCount; ++i) {
+ FunctionNode fn = fnNode.getFunctionNode (i);
+ // nested function expression statements overrides var
+ if (fn.FunctionType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) {
+ string name = fn.FunctionName;
+ if (name != null && name.Length != 0) {
+ fnNode.removeParamOrVar (name);
+ }
+ }
+ }
+ }
+
+ if (functionType == FunctionNode.FUNCTION_EXPRESSION) {
+ string name = fnNode.FunctionName;
+ if (name != null && name.Length != 0 && !fnNode.hasParamOrVar (name)) {
+ // A function expression needs to have its name as a
+ // variable (if it isn't already allocated as a variable).
+ // See ECMA Ch. 13. We add code to the beginning of the
+ // function to initialize a local variable of the
+ // function's name to the function value.
+ fnNode.addVar (name);
+ Node setFn = new Node (Token.EXPR_VOID, new Node (Token.SETNAME, Node.newString (Token.BINDNAME, name), new Node (Token.THISFN)));
+ statements.addChildrenToFront (setFn);
+ }
+ }
+
+ // Add return to end if needed.
+ Node lastStmt = statements.LastChild;
+ if (lastStmt == null || lastStmt.Type != Token.RETURN) {
+ statements.addChildToBack (new Node (Token.RETURN));
+ }
+
+ Node result = Node.newString (Token.FUNCTION, fnNode.FunctionName);
+ result.putIntProp (Node.FUNCTION_PROP, functionIndex);
+ return result;
+ }
+
+ /// Add a child to the back of the given node. This function
+ /// breaks the Factory abstraction, but it removes a requirement
+ /// from implementors of Node.
+ ///
+ internal void addChildToBack (Node parent, Node child)
+ {
+ parent.addChildToBack (child);
+ }
+
+ /// Create loop node. The parser will later call
+ /// CreateWhile|CreateDoWhile|CreateFor|CreateForIn
+ /// to finish loop generation.
+ ///
+ internal Node CreateLoopNode (Node loopLabel, int lineno)
+ {
+ Node.Jump result = new Node.Jump (Token.LOOP, lineno);
+ if (loopLabel != null) {
+ ((Node.Jump)loopLabel).Loop = result;
+ }
+ return result;
+ }
+
+ /// While
+ internal Node CreateWhile (Node loop, Node cond, Node body)
+ {
+ return CreateLoop ((Node.Jump)loop, LOOP_WHILE, body, cond, null, null);
+ }
+
+ /// DoWhile
+ internal Node CreateDoWhile (Node loop, Node body, Node cond)
+ {
+ return CreateLoop ((Node.Jump)loop, LOOP_DO_WHILE, body, cond, null, null);
+ }
+
+ /// For
+ internal Node CreateFor (Node loop, Node init, Node test, Node incr, Node body)
+ {
+ return CreateLoop ((Node.Jump)loop, LOOP_FOR, body, test, init, incr);
+ }
+
+ private Node CreateLoop (Node.Jump loop, int loopType, Node body, Node cond, Node init, Node incr)
+ {
+ Node bodyTarget = Node.newTarget ();
+ Node condTarget = Node.newTarget ();
+ if (loopType == LOOP_FOR && cond.Type == Token.EMPTY) {
+ cond = new Node (Token.TRUE);
+ }
+ Node.Jump IFEQ = new Node.Jump (Token.IFEQ, cond);
+ IFEQ.target = bodyTarget;
+ Node breakTarget = Node.newTarget ();
+
+ loop.addChildToBack (bodyTarget);
+ loop.addChildrenToBack (body);
+ if (loopType == LOOP_WHILE || loopType == LOOP_FOR) {
+ // propagate lineno to condition
+ loop.addChildrenToBack (new Node (Token.EMPTY, loop.Lineno));
+ }
+ loop.addChildToBack (condTarget);
+ loop.addChildToBack (IFEQ);
+ loop.addChildToBack (breakTarget);
+
+ loop.target = breakTarget;
+ Node continueTarget = condTarget;
+
+ if (loopType == LOOP_WHILE || loopType == LOOP_FOR) {
+ // Just add a GOTO to the condition in the do..while
+ loop.addChildToFront (makeJump (Token.GOTO, condTarget));
+
+ if (loopType == LOOP_FOR) {
+ if (init.Type != Token.EMPTY) {
+ if (init.Type != Token.VAR) {
+ init = new Node (Token.EXPR_VOID, init);
+ }
+ loop.addChildToFront (init);
+ }
+ Node incrTarget = Node.newTarget ();
+ loop.addChildAfter (incrTarget, body);
+ if (incr.Type != Token.EMPTY) {
+ incr = new Node (Token.EXPR_VOID, incr);
+ loop.addChildAfter (incr, incrTarget);
+ }
+ continueTarget = incrTarget;
+ }
+ }
+
+ loop.Continue = continueTarget;
+
+ return loop;
+ }
+
+ /// For .. In
+ ///
+ ///
+ internal Node CreateForIn (Node loop, Node lhs, Node obj, Node body, bool isForEach)
+ {
+ int type = lhs.Type;
+
+ Node lvalue;
+ if (type == Token.VAR) {
+ /*
+ * check that there was only one variable given.
+ * we can't do this in the parser, because then the
+ * parser would have to know something about the
+ * 'init' node of the for-in loop.
+ */
+ Node lastChild = lhs.LastChild;
+ if (lhs.FirstChild != lastChild) {
+ parser.ReportError ("msg.mult.index");
+ }
+ lvalue = Node.newString (Token.NAME, lastChild.String);
+ }
+ else {
+ lvalue = makeReference (lhs);
+ if (lvalue == null) {
+ parser.ReportError ("msg.bad.for.in.lhs");
+ return obj;
+ }
+ }
+
+ Node localBlock = new Node (Token.LOCAL_BLOCK);
+
+ int initType = (isForEach) ? Token.ENUM_INIT_VALUES : Token.ENUM_INIT_KEYS;
+ Node init = new Node (initType, obj);
+ init.putProp (Node.LOCAL_BLOCK_PROP, localBlock);
+ Node cond = new Node (Token.ENUM_NEXT);
+ cond.putProp (Node.LOCAL_BLOCK_PROP, localBlock);
+ Node id = new Node (Token.ENUM_ID);
+ id.putProp (Node.LOCAL_BLOCK_PROP, localBlock);
+
+ Node newBody = new Node (Token.BLOCK);
+ Node assign = simpleAssignment (lvalue, id);
+ newBody.addChildToBack (new Node (Token.EXPR_VOID, assign));
+ newBody.addChildToBack (body);
+
+ loop = CreateWhile (loop, cond, newBody);
+ loop.addChildToFront (init);
+ if (type == Token.VAR)
+ loop.addChildToFront (lhs);
+ localBlock.addChildToBack (loop);
+
+ return localBlock;
+ }
+
+ /// Try/Catch/Finally
+ ///
+ /// The IRFactory tries to express as much as possible in the tree;
+ /// the responsibilities remaining for Codegen are to add the Java
+ /// handlers: (Either (but not both) of TARGET and FINALLY might not
+ /// be defined)
+ /// - a catch handler for javascript exceptions that unwraps the
+ /// exception onto the stack and GOTOes to the catch target
+ /// - a finally handler
+ /// ... and a goto to GOTO around these handlers.
+ ///
+ internal Node CreateTryCatchFinally (Node tryBlock, Node catchBlocks, Node finallyBlock, int lineno)
+ {
+ bool hasFinally = (finallyBlock != null) && (finallyBlock.Type != Token.BLOCK || finallyBlock.hasChildren ());
+
+ // short circuit
+ if (tryBlock.Type == Token.BLOCK && !tryBlock.hasChildren () && !hasFinally) {
+ return tryBlock;
+ }
+
+ bool hasCatch = catchBlocks.hasChildren ();
+
+ // short circuit
+ if (!hasFinally && !hasCatch) {
+ // bc finally might be an empty block...
+ return tryBlock;
+ }
+
+
+ Node handlerBlock = new Node (Token.LOCAL_BLOCK);
+ Node.Jump pn = new Node.Jump (Token.TRY, tryBlock, lineno);
+ pn.putProp (Node.LOCAL_BLOCK_PROP, handlerBlock);
+
+ if (hasCatch) {
+ // jump around catch code
+ Node endCatch = Node.newTarget ();
+ pn.addChildToBack (makeJump (Token.GOTO, endCatch));
+
+ // make a TARGET for the catch that the tcf node knows about
+ Node catchTarget = Node.newTarget ();
+ pn.target = catchTarget;
+ // mark it
+ pn.addChildToBack (catchTarget);
+
+ //
+ // Given
+ //
+ // try {
+ // tryBlock;
+ // } catch (e if condition1) {
+ // something1;
+ // ...
+ //
+ // } catch (e if conditionN) {
+ // somethingN;
+ // } catch (e) {
+ // somethingDefault;
+ // }
+ //
+ // rewrite as
+ //
+ // try {
+ // tryBlock;
+ // goto after_catch:
+ // } catch (x) {
+ // with (newCatchScope(e, x)) {
+ // if (condition1) {
+ // something1;
+ // goto after_catch;
+ // }
+ // }
+ // ...
+ // with (newCatchScope(e, x)) {
+ // if (conditionN) {
+ // somethingN;
+ // goto after_catch;
+ // }
+ // }
+ // with (newCatchScope(e, x)) {
+ // somethingDefault;
+ // goto after_catch;
+ // }
+ // }
+ // after_catch:
+ //
+ // If there is no default catch, then the last with block
+ // arround "somethingDefault;" is replaced by "rethrow;"
+
+ // It is assumed that catch handler generation will store
+ // exeception object in handlerBlock register
+
+ // Block with local for exception scope objects
+ Node catchScopeBlock = new Node (Token.LOCAL_BLOCK);
+
+ // expects catchblocks children to be (cond block) pairs.
+ Node cb = catchBlocks.FirstChild;
+ bool hasDefault = false;
+ int scopeIndex = 0;
+ while (cb != null) {
+ int catchLineNo = cb.Lineno;
+
+ Node name = cb.FirstChild;
+ Node cond = name.Next;
+ Node catchStatement = cond.Next;
+ cb.removeChild (name);
+ cb.removeChild (cond);
+ cb.removeChild (catchStatement);
+
+ // Add goto to the catch statement to jump out of catch
+ // but prefix it with LEAVEWITH since try..catch produces
+ // "with"code in order to limit the scope of the exception
+ // object.
+ catchStatement.addChildToBack (new Node (Token.LEAVEWITH));
+ catchStatement.addChildToBack (makeJump (Token.GOTO, endCatch));
+
+ // Create condition "if" when present
+ Node condStmt;
+ if (cond.Type == Token.EMPTY) {
+ condStmt = catchStatement;
+ hasDefault = true;
+ }
+ else {
+ condStmt = CreateIf (cond, catchStatement, null, catchLineNo);
+ }
+
+ // Generate code to Create the scope object and store
+ // it in catchScopeBlock register
+ Node catchScope = new Node (Token.CATCH_SCOPE, name, CreateUseLocal (handlerBlock));
+ catchScope.putProp (Node.LOCAL_BLOCK_PROP, catchScopeBlock);
+ catchScope.putIntProp (Node.CATCH_SCOPE_PROP, scopeIndex);
+ catchScopeBlock.addChildToBack (catchScope);
+
+ // Add with statement based on catch scope object
+ catchScopeBlock.addChildToBack (CreateWith (CreateUseLocal (catchScopeBlock), condStmt, catchLineNo));
+
+ // move to next cb
+ cb = cb.Next;
+ ++scopeIndex;
+ }
+ pn.addChildToBack (catchScopeBlock);
+ if (!hasDefault) {
+ // Generate code to rethrow if no catch clause was executed
+ Node rethrow = new Node (Token.RETHROW);
+ rethrow.putProp (Node.LOCAL_BLOCK_PROP, handlerBlock);
+ pn.addChildToBack (rethrow);
+ }
+
+ pn.addChildToBack (endCatch);
+ }
+
+ if (hasFinally) {
+ Node finallyTarget = Node.newTarget ();
+ pn.Finally = finallyTarget;
+
+ // add jsr finally to the try block
+ pn.addChildToBack (makeJump (Token.JSR, finallyTarget));
+
+ // jump around finally code
+ Node finallyEnd = Node.newTarget ();
+ pn.addChildToBack (makeJump (Token.GOTO, finallyEnd));
+
+ pn.addChildToBack (finallyTarget);
+ Node fBlock = new Node (Token.FINALLY, finallyBlock);
+ fBlock.putProp (Node.LOCAL_BLOCK_PROP, handlerBlock);
+ pn.addChildToBack (fBlock);
+
+ pn.addChildToBack (finallyEnd);
+ }
+ handlerBlock.addChildToBack (pn);
+ return handlerBlock;
+ }
+
+ /// Throw, Return, Label, Break and Continue are defined in ASTFactory.
+
+ /// With
+ internal Node CreateWith (Node obj, Node body, int lineno)
+ {
+ setRequiresActivation ();
+ Node result = new Node (Token.BLOCK, lineno);
+ result.addChildToBack (new Node (Token.ENTERWITH, obj));
+ Node bodyNode = new Node (Token.WITH, body, lineno);
+ result.addChildrenToBack (bodyNode);
+ result.addChildToBack (new Node (Token.LEAVEWITH));
+ return result;
+ }
+
+ /// DOTQUERY
+ public Node CreateDotQuery (Node obj, Node body, int lineno)
+ {
+ setRequiresActivation ();
+ Node result = new Node (Token.DOTQUERY, obj, body, lineno);
+ return result;
+ }
+
+ internal Node CreateArrayLiteral (ObjArray elems, int skipCount)
+ {
+ int length = elems.size ();
+ int [] skipIndexes = null;
+ if (skipCount != 0) {
+ skipIndexes = new int [skipCount];
+ }
+ Node array = new Node (Token.ARRAYLIT);
+ for (int i = 0, j = 0; i != length; ++i) {
+ Node elem = (Node)elems.Get (i);
+ if (elem != null) {
+ array.addChildToBack (elem);
+ }
+ else {
+ skipIndexes [j] = i;
+ ++j;
+ }
+ }
+ if (skipCount != 0) {
+ array.putProp (Node.SKIP_INDEXES_PROP, skipIndexes);
+ }
+ return array;
+ }
+
+ /// Object Literals
+ ///
CreateObjectLiteral rewrites its argument as object
+ /// creation plus object property entries, so later compiler
+ /// stages don't need to know about object literals.
+ ///
+ internal Node CreateObjectLiteral (ObjArray elems)
+ {
+ int size = elems.size () / 2;
+ Node obj = new Node (Token.OBJECTLIT);
+ object [] properties;
+ if (size == 0) {
+ properties = ScriptRuntime.EmptyArgs;
+ }
+ else {
+ properties = new object [size];
+ for (int i = 0; i != size; ++i) {
+ properties [i] = elems.Get (2 * i);
+ Node value = (Node)elems.Get (2 * i + 1);
+ obj.addChildToBack (value);
+ }
+ }
+ obj.putProp (Node.OBJECT_IDS_PROP, properties);
+ return obj;
+ }
+
+ /// Regular expressions
+ internal Node CreateRegExp (int regexpIndex)
+ {
+ Node n = new Node (Token.REGEXP);
+ n.putIntProp (Node.REGEXP_PROP, regexpIndex);
+ return n;
+ }
+
+ /// If statement
+ internal Node CreateIf (Node cond, Node ifTrue, Node ifFalse, int lineno)
+ {
+ int condStatus = isAlwaysDefinedBoolean (cond);
+ if (condStatus == ALWAYS_TRUE_BOOLEAN) {
+ return ifTrue;
+ }
+ else if (condStatus == ALWAYS_FALSE_BOOLEAN) {
+ if (ifFalse != null) {
+ return ifFalse;
+ }
+ return new Node (Token.BLOCK, lineno);
+ }
+
+ Node result = new Node (Token.BLOCK, lineno);
+ Node ifNotTarget = Node.newTarget ();
+ Node.Jump IFNE = new Node.Jump (Token.IFNE, cond);
+ IFNE.target = ifNotTarget;
+
+ result.addChildToBack (IFNE);
+ result.addChildrenToBack (ifTrue);
+
+ if (ifFalse != null) {
+ Node endTarget = Node.newTarget ();
+ result.addChildToBack (makeJump (Token.GOTO, endTarget));
+ result.addChildToBack (ifNotTarget);
+ result.addChildrenToBack (ifFalse);
+ result.addChildToBack (endTarget);
+ }
+ else {
+ result.addChildToBack (ifNotTarget);
+ }
+
+ return result;
+ }
+
+ internal Node CreateCondExpr (Node cond, Node ifTrue, Node ifFalse)
+ {
+ int condStatus = isAlwaysDefinedBoolean (cond);
+ if (condStatus == ALWAYS_TRUE_BOOLEAN) {
+ return ifTrue;
+ }
+ else if (condStatus == ALWAYS_FALSE_BOOLEAN) {
+ return ifFalse;
+ }
+ return new Node (Token.HOOK, cond, ifTrue, ifFalse);
+ }
+
+ /// Unary
+ internal Node CreateUnary (int nodeType, Node child)
+ {
+ int childType = child.Type;
+ switch (nodeType) {
+
+ case Token.DELPROP: {
+ Node n;
+ if (childType == Token.NAME) {
+ // Transform Delete(Name "a")
+ // to Delete(Bind("a"), String("a"))
+ child.Type = Token.BINDNAME;
+ Node left = child;
+ Node right = Node.newString (child.String);
+ n = new Node (nodeType, left, right);
+ }
+ else if (childType == Token.GETPROP || childType == Token.GETELEM) {
+ Node left = child.FirstChild;
+ Node right = child.LastChild;
+ child.removeChild (left);
+ child.removeChild (right);
+ n = new Node (nodeType, left, right);
+ }
+ else if (childType == Token.GET_REF) {
+ Node rf = child.FirstChild;
+ child.removeChild (rf);
+ n = new Node (Token.DEL_REF, rf);
+ }
+ else {
+ n = new Node (Token.TRUE);
+ }
+ return n;
+ }
+
+ case Token.TYPEOF:
+ if (childType == Token.NAME) {
+ child.Type = Token.TYPEOFNAME;
+ return child;
+ }
+ break;
+
+ case Token.BITNOT:
+ if (childType == Token.NUMBER) {
+ int value = ScriptConvert.ToInt32 (child.Double);
+ child.Double = ~value;
+ return child;
+ }
+ break;
+
+ case Token.NEG:
+ if (childType == Token.NUMBER) {
+ child.Double = -child.Double;
+ return child;
+ }
+ break;
+
+ case Token.NOT: {
+ int status = isAlwaysDefinedBoolean (child);
+ if (status != 0) {
+ int type;
+ if (status == ALWAYS_TRUE_BOOLEAN) {
+ type = Token.FALSE;
+ }
+ else {
+ type = Token.TRUE;
+ }
+ if (childType == Token.TRUE || childType == Token.FALSE) {
+ child.Type = type;
+ return child;
+ }
+ return new Node (type);
+ }
+ break;
+ }
+ }
+ return new Node (nodeType, child);
+ }
+
+ internal Node CreateCallOrNew (int nodeType, Node child)
+ {
+ int type = Node.NON_SPECIALCALL;
+ if (child.Type == Token.NAME) {
+ string name = child.String;
+ if (name.Equals ("eval")) {
+ type = Node.SPECIALCALL_EVAL;
+ }
+ else if (name.Equals ("With")) {
+ type = Node.SPECIALCALL_WITH;
+ }
+ }
+ else if (child.Type == Token.GETPROP) {
+ string name = child.LastChild.String;
+ if (name.Equals ("eval")) {
+ type = Node.SPECIALCALL_EVAL;
+ }
+ }
+ Node node = new Node (nodeType, child);
+ if (type != Node.NON_SPECIALCALL) {
+ // Calls to these functions require activation objects.
+ setRequiresActivation ();
+ node.putIntProp (Node.SPECIALCALL_PROP, type);
+ }
+ return node;
+ }
+
+ internal Node CreateIncDec (int nodeType, bool post, Node child)
+ {
+ child = makeReference (child);
+ if (child == null) {
+ string msg;
+ if (nodeType == Token.DEC) {
+ msg = "msg.bad.decr";
+ }
+ else {
+ msg = "msg.bad.incr";
+ }
+ parser.ReportError (msg);
+ return null;
+ }
+
+ int childType = child.Type;
+
+ switch (childType) {
+
+ case Token.NAME:
+ case Token.GETPROP:
+ case Token.GETELEM:
+ case Token.GET_REF: {
+ Node n = new Node (nodeType, child);
+ int incrDecrMask = 0;
+ if (nodeType == Token.DEC) {
+ incrDecrMask |= Node.DECR_FLAG;
+ }
+ if (post) {
+ incrDecrMask |= Node.POST_FLAG;
+ }
+ n.putIntProp (Node.INCRDECR_PROP, incrDecrMask);
+ return n;
+ }
+ }
+ throw Context.CodeBug ();
+ }
+
+ internal Node CreatePropertyGet (Node target, string ns, string name, int memberTypeFlags)
+ {
+ if (ns == null && memberTypeFlags == 0) {
+ if (target == null) {
+ return CreateName (name);
+ }
+ checkActivationName (name, Token.GETPROP);
+ if (ScriptRuntime.isSpecialProperty (name)) {
+ Node rf = new Node (Token.REF_SPECIAL, target);
+ rf.putProp (Node.NAME_PROP, name);
+ return new Node (Token.GET_REF, rf);
+ }
+ return new Node (Token.GETPROP, target, CreateString (name));
+ }
+ Node elem = CreateString (name);
+ memberTypeFlags |= Node.PROPERTY_FLAG;
+ return CreateMemberRefGet (target, ns, elem, memberTypeFlags);
+ }
+
+ internal Node CreateElementGet (Node target, string ns, Node elem, int memberTypeFlags)
+ {
+ // OPT: could optimize to CreatePropertyGet
+ // iff elem is string that can not be number
+ if (ns == null && memberTypeFlags == 0) {
+ // stand-alone [aaa] as primary expression is array literal
+ // declaration and should not come here!
+ if (target == null)
+ throw Context.CodeBug ();
+ return new Node (Token.GETELEM, target, elem);
+ }
+ return CreateMemberRefGet (target, ns, elem, memberTypeFlags);
+ }
+
+ private Node CreateMemberRefGet (Node target, string ns, Node elem, int memberTypeFlags)
+ {
+ Node nsNode = null;
+ if (ns != null) {
+ // See 11.1.2 in ECMA 357
+ if (ns.Equals ("*")) {
+ nsNode = new Node (Token.NULL);
+ }
+ else {
+ nsNode = CreateName (ns);
+ }
+ }
+ Node rf;
+ if (target == null) {
+ if (ns == null) {
+ rf = new Node (Token.REF_NAME, elem);
+ }
+ else {
+ rf = new Node (Token.REF_NS_NAME, nsNode, elem);
+ }
+ }
+ else {
+ if (ns == null) {
+ rf = new Node (Token.REF_MEMBER, target, elem);
+ }
+ else {
+ rf = new Node (Token.REF_NS_MEMBER, target, nsNode, elem);
+ }
+ }
+ if (memberTypeFlags != 0) {
+ rf.putIntProp (Node.MEMBER_TYPE_PROP, memberTypeFlags);
+ }
+ return new Node (Token.GET_REF, rf);
+ }
+
+ /// Binary
+ internal Node CreateBinary (int nodeType, Node left, Node right)
+ {
+ switch (nodeType) {
+
+
+ case Token.ADD:
+ // numerical addition and string concatenation
+ if (left.Type == Token.STRING) {
+ string s2;
+ if (right.Type == Token.STRING) {
+ s2 = right.String;
+ }
+ else if (right.Type == Token.NUMBER) {
+ s2 = ScriptConvert.ToString (right.Double, 10);
+ }
+ else {
+ break;
+ }
+ string s1 = left.String;
+ left.String = string.Concat (s1, s2);
+ return left;
+ }
+ else if (left.Type == Token.NUMBER) {
+ if (right.Type == Token.NUMBER) {
+ left.Double = left.Double + right.Double;
+ return left;
+ }
+ else if (right.Type == Token.STRING) {
+ string s1, s2;
+ s1 = ScriptConvert.ToString (left.Double, 10);
+ s2 = right.String;
+ right.String = string.Concat (s1, s2);
+ return right;
+ }
+ }
+ // can't do anything if we don't know both types - since
+ // 0 + object is supposed to call toString on the object and do
+ // string concantenation rather than addition
+ break;
+
+
+ case Token.SUB:
+ // numerical subtraction
+ if (left.Type == Token.NUMBER) {
+ double ld = left.Double;
+ if (right.Type == Token.NUMBER) {
+ //both numbers
+ left.Double = ld - right.Double;
+ return left;
+ }
+ else if (ld == 0.0) {
+ // first 0: 0-x -> -x
+ return new Node (Token.NEG, right);
+ }
+ }
+ else if (right.Type == Token.NUMBER) {
+ if (right.Double == 0.0) {
+ //second 0: x - 0 -> +x
+ // can not make simply x because x - 0 must be number
+ return new Node (Token.POS, left);
+ }
+ }
+ break;
+
+
+ case Token.MUL:
+ // numerical multiplication
+ if (left.Type == Token.NUMBER) {
+ double ld = left.Double;
+ if (right.Type == Token.NUMBER) {
+ //both numbers
+ left.Double = ld * right.Double;
+ return left;
+ }
+ else if (ld == 1.0) {
+ // first 1: 1 * x -> +x
+ return new Node (Token.POS, right);
+ }
+ }
+ else if (right.Type == Token.NUMBER) {
+ if (right.Double == 1.0) {
+ //second 1: x * 1 -> +x
+ // can not make simply x because x - 0 must be number
+ return new Node (Token.POS, left);
+ }
+ }
+ // can't do x*0: Infinity * 0 gives NaN, not 0
+ break;
+
+
+ case Token.DIV:
+ // number division
+ if (right.Type == Token.NUMBER) {
+ double rd = right.Double;
+ if (left.Type == Token.NUMBER) {
+ // both constants -- just divide, trust Java to handle x/0
+ left.Double = left.Double / rd;
+ return left;
+ }
+ else if (rd == 1.0) {
+ // second 1: x/1 -> +x
+ // not simply x to force number convertion
+ return new Node (Token.POS, left);
+ }
+ }
+ break;
+
+
+ case Token.AND: {
+ int leftStatus = isAlwaysDefinedBoolean (left);
+ if (leftStatus == ALWAYS_FALSE_BOOLEAN) {
+ // if the first one is false, replace with FALSE
+ return new Node (Token.FALSE);
+ }
+ else if (leftStatus == ALWAYS_TRUE_BOOLEAN) {
+ // if first is true, set to second
+ return right;
+ }
+ int rightStatus = isAlwaysDefinedBoolean (right);
+ if (rightStatus == ALWAYS_FALSE_BOOLEAN) {
+ // if the second one is false, replace with FALSE
+ if (!hasSideEffects (left)) {
+ return new Node (Token.FALSE);
+ }
+ }
+ else if (rightStatus == ALWAYS_TRUE_BOOLEAN) {
+ // if second is true, set to first
+ return left;
+ }
+ break;
+ }
+
+
+ case Token.OR: {
+ int leftStatus = isAlwaysDefinedBoolean (left);
+ if (leftStatus == ALWAYS_TRUE_BOOLEAN) {
+ // if the first one is true, replace with TRUE
+ return new Node (Token.TRUE);
+ }
+ else if (leftStatus == ALWAYS_FALSE_BOOLEAN) {
+ // if first is false, set to second
+ return right;
+ }
+ int rightStatus = isAlwaysDefinedBoolean (right);
+ if (rightStatus == ALWAYS_TRUE_BOOLEAN) {
+ // if the second one is true, replace with TRUE
+ if (!hasSideEffects (left)) {
+ return new Node (Token.TRUE);
+ }
+ }
+ else if (rightStatus == ALWAYS_FALSE_BOOLEAN) {
+ // if second is false, set to first
+ return left;
+ }
+ break;
+ }
+ }
+
+ return new Node (nodeType, left, right);
+ }
+
+ private Node simpleAssignment (Node left, Node right)
+ {
+ int nodeType = left.Type;
+ switch (nodeType) {
+
+ case Token.NAME:
+ left.Type = Token.BINDNAME;
+ return new Node (Token.SETNAME, left, right);
+
+
+ case Token.GETPROP:
+ case Token.GETELEM: {
+ Node obj = left.FirstChild;
+ Node id = left.LastChild;
+ int type;
+ if (nodeType == Token.GETPROP) {
+ type = Token.SETPROP;
+ }
+ else {
+ type = Token.SETELEM;
+ }
+ return new Node (type, obj, id, right);
+ }
+
+ case Token.GET_REF: {
+ Node rf = left.FirstChild;
+ checkMutableReference (rf);
+ return new Node (Token.SET_REF, rf, right);
+ }
+ }
+
+ throw Context.CodeBug ();
+ }
+
+ private void checkMutableReference (Node n)
+ {
+ int memberTypeFlags = n.getIntProp (Node.MEMBER_TYPE_PROP, 0);
+ if ((memberTypeFlags & Node.DESCENDANTS_FLAG) != 0) {
+ parser.ReportError ("msg.bad.assign.left");
+ }
+ }
+
+ internal Node CreateAssignment (int assignType, Node left, Node right)
+ {
+ left = makeReference (left);
+ if (left == null) {
+ parser.ReportError ("msg.bad.assign.left");
+ return right;
+ }
+
+ int assignOp;
+ switch (assignType) {
+
+ case Token.ASSIGN:
+ return simpleAssignment (left, right);
+
+ case Token.ASSIGN_BITOR:
+ assignOp = Token.BITOR;
+ break;
+
+ case Token.ASSIGN_BITXOR:
+ assignOp = Token.BITXOR;
+ break;
+
+ case Token.ASSIGN_BITAND:
+ assignOp = Token.BITAND;
+ break;
+
+ case Token.ASSIGN_LSH:
+ assignOp = Token.LSH;
+ break;
+
+ case Token.ASSIGN_RSH:
+ assignOp = Token.RSH;
+ break;
+
+ case Token.ASSIGN_URSH:
+ assignOp = Token.URSH;
+ break;
+
+ case Token.ASSIGN_ADD:
+ assignOp = Token.ADD;
+ break;
+
+ case Token.ASSIGN_SUB:
+ assignOp = Token.SUB;
+ break;
+
+ case Token.ASSIGN_MUL:
+ assignOp = Token.MUL;
+ break;
+
+ case Token.ASSIGN_DIV:
+ assignOp = Token.DIV;
+ break;
+
+ case Token.ASSIGN_MOD:
+ assignOp = Token.MOD;
+ break;
+
+ default:
+ throw Context.CodeBug ();
+
+ }
+
+ int nodeType = left.Type;
+ switch (nodeType) {
+
+ case Token.NAME: {
+ string s = left.String;
+
+ Node opLeft = Node.newString (Token.NAME, s);
+ Node op = new Node (assignOp, opLeft, right);
+ Node lvalueLeft = Node.newString (Token.BINDNAME, s);
+ return new Node (Token.SETNAME, lvalueLeft, op);
+ }
+
+ case Token.GETPROP:
+ case Token.GETELEM: {
+ Node obj = left.FirstChild;
+ Node id = left.LastChild;
+
+ int type = nodeType == Token.GETPROP ? Token.SETPROP_OP : Token.SETELEM_OP;
+
+ Node opLeft = new Node (Token.USE_STACK);
+ Node op = new Node (assignOp, opLeft, right);
+ return new Node (type, obj, id, op);
+ }
+
+ case Token.GET_REF: {
+ Node rf = left.FirstChild;
+ checkMutableReference (rf);
+ Node opLeft = new Node (Token.USE_STACK);
+ Node op = new Node (assignOp, opLeft, right);
+ return new Node (Token.SET_REF_OP, rf, op);
+ }
+ }
+
+ throw Context.CodeBug ();
+ }
+
+ internal Node CreateUseLocal (Node localBlock)
+ {
+ if (Token.LOCAL_BLOCK != localBlock.Type)
+ throw Context.CodeBug ();
+ Node result = new Node (Token.LOCAL_LOAD);
+ result.putProp (Node.LOCAL_BLOCK_PROP, localBlock);
+ return result;
+ }
+
+ private Node.Jump makeJump (int type, Node target)
+ {
+ Node.Jump n = new Node.Jump (type);
+ n.target = target;
+ return n;
+ }
+
+ private Node makeReference (Node node)
+ {
+ int type = node.Type;
+ switch (type) {
+
+ case Token.NAME:
+ case Token.GETPROP:
+ case Token.GETELEM:
+ case Token.GET_REF:
+ return node;
+
+ case Token.CALL:
+ node.Type = Token.REF_CALL;
+ return new Node (Token.GET_REF, node);
+ }
+ // Signal caller to report error
+ return null;
+ }
+
+ // Check if Node always mean true or false in boolean context
+ private static int isAlwaysDefinedBoolean (Node node)
+ {
+ switch (node.Type) {
+
+ case Token.FALSE:
+ case Token.NULL:
+ return ALWAYS_FALSE_BOOLEAN;
+
+ case Token.TRUE:
+ return ALWAYS_TRUE_BOOLEAN;
+
+ case Token.NUMBER: {
+ double num = node.Double;
+ if (!double.IsNaN (num) && num != 0.0) {
+ return ALWAYS_TRUE_BOOLEAN;
+ }
+ else {
+ return ALWAYS_FALSE_BOOLEAN;
+ }
+ }
+ }
+ return 0;
+ }
+
+ private static bool hasSideEffects (Node exprTree)
+ {
+ switch (exprTree.Type) {
+
+ case Token.INC:
+ case Token.DEC:
+ case Token.SETPROP:
+ case Token.SETELEM:
+ case Token.SETNAME:
+ case Token.CALL:
+ case Token.NEW:
+ return true;
+
+ default:
+ Node child = exprTree.FirstChild;
+ while (child != null) {
+ if (hasSideEffects (child))
+ return true;
+ child = child.Next;
+ }
+ break;
+
+ }
+ return false;
+ }
+
+ private void checkActivationName (string name, int token)
+ {
+ if (parser.insideFunction ()) {
+ bool activation = false;
+ if ("arguments".Equals (name) || (parser.compilerEnv.activationNames != null && parser.compilerEnv.activationNames.ContainsKey (name))) {
+ activation = true;
+ }
+ else if ("length".Equals (name)) {
+ if (token == Token.GETPROP && parser.compilerEnv.LanguageVersion == Context.Versions.JS1_2) {
+ // Use of "length" in 1.2 requires an activation object.
+ activation = true;
+ }
+ }
+ if (activation) {
+ setRequiresActivation ();
+ }
+ }
+ }
+
+ private void setRequiresActivation ()
+ {
+ if (parser.insideFunction ()) {
+ ((FunctionNode)parser.currentScriptOrFn).itsNeedsActivation = true;
+ }
+ }
+
+ private Parser parser;
+
+ private const int LOOP_DO_WHILE = 0;
+ private const int LOOP_WHILE = 1;
+ private const int LOOP_FOR = 2;
+
+ private const int ALWAYS_TRUE_BOOLEAN = 1;
+ private const int ALWAYS_FALSE_BOOLEAN = -1;
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/NodeTransformer.cs b/src/EcmaScript.NET/NodeTransformer.cs
similarity index 97%
rename from Code/EcmaScript.NET/NodeTransformer.cs
rename to src/EcmaScript.NET/NodeTransformer.cs
index ef4d0b6..4ec7562 100644
--- a/Code/EcmaScript.NET/NodeTransformer.cs
+++ b/src/EcmaScript.NET/NodeTransformer.cs
@@ -1,345 +1,345 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-using EcmaScript.NET.Collections;
-
-namespace EcmaScript.NET
-{
-
- /// This class transforms a tree to a lower-level representation for codegen.
- ///
- ///
- public class NodeTransformer
- {
-
- public NodeTransformer ()
- {
- }
-
- public void transform (ScriptOrFnNode tree)
- {
- transformCompilationUnit (tree);
- for (int i = 0; i != tree.FunctionCount; ++i) {
- FunctionNode fn = tree.getFunctionNode (i);
- transform (fn);
- }
- }
-
- private void transformCompilationUnit (ScriptOrFnNode tree)
- {
- loops = new ObjArray ();
- loopEnds = new ObjArray ();
- // to save against upchecks if no finally blocks are used.
- hasFinally = false;
-
- try {
- transformCompilationUnit_r (tree, tree);
- } catch (Helpers.StackOverflowVerifierException) {
- throw Context.ReportRuntimeError (
- ScriptRuntime.GetMessage ("mag.too.deep.parser.recursion"));
- }
- }
-
- private void transformCompilationUnit_r (ScriptOrFnNode tree, Node parent)
- {
- Node node = null;
-
- using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier (1024)) {
- for (; ; ) {
- Node previous = null;
- if (node == null) {
- node = parent.FirstChild;
- }
- else {
- previous = node;
- node = node.Next;
- }
- if (node == null) {
- break;
- }
-
- int type = node.Type;
-
- switch (type) {
-
-
- case Token.LABEL:
- case Token.SWITCH:
- case Token.LOOP:
- loops.push (node);
- loopEnds.push (((Node.Jump)node).target);
- break;
-
-
- case Token.WITH: {
- loops.push (node);
- Node leave = node.Next;
- if (leave.Type != Token.LEAVEWITH) {
- Context.CodeBug ();
- }
- loopEnds.push (leave);
- break;
- }
-
-
- case Token.TRY: {
- Node.Jump jump = (Node.Jump)node;
- Node finallytarget = jump.Finally;
- if (finallytarget != null) {
- hasFinally = true;
- loops.push (node);
- loopEnds.push (finallytarget);
- }
- break;
- }
-
-
- case Token.TARGET:
- case Token.LEAVEWITH:
- if (!loopEnds.Empty && loopEnds.peek () == node) {
- loopEnds.pop ();
- loops.pop ();
- }
- break;
-
-
- case Token.RETURN: {
- /* If we didn't support try/finally, it wouldn't be
- * necessary to put LEAVEWITH nodes here... but as
- * we do need a series of JSR FINALLY nodes before
- * each RETURN, we need to ensure that each finally
- * block gets the correct scope... which could mean
- * that some LEAVEWITH nodes are necessary.
- */
- if (!hasFinally)
- break; // skip the whole mess.
- Node unwindBlock = null;
- for (int i = loops.size () - 1; i >= 0; i--) {
- Node n = (Node)loops.Get (i);
- int elemtype = n.Type;
- if (elemtype == Token.TRY || elemtype == Token.WITH) {
- Node unwind;
- if (elemtype == Token.TRY) {
- Node.Jump jsrnode = new Node.Jump (Token.JSR);
- Node jsrtarget = ((Node.Jump)n).Finally;
- jsrnode.target = jsrtarget;
- unwind = jsrnode;
- }
- else {
- unwind = new Node (Token.LEAVEWITH);
- }
- if (unwindBlock == null) {
- unwindBlock = new Node (Token.BLOCK, node.Lineno);
- }
- unwindBlock.addChildToBack (unwind);
- }
- }
- if (unwindBlock != null) {
- Node returnNode = node;
- Node returnExpr = returnNode.FirstChild;
- node = replaceCurrent (parent, previous, node, unwindBlock);
- if (returnExpr == null) {
- unwindBlock.addChildToBack (returnNode);
- }
- else {
- Node store = new Node (Token.EXPR_RESULT, returnExpr);
- unwindBlock.addChildToFront (store);
- returnNode = new Node (Token.RETURN_RESULT);
- unwindBlock.addChildToBack (returnNode);
- // transform return expression
- transformCompilationUnit_r (tree, store);
- }
- // skip transformCompilationUnit_r to avoid infinite loop
-
- goto siblingLoop;
- }
- break;
- }
-
-
- case Token.BREAK:
- case Token.CONTINUE: {
- Node.Jump jump = (Node.Jump)node;
- Node.Jump jumpStatement = jump.JumpStatement;
- if (jumpStatement == null)
- Context.CodeBug ();
-
- for (int i = loops.size (); ; ) {
- if (i == 0) {
- // Parser/IRFactory ensure that break/continue
- // always has a jump statement associated with it
- // which should be found
- throw Context.CodeBug ();
- }
- --i;
- Node n = (Node)loops.Get (i);
- if (n == jumpStatement) {
- break;
- }
-
- int elemtype = n.Type;
- if (elemtype == Token.WITH) {
- Node leave = new Node (Token.LEAVEWITH);
- previous = addBeforeCurrent (parent, previous, node, leave);
- }
- else if (elemtype == Token.TRY) {
- Node.Jump tryNode = (Node.Jump)n;
- Node.Jump jsrFinally = new Node.Jump (Token.JSR);
- jsrFinally.target = tryNode.Finally;
- previous = addBeforeCurrent (parent, previous, node, jsrFinally);
- }
- }
-
- if (type == Token.BREAK) {
- jump.target = jumpStatement.target;
- }
- else {
- jump.target = jumpStatement.Continue;
- }
- jump.Type = Token.GOTO;
-
- break;
- }
-
-
- case Token.CALL:
- visitCall (node, tree);
- break;
-
-
- case Token.NEW:
- visitNew (node, tree);
- break;
-
-
- case Token.VAR: {
- Node result = new Node (Token.BLOCK);
- for (Node cursor = node.FirstChild; cursor != null; ) {
- // Move cursor to next before createAssignment get chance
- // to change n.next
- Node n = cursor;
- if (n.Type != Token.NAME)
- Context.CodeBug ();
- cursor = cursor.Next;
- if (!n.hasChildren ())
- continue;
- Node init = n.FirstChild;
- n.removeChild (init);
- n.Type = Token.BINDNAME;
- n = new Node (Token.SETNAME, n, init);
- Node pop = new Node (Token.EXPR_VOID, n, node.Lineno);
- result.addChildToBack (pop);
- }
- node = replaceCurrent (parent, previous, node, result);
- break;
- }
-
-
- case Token.NAME:
- case Token.SETNAME:
- case Token.DELPROP: {
- // Turn name to var for faster access if possible
- if (tree.Type != Token.FUNCTION || ((FunctionNode)tree).RequiresActivation) {
- break;
- }
- Node nameSource;
- if (type == Token.NAME) {
- nameSource = node;
- }
- else {
- nameSource = node.FirstChild;
- if (nameSource.Type != Token.BINDNAME) {
- if (type == Token.DELPROP) {
- break;
- }
- throw Context.CodeBug ();
- }
- }
- string name = nameSource.String;
- if (tree.hasParamOrVar (name)) {
- if (type == Token.NAME) {
- node.Type = Token.GETVAR;
- }
- else if (type == Token.SETNAME) {
- node.Type = Token.SETVAR;
- nameSource.Type = Token.STRING;
- }
- else if (type == Token.DELPROP) {
- // Local variables are by definition permanent
- Node n = new Node (Token.FALSE);
- node = replaceCurrent (parent, previous, node, n);
- }
- else {
- throw Context.CodeBug ();
- }
- }
- break;
- }
- }
-
- transformCompilationUnit_r (tree, node);
-
- siblingLoop:
- ;
- }
- }
- }
-
- protected internal virtual void visitNew (Node node, ScriptOrFnNode tree)
- {
- }
-
- protected internal virtual void visitCall (Node node, ScriptOrFnNode tree)
- {
- }
-
- private static Node addBeforeCurrent (Node parent, Node previous, Node current, Node toAdd)
- {
- if (previous == null) {
- if (!(current == parent.FirstChild))
- Context.CodeBug ();
- parent.addChildToFront (toAdd);
- }
- else {
- if (!(current == previous.Next))
- Context.CodeBug ();
- parent.addChildAfter (toAdd, previous);
- }
- return toAdd;
- }
-
- private static Node replaceCurrent (Node parent, Node previous, Node current, Node replacement)
- {
- if (previous == null) {
- if (!(current == parent.FirstChild))
- Context.CodeBug ();
- parent.replaceChild (current, replacement);
- }
- else if (previous.next == current) {
- // Check cachedPrev.next == current is necessary due to possible
- // tree mutations
- parent.replaceChildAfter (previous, replacement);
- }
- else {
- parent.replaceChild (current, replacement);
- }
- return replacement;
- }
-
- private ObjArray loops;
- private ObjArray loopEnds;
- private bool hasFinally;
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+using EcmaScript.NET.Collections;
+
+namespace EcmaScript.NET
+{
+
+ /// This class transforms a tree to a lower-level representation for codegen.
+ ///
+ ///
+ public class NodeTransformer
+ {
+
+ public NodeTransformer ()
+ {
+ }
+
+ public void transform (ScriptOrFnNode tree)
+ {
+ transformCompilationUnit (tree);
+ for (int i = 0; i != tree.FunctionCount; ++i) {
+ FunctionNode fn = tree.getFunctionNode (i);
+ transform (fn);
+ }
+ }
+
+ private void transformCompilationUnit (ScriptOrFnNode tree)
+ {
+ loops = new ObjArray ();
+ loopEnds = new ObjArray ();
+ // to save against upchecks if no finally blocks are used.
+ hasFinally = false;
+
+ try {
+ transformCompilationUnit_r (tree, tree);
+ } catch (Helpers.StackOverflowVerifierException) {
+ throw Context.ReportRuntimeError (
+ ScriptRuntime.GetMessage ("mag.too.deep.parser.recursion"));
+ }
+ }
+
+ private void transformCompilationUnit_r (ScriptOrFnNode tree, Node parent)
+ {
+ Node node = null;
+
+ using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier (1024)) {
+ for (; ; ) {
+ Node previous = null;
+ if (node == null) {
+ node = parent.FirstChild;
+ }
+ else {
+ previous = node;
+ node = node.Next;
+ }
+ if (node == null) {
+ break;
+ }
+
+ int type = node.Type;
+
+ switch (type) {
+
+
+ case Token.LABEL:
+ case Token.SWITCH:
+ case Token.LOOP:
+ loops.push (node);
+ loopEnds.push (((Node.Jump)node).target);
+ break;
+
+
+ case Token.WITH: {
+ loops.push (node);
+ Node leave = node.Next;
+ if (leave.Type != Token.LEAVEWITH) {
+ Context.CodeBug ();
+ }
+ loopEnds.push (leave);
+ break;
+ }
+
+
+ case Token.TRY: {
+ Node.Jump jump = (Node.Jump)node;
+ Node finallytarget = jump.Finally;
+ if (finallytarget != null) {
+ hasFinally = true;
+ loops.push (node);
+ loopEnds.push (finallytarget);
+ }
+ break;
+ }
+
+
+ case Token.TARGET:
+ case Token.LEAVEWITH:
+ if (!loopEnds.Empty && loopEnds.peek () == node) {
+ loopEnds.pop ();
+ loops.pop ();
+ }
+ break;
+
+
+ case Token.RETURN: {
+ /* If we didn't support try/finally, it wouldn't be
+ * necessary to put LEAVEWITH nodes here... but as
+ * we do need a series of JSR FINALLY nodes before
+ * each RETURN, we need to ensure that each finally
+ * block gets the correct scope... which could mean
+ * that some LEAVEWITH nodes are necessary.
+ */
+ if (!hasFinally)
+ break; // skip the whole mess.
+ Node unwindBlock = null;
+ for (int i = loops.size () - 1; i >= 0; i--) {
+ Node n = (Node)loops.Get (i);
+ int elemtype = n.Type;
+ if (elemtype == Token.TRY || elemtype == Token.WITH) {
+ Node unwind;
+ if (elemtype == Token.TRY) {
+ Node.Jump jsrnode = new Node.Jump (Token.JSR);
+ Node jsrtarget = ((Node.Jump)n).Finally;
+ jsrnode.target = jsrtarget;
+ unwind = jsrnode;
+ }
+ else {
+ unwind = new Node (Token.LEAVEWITH);
+ }
+ if (unwindBlock == null) {
+ unwindBlock = new Node (Token.BLOCK, node.Lineno);
+ }
+ unwindBlock.addChildToBack (unwind);
+ }
+ }
+ if (unwindBlock != null) {
+ Node returnNode = node;
+ Node returnExpr = returnNode.FirstChild;
+ node = replaceCurrent (parent, previous, node, unwindBlock);
+ if (returnExpr == null) {
+ unwindBlock.addChildToBack (returnNode);
+ }
+ else {
+ Node store = new Node (Token.EXPR_RESULT, returnExpr);
+ unwindBlock.addChildToFront (store);
+ returnNode = new Node (Token.RETURN_RESULT);
+ unwindBlock.addChildToBack (returnNode);
+ // transform return expression
+ transformCompilationUnit_r (tree, store);
+ }
+ // skip transformCompilationUnit_r to avoid infinite loop
+
+ goto siblingLoop;
+ }
+ break;
+ }
+
+
+ case Token.BREAK:
+ case Token.CONTINUE: {
+ Node.Jump jump = (Node.Jump)node;
+ Node.Jump jumpStatement = jump.JumpStatement;
+ if (jumpStatement == null)
+ Context.CodeBug ();
+
+ for (int i = loops.size (); ; ) {
+ if (i == 0) {
+ // Parser/IRFactory ensure that break/continue
+ // always has a jump statement associated with it
+ // which should be found
+ throw Context.CodeBug ();
+ }
+ --i;
+ Node n = (Node)loops.Get (i);
+ if (n == jumpStatement) {
+ break;
+ }
+
+ int elemtype = n.Type;
+ if (elemtype == Token.WITH) {
+ Node leave = new Node (Token.LEAVEWITH);
+ previous = addBeforeCurrent (parent, previous, node, leave);
+ }
+ else if (elemtype == Token.TRY) {
+ Node.Jump tryNode = (Node.Jump)n;
+ Node.Jump jsrFinally = new Node.Jump (Token.JSR);
+ jsrFinally.target = tryNode.Finally;
+ previous = addBeforeCurrent (parent, previous, node, jsrFinally);
+ }
+ }
+
+ if (type == Token.BREAK) {
+ jump.target = jumpStatement.target;
+ }
+ else {
+ jump.target = jumpStatement.Continue;
+ }
+ jump.Type = Token.GOTO;
+
+ break;
+ }
+
+
+ case Token.CALL:
+ visitCall (node, tree);
+ break;
+
+
+ case Token.NEW:
+ visitNew (node, tree);
+ break;
+
+
+ case Token.VAR: {
+ Node result = new Node (Token.BLOCK);
+ for (Node cursor = node.FirstChild; cursor != null; ) {
+ // Move cursor to next before createAssignment get chance
+ // to change n.next
+ Node n = cursor;
+ if (n.Type != Token.NAME)
+ Context.CodeBug ();
+ cursor = cursor.Next;
+ if (!n.hasChildren ())
+ continue;
+ Node init = n.FirstChild;
+ n.removeChild (init);
+ n.Type = Token.BINDNAME;
+ n = new Node (Token.SETNAME, n, init);
+ Node pop = new Node (Token.EXPR_VOID, n, node.Lineno);
+ result.addChildToBack (pop);
+ }
+ node = replaceCurrent (parent, previous, node, result);
+ break;
+ }
+
+
+ case Token.NAME:
+ case Token.SETNAME:
+ case Token.DELPROP: {
+ // Turn name to var for faster access if possible
+ if (tree.Type != Token.FUNCTION || ((FunctionNode)tree).RequiresActivation) {
+ break;
+ }
+ Node nameSource;
+ if (type == Token.NAME) {
+ nameSource = node;
+ }
+ else {
+ nameSource = node.FirstChild;
+ if (nameSource.Type != Token.BINDNAME) {
+ if (type == Token.DELPROP) {
+ break;
+ }
+ throw Context.CodeBug ();
+ }
+ }
+ string name = nameSource.String;
+ if (tree.hasParamOrVar (name)) {
+ if (type == Token.NAME) {
+ node.Type = Token.GETVAR;
+ }
+ else if (type == Token.SETNAME) {
+ node.Type = Token.SETVAR;
+ nameSource.Type = Token.STRING;
+ }
+ else if (type == Token.DELPROP) {
+ // Local variables are by definition permanent
+ Node n = new Node (Token.FALSE);
+ node = replaceCurrent (parent, previous, node, n);
+ }
+ else {
+ throw Context.CodeBug ();
+ }
+ }
+ break;
+ }
+ }
+
+ transformCompilationUnit_r (tree, node);
+
+ siblingLoop:
+ ;
+ }
+ }
+ }
+
+ protected internal virtual void visitNew (Node node, ScriptOrFnNode tree)
+ {
+ }
+
+ protected internal virtual void visitCall (Node node, ScriptOrFnNode tree)
+ {
+ }
+
+ private static Node addBeforeCurrent (Node parent, Node previous, Node current, Node toAdd)
+ {
+ if (previous == null) {
+ if (!(current == parent.FirstChild))
+ Context.CodeBug ();
+ parent.addChildToFront (toAdd);
+ }
+ else {
+ if (!(current == previous.Next))
+ Context.CodeBug ();
+ parent.addChildAfter (toAdd, previous);
+ }
+ return toAdd;
+ }
+
+ private static Node replaceCurrent (Node parent, Node previous, Node current, Node replacement)
+ {
+ if (previous == null) {
+ if (!(current == parent.FirstChild))
+ Context.CodeBug ();
+ parent.replaceChild (current, replacement);
+ }
+ else if (previous.next == current) {
+ // Check cachedPrev.next == current is necessary due to possible
+ // tree mutations
+ parent.replaceChildAfter (previous, replacement);
+ }
+ else {
+ parent.replaceChild (current, replacement);
+ }
+ return replacement;
+ }
+
+ private ObjArray loops;
+ private ObjArray loopEnds;
+ private bool hasFinally;
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/Parser.cs b/src/EcmaScript.NET/Parser.cs
similarity index 96%
rename from Code/EcmaScript.NET/Parser.cs
rename to src/EcmaScript.NET/Parser.cs
index ff25eaa..dcc56a1 100644
--- a/Code/EcmaScript.NET/Parser.cs
+++ b/src/EcmaScript.NET/Parser.cs
@@ -1,2464 +1,2477 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-using System.Collections;
-
-using EcmaScript.NET.Collections;
-
-namespace EcmaScript.NET
-{
-
- /// This class implements the JavaScript parser.
- ///
- /// It is based on the C source files jsparse.c and jsparse.h
- /// in the jsref package.
- ///
- ///
- public class Parser
- {
- public string EncodedSource
- {
- get
- {
- return encodedSource;
- }
-
- }
- // TokenInformation flags : currentFlaggedToken stores them together
- // with token type
- internal const int CLEAR_TI_MASK = 0xFFFF;
- internal const int TI_AFTER_EOL = 1 << 16;
- internal const int TI_CHECK_LABEL = 1 << 17; // indicates to check for label
-
- internal CompilerEnvirons compilerEnv;
- ErrorReporter errorReporter;
- string sourceURI;
- internal bool calledByCompileFunction;
-
- TokenStream ts;
- int currentFlaggedToken;
- int syntaxErrorCount;
-
- NodeFactory nf;
-
- int nestingOfFunction;
-
- Decompiler decompiler;
- string encodedSource;
-
- // The following are per function variables and should be saved/restored
- // during function parsing.
- // TODO: Move to separated class?
- internal ScriptOrFnNode currentScriptOrFn;
- int nestingOfWith;
- Hashtable labelSet; // map of label names into nodes
- ObjArray loopSet;
- ObjArray loopAndSwitchSet;
- // end of per function variables
-
- // Exception to unwind
-
- class ParserException : ApplicationException
- {
-
- }
-
- public Parser(CompilerEnvirons compilerEnv, ErrorReporter errorReporter)
- {
- this.compilerEnv = compilerEnv;
- this.errorReporter = errorReporter;
- }
-
- Decompiler CreateDecompiler(CompilerEnvirons compilerEnv)
- {
- return new Decompiler();
- }
-
- internal void AddWarning(string messageId, string messageArg)
- {
- string message = ScriptRuntime.GetMessage(messageId, messageArg);
- errorReporter.Warning(message, sourceURI, ts.Lineno, ts.Line, ts.Offset);
- }
-
- internal void AddError(string messageId)
- {
- ++syntaxErrorCount;
- string message = ScriptRuntime.GetMessage(messageId);
- errorReporter.Error(message, sourceURI, ts.Lineno, ts.Line, ts.Offset);
- }
-
- internal Exception ReportError(string messageId)
- {
- AddError(messageId);
-
- // Throw a ParserException exception to unwind the recursive descent
- // parse.
- throw new ParserException();
- }
-
- int peekToken()
- {
- int tt = currentFlaggedToken;
- if (tt == Token.EOF)
- {
-
- while ((tt = ts.Token) == Token.CONDCOMMENT || tt == Token.KEEPCOMMENT)
- {
- if (tt == Token.CONDCOMMENT)
- {
- /* Support for JScript conditional comments */
- decompiler.AddJScriptConditionalComment(ts.String);
- }
- else
- {
- /* Support for preserved comments */
- decompiler.AddPreservedComment(ts.String);
- }
- }
-
- if (tt == Token.EOL)
- {
- do
- {
- tt = ts.Token;
-
- if (tt == Token.CONDCOMMENT)
- {
- /* Support for JScript conditional comments */
- decompiler.AddJScriptConditionalComment(ts.String);
- }
- else if (tt == Token.KEEPCOMMENT)
- {
- /* Support for preserved comments */
- decompiler.AddPreservedComment(ts.String);
- }
-
- }
- while (tt == Token.EOL || tt == Token.CONDCOMMENT || tt == Token.KEEPCOMMENT);
- tt |= TI_AFTER_EOL;
- }
- currentFlaggedToken = tt;
- }
- return tt & CLEAR_TI_MASK;
- }
-
- int peekFlaggedToken()
- {
- peekToken();
- return currentFlaggedToken;
- }
-
- void consumeToken()
- {
- currentFlaggedToken = Token.EOF;
- }
-
- int nextToken()
- {
- int tt = peekToken();
- consumeToken();
- return tt;
- }
-
- int nextFlaggedToken()
- {
- peekToken();
- int ttFlagged = currentFlaggedToken;
- consumeToken();
- return ttFlagged;
- }
-
- bool matchToken(int toMatch)
- {
- int tt = peekToken();
- if (tt != toMatch)
- {
- return false;
- }
- consumeToken();
- return true;
- }
-
- int peekTokenOrEOL()
- {
- int tt = peekToken();
- // Check for last peeked token flags
- if ((currentFlaggedToken & TI_AFTER_EOL) != 0)
- {
- tt = Token.EOL;
- }
- return tt;
- }
-
- void setCheckForLabel()
- {
- if ((currentFlaggedToken & CLEAR_TI_MASK) != Token.NAME)
- throw Context.CodeBug();
- currentFlaggedToken |= TI_CHECK_LABEL;
- }
-
- void mustMatchToken(int toMatch, string messageId)
- {
- if (!matchToken(toMatch))
- {
- ReportError(messageId);
- }
- }
-
- void mustHaveXML()
- {
- if (!compilerEnv.isXmlAvailable())
- {
- ReportError("msg.XML.not.available");
- }
- }
-
- public bool Eof
- {
- get
- {
- return ts.eof();
- }
- }
-
- internal bool insideFunction()
- {
- return nestingOfFunction != 0;
- }
-
- Node enterLoop(Node loopLabel)
- {
- Node loop = nf.CreateLoopNode(loopLabel, ts.Lineno);
- if (loopSet == null)
- {
- loopSet = new ObjArray();
- if (loopAndSwitchSet == null)
- {
- loopAndSwitchSet = new ObjArray();
- }
- }
- loopSet.push(loop);
- loopAndSwitchSet.push(loop);
- return loop;
- }
-
- void exitLoop()
- {
- loopSet.pop();
- loopAndSwitchSet.pop();
- }
-
- Node enterSwitch(Node switchSelector, int lineno, Node switchLabel)
- {
- Node switchNode = nf.CreateSwitch(switchSelector, lineno);
- if (loopAndSwitchSet == null)
- {
- loopAndSwitchSet = new ObjArray();
- }
- loopAndSwitchSet.push(switchNode);
- return switchNode;
- }
-
- void exitSwitch()
- {
- loopAndSwitchSet.pop();
- }
-
- /*
- * Build a parse tree from the given sourceString.
- *
- * @return an Object representing the parsed
- * program. If the parse fails, null will be returned. (The
- * parse failure will result in a call to the ErrorReporter from
- * CompilerEnvirons.)
- */
- public ScriptOrFnNode Parse(string sourceString, string sourceURI, int lineno)
- {
- this.sourceURI = sourceURI;
- this.ts = new TokenStream(this, null, sourceString, lineno);
- try
- {
- return Parse();
- }
- catch (System.IO.IOException)
- {
- // Should never happen
- throw new ApplicationException();
- }
- }
-
- /*
- * Build a parse tree from the given sourceString.
- *
- * @return an Object representing the parsed
- * program. If the parse fails, null will be returned. (The
- * parse failure will result in a call to the ErrorReporter from
- * CompilerEnvirons.)
- */
- public ScriptOrFnNode Parse(System.IO.StreamReader sourceReader, string sourceURI, int lineno)
- {
- this.sourceURI = sourceURI;
- this.ts = new TokenStream(this, sourceReader, null, lineno);
- return Parse();
- }
-
- ScriptOrFnNode Parse()
- {
- this.decompiler = CreateDecompiler(compilerEnv);
- this.nf = new NodeFactory(this);
- currentScriptOrFn = nf.CreateScript();
- int sourceStartOffset = decompiler.CurrentOffset;
- this.encodedSource = null;
- decompiler.AddToken(Token.SCRIPT);
-
- this.currentFlaggedToken = Token.EOF;
- this.syntaxErrorCount = 0;
-
- int baseLineno = ts.Lineno; // line number where source starts
-
- /* so we have something to add nodes to until
- * we've collected all the source */
- Node pn = nf.CreateLeaf(Token.BLOCK);
-
- for (; ; )
- {
- int tt = peekToken();
-
- if (tt <= Token.EOF)
- {
- break;
- }
-
- Node n;
- if (tt == Token.FUNCTION)
- {
- consumeToken();
- try
- {
- n = function(calledByCompileFunction ? FunctionNode.FUNCTION_EXPRESSION : FunctionNode.FUNCTION_STATEMENT);
- }
- catch (ParserException)
- {
- break;
- }
- }
- else
- {
- n = statement();
- }
- nf.addChildToBack(pn, n);
- }
-
- if (this.syntaxErrorCount != 0)
- {
- string msg = Convert.ToString(this.syntaxErrorCount);
- msg = ScriptRuntime.GetMessage("msg.got.syntax.errors", msg);
- throw errorReporter.RuntimeError(msg, sourceURI, baseLineno, null, 0);
- }
-
- currentScriptOrFn.SourceName = sourceURI;
- currentScriptOrFn.BaseLineno = baseLineno;
- currentScriptOrFn.EndLineno = ts.Lineno;
-
- int sourceEndOffset = decompiler.CurrentOffset;
- currentScriptOrFn.setEncodedSourceBounds(sourceStartOffset, sourceEndOffset);
-
- nf.initScript(currentScriptOrFn, pn);
-
- if (compilerEnv.isGeneratingSource())
- {
- encodedSource = decompiler.EncodedSource;
- }
- this.decompiler = null; // It helps GC
-
- return currentScriptOrFn;
- }
-
- /*
- * The C version of this function takes an argument list,
- * which doesn't seem to be needed for tree generation...
- * it'd only be useful for checking argument hiding, which
- * I'm not doing anyway...
- */
- Node parseFunctionBody()
- {
- ++nestingOfFunction;
- Node pn = nf.CreateBlock(ts.Lineno);
- try
- {
- for (; ; )
- {
- Node n;
- int tt = peekToken();
- switch (tt)
- {
-
- case Token.ERROR:
- case Token.EOF:
- case Token.RC:
-
- goto bodyLoop_brk;
-
-
- case Token.FUNCTION:
- consumeToken();
- n = function(FunctionNode.FUNCTION_STATEMENT);
- break;
-
- default:
- n = statement();
- break;
-
- }
- nf.addChildToBack(pn, n);
- }
-
- bodyLoop_brk:
- ;
-
- }
- catch (ParserException)
- {
- // Ignore it
- }
- finally
- {
- --nestingOfFunction;
- }
-
- return pn;
- }
-
- Node function(int functionType)
- {
- using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier(1024))
- {
- int syntheticType = functionType;
- int baseLineno = ts.Lineno; // line number where source starts
-
- int functionSourceStart = decompiler.MarkFunctionStart(functionType);
- string name;
- Node memberExprNode = null;
- if (matchToken(Token.NAME))
- {
- name = ts.String;
- decompiler.AddName(name);
- if (!matchToken(Token.LP))
- {
- if (compilerEnv.isAllowMemberExprAsFunctionName())
- {
- // Extension to ECMA: if 'function ' does not follow
- // by '(', assume starts memberExpr
- Node memberExprHead = nf.CreateName(name);
- name = "";
- memberExprNode = memberExprTail(false, memberExprHead);
- }
- mustMatchToken(Token.LP, "msg.no.paren.parms");
- }
- }
- else if (matchToken(Token.LP))
- {
- // Anonymous function
- name = "";
- }
- else
- {
- name = "";
- if (compilerEnv.isAllowMemberExprAsFunctionName())
- {
- // Note that memberExpr can not start with '(' like
- // in function (1+2).toString(), because 'function (' already
- // processed as anonymous function
- memberExprNode = memberExpr(false);
- }
- mustMatchToken(Token.LP, "msg.no.paren.parms");
- }
-
- if (memberExprNode != null)
- {
- syntheticType = FunctionNode.FUNCTION_EXPRESSION;
- }
-
- bool nested = insideFunction();
-
- FunctionNode fnNode = nf.CreateFunction(name);
- if (nested || nestingOfWith > 0)
- {
- // 1. Nested functions are not affected by the dynamic scope flag
- // as dynamic scope is already a parent of their scope.
- // 2. Functions defined under the with statement also immune to
- // this setup, in which case dynamic scope is ignored in favor
- // of with object.
- fnNode.itsIgnoreDynamicScope = true;
- }
-
- int functionIndex = currentScriptOrFn.addFunction(fnNode);
-
- int functionSourceEnd;
-
- ScriptOrFnNode savedScriptOrFn = currentScriptOrFn;
- currentScriptOrFn = fnNode;
- int savedNestingOfWith = nestingOfWith;
- nestingOfWith = 0;
- Hashtable savedLabelSet = labelSet;
- labelSet = null;
- ObjArray savedLoopSet = loopSet;
- loopSet = null;
- ObjArray savedLoopAndSwitchSet = loopAndSwitchSet;
- loopAndSwitchSet = null;
-
- Node body;
- try
- {
- decompiler.AddToken(Token.LP);
- if (!matchToken(Token.RP))
- {
- bool first = true;
- do
- {
- if (!first)
- decompiler.AddToken(Token.COMMA);
- first = false;
- mustMatchToken(Token.NAME, "msg.no.parm");
- string s = ts.String;
- if (fnNode.hasParamOrVar(s))
- {
- AddWarning("msg.dup.parms", s);
- }
- fnNode.addParam(s);
- decompiler.AddName(s);
- }
- while (matchToken(Token.COMMA));
-
- mustMatchToken(Token.RP, "msg.no.paren.after.parms");
- }
- decompiler.AddToken(Token.RP);
-
- mustMatchToken(Token.LC, "msg.no.brace.body");
- decompiler.AddEol(Token.LC);
- body = parseFunctionBody();
- mustMatchToken(Token.RC, "msg.no.brace.after.body");
-
- decompiler.AddToken(Token.RC);
- functionSourceEnd = decompiler.MarkFunctionEnd(functionSourceStart);
- if (functionType != FunctionNode.FUNCTION_EXPRESSION)
- {
- if (compilerEnv.LanguageVersion >= Context.Versions.JS1_2)
- {
- // function f() {} function g() {} is not allowed in 1.2
- // or later but for compatibility with old scripts
- // the check is done only if language is
- // explicitly set.
- // TODO: warning needed if version == VERSION_DEFAULT ?
- int tt = peekTokenOrEOL();
- if (tt == Token.FUNCTION)
- {
- ReportError("msg.no.semi.stmt");
- }
- }
- // Add EOL only if function is not part of expression
- // since it gets SEMI + EOL from Statement in that case
- decompiler.AddToken(Token.EOL);
- }
- }
- finally
- {
- loopAndSwitchSet = savedLoopAndSwitchSet;
- loopSet = savedLoopSet;
- labelSet = savedLabelSet;
- nestingOfWith = savedNestingOfWith;
- currentScriptOrFn = savedScriptOrFn;
- }
-
- fnNode.setEncodedSourceBounds(functionSourceStart, functionSourceEnd);
- fnNode.SourceName = sourceURI;
- fnNode.BaseLineno = baseLineno;
- fnNode.EndLineno = ts.Lineno;
-
- Node pn = nf.initFunction(fnNode, functionIndex, body, syntheticType);
- if (memberExprNode != null)
- {
- pn = nf.CreateAssignment(Token.ASSIGN, memberExprNode, pn);
- if (functionType != FunctionNode.FUNCTION_EXPRESSION)
- {
- // TOOD: check JScript behavior: should it be createExprStatement?
- pn = nf.CreateExprStatementNoReturn(pn, baseLineno);
- }
- }
- return pn;
- }
- }
-
- Node statements()
- {
- Node pn = nf.CreateBlock(ts.Lineno);
-
- int tt;
- while ((tt = peekToken()) > Token.EOF && tt != Token.RC)
- {
- nf.addChildToBack(pn, statement());
- }
-
- return pn;
- }
-
- Node condition()
- {
- Node pn;
- mustMatchToken(Token.LP, "msg.no.paren.cond");
- decompiler.AddToken(Token.LP);
- pn = expr(false);
- mustMatchToken(Token.RP, "msg.no.paren.after.cond");
- decompiler.AddToken(Token.RP);
-
- // there's a check here in jsparse.c that corrects = to ==
-
- return pn;
- }
-
- // match a NAME; return null if no match.
- Node matchJumpLabelName()
- {
- Node label = null;
-
- int tt = peekTokenOrEOL();
- if (tt == Token.NAME)
- {
- consumeToken();
- string name = ts.String;
- decompiler.AddName(name);
- if (labelSet != null)
- {
- label = (Node)labelSet[name];
- }
- if (label == null)
- {
- ReportError("msg.undef.label");
- }
- }
-
- return label;
- }
-
- Node statement()
- {
- using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier(512))
- {
- try
- {
- Node pn = statementHelper(null);
- if (pn != null)
- {
- return pn;
- }
- }
- catch (ParserException)
- {
- }
- }
-
- // skip to end of statement
- int lineno = ts.Lineno;
- for (; ; )
- {
- int tt = peekTokenOrEOL();
- consumeToken();
- switch (tt)
- {
-
- case Token.ERROR:
- case Token.EOF:
- case Token.EOL:
- case Token.SEMI:
-
- goto guessingStatementEnd_brk;
- }
- }
-
- guessingStatementEnd_brk:
- ;
-
- return nf.CreateExprStatement(nf.CreateName("error"), lineno);
- }
-
- /// Whether the "catch (e: e instanceof Exception) { ... }" syntax
- /// is implemented.
- ///
-
- Node statementHelper(Node statementLabel)
- {
- Node pn = null;
-
- int tt;
-
- tt = peekToken();
-
- switch (tt)
- {
-
- case Token.IF:
- {
- consumeToken();
-
- decompiler.AddToken(Token.IF);
- int lineno = ts.Lineno;
- Node cond = condition();
- decompiler.AddEol(Token.LC);
- Node ifTrue = statement();
- Node ifFalse = null;
- if (matchToken(Token.ELSE))
- {
- decompiler.AddToken(Token.RC);
- decompiler.AddToken(Token.ELSE);
- decompiler.AddEol(Token.LC);
- ifFalse = statement();
- }
- decompiler.AddEol(Token.RC);
- pn = nf.CreateIf(cond, ifTrue, ifFalse, lineno);
- return pn;
- }
-
-
- case Token.SWITCH:
- {
- consumeToken();
-
- decompiler.AddToken(Token.SWITCH);
- int lineno = ts.Lineno;
- mustMatchToken(Token.LP, "msg.no.paren.switch");
- decompiler.AddToken(Token.LP);
- pn = enterSwitch(expr(false), lineno, statementLabel);
- try
- {
- mustMatchToken(Token.RP, "msg.no.paren.after.switch");
- decompiler.AddToken(Token.RP);
- mustMatchToken(Token.LC, "msg.no.brace.switch");
- decompiler.AddEol(Token.LC);
-
- bool hasDefault = false;
- for (; ; )
- {
- tt = nextToken();
- Node caseExpression;
- switch (tt)
- {
-
- case Token.RC:
-
- goto switchLoop_brk;
-
-
- case Token.CASE:
- decompiler.AddToken(Token.CASE);
- caseExpression = expr(false);
- mustMatchToken(Token.COLON, "msg.no.colon.case");
- decompiler.AddEol(Token.COLON);
- break;
-
-
- case Token.DEFAULT:
- if (hasDefault)
- {
- ReportError("msg.double.switch.default");
- }
- decompiler.AddToken(Token.DEFAULT);
- hasDefault = true;
- caseExpression = null;
- mustMatchToken(Token.COLON, "msg.no.colon.case");
- decompiler.AddEol(Token.COLON);
- break;
-
-
- default:
- ReportError("msg.bad.switch");
-
- goto switchLoop_brk;
-
- }
-
- Node block = nf.CreateLeaf(Token.BLOCK);
- while ((tt = peekToken()) != Token.RC && tt != Token.CASE && tt != Token.DEFAULT && tt != Token.EOF)
- {
- nf.addChildToBack(block, statement());
- }
-
- // caseExpression == null => add default lable
- nf.addSwitchCase(pn, caseExpression, block);
- }
-
- switchLoop_brk:
- ;
-
- decompiler.AddEol(Token.RC);
- nf.closeSwitch(pn);
- }
- finally
- {
- exitSwitch();
- }
- return pn;
- }
-
-
- case Token.WHILE:
- {
- consumeToken();
- decompiler.AddToken(Token.WHILE);
-
- Node loop = enterLoop(statementLabel);
- try
- {
- Node cond = condition();
- decompiler.AddEol(Token.LC);
- Node body = statement();
- decompiler.AddEol(Token.RC);
- pn = nf.CreateWhile(loop, cond, body);
- }
- finally
- {
- exitLoop();
- }
- return pn;
- }
-
-
- case Token.DO:
- {
- consumeToken();
- decompiler.AddToken(Token.DO);
- decompiler.AddEol(Token.LC);
-
- Node loop = enterLoop(statementLabel);
- try
- {
- Node body = statement();
- decompiler.AddToken(Token.RC);
- mustMatchToken(Token.WHILE, "msg.no.while.do");
- decompiler.AddToken(Token.WHILE);
- Node cond = condition();
- pn = nf.CreateDoWhile(loop, body, cond);
- }
- finally
- {
- exitLoop();
- }
- // Always auto-insert semicon to follow SpiderMonkey:
- // It is required by EMAScript but is ignored by the rest of
- // world, see bug 238945
- matchToken(Token.SEMI);
- decompiler.AddEol(Token.SEMI);
- return pn;
- }
-
-
- case Token.FOR:
- {
- consumeToken();
- bool isForEach = false;
- decompiler.AddToken(Token.FOR);
-
- Node loop = enterLoop(statementLabel);
- try
- {
-
- Node init; // Node init is also foo in 'foo in Object'
- Node cond; // Node cond is also object in 'foo in Object'
- Node incr = null; // to kill warning
- Node body;
-
- // See if this is a for each () instead of just a for ()
- if (matchToken(Token.NAME))
- {
- decompiler.AddName(ts.String);
- if (ts.String.Equals("each"))
- {
- isForEach = true;
- }
- else
- {
- ReportError("msg.no.paren.for");
- }
- }
-
- mustMatchToken(Token.LP, "msg.no.paren.for");
- decompiler.AddToken(Token.LP);
- tt = peekToken();
- if (tt == Token.SEMI)
- {
- init = nf.CreateLeaf(Token.EMPTY);
- }
- else
- {
- if (tt == Token.VAR)
- {
- // set init to a var list or initial
- consumeToken(); // consume the 'var' token
- init = variables(true);
- }
- else
- {
- init = expr(true);
- }
- }
-
- if (matchToken(Token.IN))
- {
- decompiler.AddToken(Token.IN);
- // 'cond' is the object over which we're iterating
- cond = expr(false);
- }
- else
- {
- // ordinary for loop
- mustMatchToken(Token.SEMI, "msg.no.semi.for");
- decompiler.AddToken(Token.SEMI);
- if (peekToken() == Token.SEMI)
- {
- // no loop condition
- cond = nf.CreateLeaf(Token.EMPTY);
- }
- else
- {
- cond = expr(false);
- }
-
- mustMatchToken(Token.SEMI, "msg.no.semi.for.cond");
- decompiler.AddToken(Token.SEMI);
- if (peekToken() == Token.RP)
- {
- incr = nf.CreateLeaf(Token.EMPTY);
- }
- else
- {
- incr = expr(false);
- }
- }
-
- mustMatchToken(Token.RP, "msg.no.paren.for.ctrl");
- decompiler.AddToken(Token.RP);
- decompiler.AddEol(Token.LC);
- body = statement();
- decompiler.AddEol(Token.RC);
-
- if (incr == null)
- {
- // cond could be null if 'in obj' got eaten
- // by the init node.
- pn = nf.CreateForIn(loop, init, cond, body, isForEach);
- }
- else
- {
- pn = nf.CreateFor(loop, init, cond, incr, body);
- }
- }
- finally
- {
- exitLoop();
- }
- return pn;
- }
-
-
- case Token.TRY:
- {
- consumeToken();
- int lineno = ts.Lineno;
-
- Node tryblock;
- Node catchblocks = null;
- Node finallyblock = null;
-
- decompiler.AddToken(Token.TRY);
- decompiler.AddEol(Token.LC);
- tryblock = statement();
- decompiler.AddEol(Token.RC);
-
- catchblocks = nf.CreateLeaf(Token.BLOCK);
-
- bool sawDefaultCatch = false;
- int peek = peekToken();
- if (peek == Token.CATCH)
- {
- while (matchToken(Token.CATCH))
- {
- if (sawDefaultCatch)
- {
- ReportError("msg.catch.unreachable");
- }
- decompiler.AddToken(Token.CATCH);
- mustMatchToken(Token.LP, "msg.no.paren.catch");
- decompiler.AddToken(Token.LP);
-
- mustMatchToken(Token.NAME, "msg.bad.catchcond");
- string varName = ts.String;
- decompiler.AddName(varName);
-
- Node catchCond = null;
- if (matchToken(Token.IF))
- {
- decompiler.AddToken(Token.IF);
- catchCond = expr(false);
- }
- else
- {
- sawDefaultCatch = true;
- }
-
- mustMatchToken(Token.RP, "msg.bad.catchcond");
- decompiler.AddToken(Token.RP);
- mustMatchToken(Token.LC, "msg.no.brace.catchblock");
- decompiler.AddEol(Token.LC);
-
- nf.addChildToBack(catchblocks, nf.CreateCatch(varName, catchCond, statements(), ts.Lineno));
-
- mustMatchToken(Token.RC, "msg.no.brace.after.body");
- decompiler.AddEol(Token.RC);
- }
- }
- else if (peek != Token.FINALLY)
- {
- mustMatchToken(Token.FINALLY, "msg.try.no.catchfinally");
- }
-
- if (matchToken(Token.FINALLY))
- {
- decompiler.AddToken(Token.FINALLY);
- decompiler.AddEol(Token.LC);
- finallyblock = statement();
- decompiler.AddEol(Token.RC);
- }
-
- pn = nf.CreateTryCatchFinally(tryblock, catchblocks, finallyblock, lineno);
-
- return pn;
- }
-
-
- case Token.THROW:
- {
- consumeToken();
- if (peekTokenOrEOL() == Token.EOL)
- {
- // ECMAScript does not allow new lines before throw expression,
- // see bug 256617
- ReportError("msg.bad.throw.eol");
- }
-
- int lineno = ts.Lineno;
- decompiler.AddToken(Token.THROW);
- pn = nf.CreateThrow(expr(false), lineno);
- break;
- }
-
-
- case Token.BREAK:
- {
- consumeToken();
- int lineno = ts.Lineno;
-
- decompiler.AddToken(Token.BREAK);
-
- // matchJumpLabelName only matches if there is one
- Node breakStatement = matchJumpLabelName();
- if (breakStatement == null)
- {
- if (loopAndSwitchSet == null || loopAndSwitchSet.size() == 0)
- {
- ReportError("msg.bad.break");
- return null;
- }
- breakStatement = (Node)loopAndSwitchSet.peek();
- }
- pn = nf.CreateBreak(breakStatement, lineno);
- break;
- }
-
-
- case Token.CONTINUE:
- {
- consumeToken();
- int lineno = ts.Lineno;
-
- decompiler.AddToken(Token.CONTINUE);
-
- Node loop;
- // matchJumpLabelName only matches if there is one
- Node label = matchJumpLabelName();
- if (label == null)
- {
- if (loopSet == null || loopSet.size() == 0)
- {
- ReportError("msg.continue.outside");
- return null;
- }
- loop = (Node)loopSet.peek();
- }
- else
- {
- loop = nf.getLabelLoop(label);
- if (loop == null)
- {
- ReportError("msg.continue.nonloop");
- return null;
- }
- }
- pn = nf.CreateContinue(loop, lineno);
- break;
- }
-
-
- case Token.WITH:
- {
- consumeToken();
-
- decompiler.AddToken(Token.WITH);
- int lineno = ts.Lineno;
- mustMatchToken(Token.LP, "msg.no.paren.with");
- decompiler.AddToken(Token.LP);
- Node obj = expr(false);
- mustMatchToken(Token.RP, "msg.no.paren.after.with");
- decompiler.AddToken(Token.RP);
- decompiler.AddEol(Token.LC);
-
- ++nestingOfWith;
- Node body;
- try
- {
- body = statement();
- }
- finally
- {
- --nestingOfWith;
- }
-
- decompiler.AddEol(Token.RC);
-
- pn = nf.CreateWith(obj, body, lineno);
- return pn;
- }
-
-
- case Token.VAR:
- {
- consumeToken();
- pn = variables(false);
- break;
- }
-
-
- case Token.RETURN:
- {
- if (!insideFunction())
- {
- ReportError("msg.bad.return");
- }
- consumeToken();
- decompiler.AddToken(Token.RETURN);
- int lineno = ts.Lineno;
-
- Node retExpr;
- /* This is ugly, but we don't want to require a semicolon. */
- tt = peekTokenOrEOL();
- switch (tt)
- {
-
- case Token.SEMI:
- case Token.RC:
- case Token.EOF:
- case Token.EOL:
- case Token.ERROR:
- retExpr = null;
- break;
-
- default:
- retExpr = expr(false);
- break;
-
- }
- pn = nf.CreateReturn(retExpr, lineno);
- break;
- }
-
- case Token.DEBUGGER:
- consumeToken();
- decompiler.AddToken(Token.DEBUGGER);
- pn = nf.CreateDebugger(ts.Lineno);
- break;
-
- case Token.LC:
- consumeToken();
- if (statementLabel != null)
- {
- decompiler.AddToken(Token.LC);
- }
- pn = statements();
- mustMatchToken(Token.RC, "msg.no.brace.block");
- if (statementLabel != null)
- {
- decompiler.AddEol(Token.RC);
- }
- return pn;
-
-
- case Token.ERROR:
- // Fall thru, to have a node for error recovery to work on
- case Token.SEMI:
- consumeToken();
- pn = nf.CreateLeaf(Token.EMPTY);
- return pn;
-
-
- case Token.FUNCTION:
- {
- consumeToken();
- pn = function(FunctionNode.FUNCTION_EXPRESSION_STATEMENT);
- return pn;
- }
-
-
- case Token.DEFAULT:
- consumeToken();
- mustHaveXML();
-
- decompiler.AddToken(Token.DEFAULT);
- int nsLine = ts.Lineno;
-
- if (!(matchToken(Token.NAME) && ts.String.Equals("xml")))
- {
- ReportError("msg.bad.namespace");
- }
- decompiler.AddName(ts.String);
-
- if (!(matchToken(Token.NAME) && ts.String.Equals("namespace")))
- {
- ReportError("msg.bad.namespace");
- }
- decompiler.AddName(ts.String);
-
- if (!matchToken(Token.ASSIGN))
- {
- ReportError("msg.bad.namespace");
- }
- decompiler.AddToken(Token.ASSIGN);
-
- Node e = expr(false);
- pn = nf.CreateDefaultNamespace(e, nsLine);
- break;
-
-
- case Token.NAME:
- {
- int lineno = ts.Lineno;
- string name = ts.String;
- setCheckForLabel();
- pn = expr(false);
- if (pn.Type != Token.LABEL)
- {
-
- if (compilerEnv.getterAndSetterSupport)
- {
- tt = peekToken();
- if (tt == Token.NAME)
- {
- if (ts.String == "getter" || ts.String == "setter")
- {
- pn.Type = (ts.String[0] == 'g' ? Token.SETPROP_GETTER
- : Token.SETPROP_SETTER);
- decompiler.AddName(" " + ts.String); // HACK: Hack (whitespace) for decmpiler
- consumeToken();
- matchToken(Token.ASSIGN);
- decompiler.AddToken(Token.ASSIGN);
- matchToken(Token.FUNCTION);
- Node fn = function(FunctionNode.FUNCTION_EXPRESSION);
- pn.addChildToBack(fn);
- }
- }
- }
- pn = nf.CreateExprStatement(pn, lineno);
- }
- else
- {
- // Parsed the label: push back token should be
- // colon that primaryExpr left untouched.
- if (peekToken() != Token.COLON)
- Context.CodeBug();
- consumeToken();
- // depend on decompiling lookahead to guess that that
- // last name was a label.
- decompiler.AddName(name);
- decompiler.AddEol(Token.COLON);
-
- if (labelSet == null)
- {
- labelSet = Hashtable.Synchronized(new Hashtable());
- }
- else if (labelSet.ContainsKey(name))
- {
- ReportError("msg.dup.label");
- }
-
- bool firstLabel;
- if (statementLabel == null)
- {
- firstLabel = true;
- statementLabel = pn;
- }
- else
- {
- // Discard multiple label nodes and use only
- // the first: it allows to simplify IRFactory
- firstLabel = false;
- }
- labelSet[name] = statementLabel;
- try
- {
- pn = statementHelper(statementLabel);
- }
- finally
- {
- labelSet.Remove(name);
- }
- if (firstLabel)
- {
- pn = nf.CreateLabeledStatement(statementLabel, pn);
- }
- return pn;
- }
- break;
- }
-
-
- default:
- {
- int lineno = ts.Lineno;
- pn = expr(false);
- pn = nf.CreateExprStatement(pn, lineno);
- break;
- }
-
- }
-
- // FINDME
-
- int ttFlagged = peekFlaggedToken();
- switch (ttFlagged & CLEAR_TI_MASK)
- {
-
- case Token.SEMI:
- // Consume ';' as a part of expression
- consumeToken();
- break;
-
- case Token.ERROR:
- case Token.EOF:
- case Token.RC:
- // Autoinsert ;
- break;
-
- default:
- if ((ttFlagged & TI_AFTER_EOL) == 0)
- {
- // Report error if no EOL or autoinsert ; otherwise
- ReportError("msg.no.semi.stmt");
- }
- break;
-
- }
- decompiler.AddEol(Token.SEMI);
-
- return pn;
- }
-
- Node variables(bool inForInit)
- {
- Node pn = nf.CreateVariables(ts.Lineno);
- bool first = true;
-
- decompiler.AddToken(Token.VAR);
-
- for (; ; )
- {
- Node name;
- Node init;
- mustMatchToken(Token.NAME, "msg.bad.var");
- string s = ts.String;
-
- if (!first)
- decompiler.AddToken(Token.COMMA);
- first = false;
-
- decompiler.AddName(s);
- currentScriptOrFn.addVar(s);
- name = nf.CreateName(s);
-
- // omitted check for argument hiding
-
- if (matchToken(Token.ASSIGN))
- {
- decompiler.AddToken(Token.ASSIGN);
-
- init = assignExpr(inForInit);
- nf.addChildToBack(name, init);
- }
- nf.addChildToBack(pn, name);
- if (!matchToken(Token.COMMA))
- break;
- }
- return pn;
- }
-
- Node expr(bool inForInit)
- {
- Node pn = assignExpr(inForInit);
- while (matchToken(Token.COMMA))
- {
- decompiler.AddToken(Token.COMMA);
- pn = nf.CreateBinary(Token.COMMA, pn, assignExpr(inForInit));
- }
- return pn;
- }
-
- Node assignExpr(bool inForInit)
- {
- Node pn = condExpr(inForInit);
-
- int tt = peekToken();
- if (Token.FIRST_ASSIGN <= tt && tt <= Token.LAST_ASSIGN)
- {
- consumeToken();
- decompiler.AddToken(tt);
- pn = nf.CreateAssignment(tt, pn, assignExpr(inForInit));
- }
-
- return pn;
- }
-
- Node condExpr(bool inForInit)
- {
- Node ifTrue;
- Node ifFalse;
-
- Node pn = orExpr(inForInit);
-
- if (matchToken(Token.HOOK))
- {
- decompiler.AddToken(Token.HOOK);
- ifTrue = assignExpr(false);
- mustMatchToken(Token.COLON, "msg.no.colon.cond");
- decompiler.AddToken(Token.COLON);
- ifFalse = assignExpr(inForInit);
- return nf.CreateCondExpr(pn, ifTrue, ifFalse);
- }
-
- return pn;
- }
-
- Node orExpr(bool inForInit)
- {
- Node pn = andExpr(inForInit);
- if (matchToken(Token.OR))
- {
- decompiler.AddToken(Token.OR);
- pn = nf.CreateBinary(Token.OR, pn, orExpr(inForInit));
- }
-
- return pn;
- }
-
- Node andExpr(bool inForInit)
- {
- Node pn = bitOrExpr(inForInit);
- if (matchToken(Token.AND))
- {
- decompiler.AddToken(Token.AND);
- pn = nf.CreateBinary(Token.AND, pn, andExpr(inForInit));
- }
-
- return pn;
- }
-
- Node bitOrExpr(bool inForInit)
- {
- Node pn = bitXorExpr(inForInit);
- while (matchToken(Token.BITOR))
- {
- decompiler.AddToken(Token.BITOR);
- pn = nf.CreateBinary(Token.BITOR, pn, bitXorExpr(inForInit));
- }
- return pn;
- }
-
- Node bitXorExpr(bool inForInit)
- {
- Node pn = bitAndExpr(inForInit);
- while (matchToken(Token.BITXOR))
- {
- decompiler.AddToken(Token.BITXOR);
- pn = nf.CreateBinary(Token.BITXOR, pn, bitAndExpr(inForInit));
- }
- return pn;
- }
-
- Node bitAndExpr(bool inForInit)
- {
- Node pn = eqExpr(inForInit);
- while (matchToken(Token.BITAND))
- {
- decompiler.AddToken(Token.BITAND);
- pn = nf.CreateBinary(Token.BITAND, pn, eqExpr(inForInit));
- }
- return pn;
- }
-
- Node eqExpr(bool inForInit)
- {
- Node pn = relExpr(inForInit);
- for (; ; )
- {
- int tt = peekToken();
- switch (tt)
- {
-
- case Token.EQ:
- case Token.NE:
- case Token.SHEQ:
- case Token.SHNE:
- consumeToken();
- int decompilerToken = tt;
- int parseToken = tt;
- if (compilerEnv.LanguageVersion == Context.Versions.JS1_2)
- {
- // JavaScript 1.2 uses shallow equality for == and != .
- // In addition, convert === and !== for decompiler into
- // == and != since the decompiler is supposed to show
- // canonical source and in 1.2 ===, !== are allowed
- // only as an alias to ==, !=.
- switch (tt)
- {
-
- case Token.EQ:
- parseToken = Token.SHEQ;
- break;
-
- case Token.NE:
- parseToken = Token.SHNE;
- break;
-
- case Token.SHEQ:
- decompilerToken = Token.EQ;
- break;
-
- case Token.SHNE:
- decompilerToken = Token.NE;
- break;
- }
- }
- decompiler.AddToken(decompilerToken);
- pn = nf.CreateBinary(parseToken, pn, relExpr(inForInit));
- continue;
- }
- break;
- }
- return pn;
- }
-
- Node relExpr(bool inForInit)
- {
- Node pn = shiftExpr();
- for (; ; )
- {
- int tt = peekToken();
- switch (tt)
- {
-
- case Token.IN:
- if (inForInit)
- break;
- // fall through
- goto case Token.INSTANCEOF;
-
- case Token.INSTANCEOF:
- case Token.LE:
- case Token.LT:
- case Token.GE:
- case Token.GT:
- consumeToken();
- decompiler.AddToken(tt);
- pn = nf.CreateBinary(tt, pn, shiftExpr());
- continue;
- }
- break;
- }
- return pn;
- }
-
- Node shiftExpr()
- {
- Node pn = addExpr();
- for (; ; )
- {
- int tt = peekToken();
- switch (tt)
- {
-
- case Token.LSH:
- case Token.URSH:
- case Token.RSH:
- consumeToken();
- decompiler.AddToken(tt);
- pn = nf.CreateBinary(tt, pn, addExpr());
- continue;
- }
- break;
- }
- return pn;
- }
-
- Node addExpr()
- {
- Node pn = mulExpr();
- for (; ; )
- {
- int tt = peekToken();
- if (tt == Token.ADD || tt == Token.SUB)
- {
- consumeToken();
- decompiler.AddToken(tt);
- // flushNewLines
- pn = nf.CreateBinary(tt, pn, mulExpr());
- continue;
- }
- break;
- }
-
- return pn;
- }
-
- Node mulExpr()
- {
- Node pn = unaryExpr();
- for (; ; )
- {
- int tt = peekToken();
- switch (tt)
- {
-
- case Token.MUL:
- case Token.DIV:
- case Token.MOD:
- consumeToken();
- decompiler.AddToken(tt);
- pn = nf.CreateBinary(tt, pn, unaryExpr());
- continue;
- }
- break;
- }
-
- return pn;
- }
-
- Node unaryExpr()
- {
- using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier(4096))
- {
- int tt;
-
- tt = peekToken();
-
- switch (tt)
- {
-
- case Token.VOID:
- case Token.NOT:
- case Token.BITNOT:
- case Token.TYPEOF:
- consumeToken();
- decompiler.AddToken(tt);
- return nf.CreateUnary(tt, unaryExpr());
-
-
- case Token.ADD:
- consumeToken();
- // Convert to special POS token in decompiler and parse tree
- decompiler.AddToken(Token.POS);
- return nf.CreateUnary(Token.POS, unaryExpr());
-
-
- case Token.SUB:
- consumeToken();
- // Convert to special NEG token in decompiler and parse tree
- decompiler.AddToken(Token.NEG);
- return nf.CreateUnary(Token.NEG, unaryExpr());
-
-
- case Token.INC:
- case Token.DEC:
- consumeToken();
- decompiler.AddToken(tt);
- return nf.CreateIncDec(tt, false, memberExpr(true));
-
-
- case Token.DELPROP:
- consumeToken();
- decompiler.AddToken(Token.DELPROP);
- return nf.CreateUnary(Token.DELPROP, unaryExpr());
-
-
- case Token.ERROR:
- consumeToken();
- break;
-
- // XML stream encountered in expression.
-
- case Token.LT:
- if (compilerEnv.isXmlAvailable())
- {
- consumeToken();
- Node pn = xmlInitializer();
- return memberExprTail(true, pn);
- }
- // Fall thru to the default handling of RELOP
- goto default;
-
-
- default:
- {
- Node pn = memberExpr(true);
-
- // Don't look across a newline boundary for a postfix incop.
- tt = peekTokenOrEOL();
- if (tt == Token.INC || tt == Token.DEC)
- {
- consumeToken();
- decompiler.AddToken(tt);
- return nf.CreateIncDec(tt, true, pn);
- }
- return pn;
- }
-
- }
- return nf.CreateName("err"); // Only reached on error. Try to continue.
- }
- }
-
- Node xmlInitializer()
- {
- int tt = ts.FirstXMLToken;
- if (tt != Token.XML && tt != Token.XMLEND)
- {
- ReportError("msg.syntax");
- return null;
- }
-
- /* Make a NEW node to append to. */
- Node pnXML = nf.CreateLeaf(Token.NEW);
- decompiler.AddToken(Token.NEW);
- decompiler.AddToken(Token.DOT);
-
- string xml = ts.String;
- bool fAnonymous = xml.Trim().StartsWith("<>");
-
- decompiler.AddName(fAnonymous ? "XMLList" : "XML");
- Node pn = nf.CreateName(fAnonymous ? "XMLList" : "XML");
- nf.addChildToBack(pnXML, pn);
-
- pn = null;
- Node e;
- for (; ; tt = ts.NextXMLToken)
- {
- switch (tt)
- {
-
- case Token.XML:
- xml = ts.String;
- decompiler.AddString(xml);
- mustMatchToken(Token.LC, "msg.syntax");
- decompiler.AddToken(Token.LC);
- e = (peekToken() == Token.RC) ? nf.CreateString("") : expr(false);
- mustMatchToken(Token.RC, "msg.syntax");
- decompiler.AddToken(Token.RC);
- if (pn == null)
- {
- pn = nf.CreateString(xml);
- }
- else
- {
- pn = nf.CreateBinary(Token.ADD, pn, nf.CreateString(xml));
- }
- int nodeType;
- if (ts.XMLAttribute)
- {
- nodeType = Token.ESCXMLATTR;
- }
- else
- {
- nodeType = Token.ESCXMLTEXT;
- }
- e = nf.CreateUnary(nodeType, e);
- pn = nf.CreateBinary(Token.ADD, pn, e);
- break;
-
- case Token.XMLEND:
- xml = ts.String;
- decompiler.AddString(xml);
- if (pn == null)
- {
- pn = nf.CreateString(xml);
- }
- else
- {
- pn = nf.CreateBinary(Token.ADD, pn, nf.CreateString(xml));
- }
-
- nf.addChildToBack(pnXML, pn);
- return pnXML;
-
- default:
- ReportError("msg.syntax");
- return null;
-
- }
- }
- }
-
- void argumentList(Node listNode)
- {
- bool matched;
- matched = matchToken(Token.RP);
- if (!matched)
- {
- bool first = true;
- do
- {
- if (!first)
- decompiler.AddToken(Token.COMMA);
- first = false;
- nf.addChildToBack(listNode, assignExpr(false));
- }
- while (matchToken(Token.COMMA));
-
- mustMatchToken(Token.RP, "msg.no.paren.arg");
- }
- decompiler.AddToken(Token.RP);
- }
-
- Node memberExpr(bool allowCallSyntax)
- {
- int tt;
-
- Node pn;
-
- /* Check for new expressions. */
- tt = peekToken();
- if (tt == Token.NEW)
- {
- /* Eat the NEW token. */
- consumeToken();
- decompiler.AddToken(Token.NEW);
-
- /* Make a NEW node to append to. */
- pn = nf.CreateCallOrNew(Token.NEW, memberExpr(false));
-
- if (matchToken(Token.LP))
- {
- decompiler.AddToken(Token.LP);
- /* Add the arguments to pn, if any are supplied. */
- argumentList(pn);
- }
-
- // TODO: there's a check in the C source against
- // TODO: "too many constructor arguments" - how many
- // TODO: do we claim to support?
-
- /* Experimental syntax: allow an object literal to follow a new expression,
- * which will mean a kind of anonymous class built with the JavaAdapter.
- * the object literal will be passed as an additional argument to the constructor.
- */
- tt = peekToken();
- if (tt == Token.LC)
- {
- nf.addChildToBack(pn, primaryExpr());
- }
- }
- else
- {
- pn = primaryExpr();
- }
-
- return memberExprTail(allowCallSyntax, pn);
- }
-
- Node memberExprTail(bool allowCallSyntax, Node pn)
- {
- for (; ; )
- {
- int tt = peekToken();
- switch (tt)
- {
-
-
- case Token.DOT:
- case Token.DOTDOT:
- {
- int memberTypeFlags;
- string s;
-
- consumeToken();
- decompiler.AddToken(tt);
- memberTypeFlags = 0;
- if (tt == Token.DOTDOT)
- {
- mustHaveXML();
- memberTypeFlags = Node.DESCENDANTS_FLAG;
- }
- if (!compilerEnv.isXmlAvailable())
- {
- mustMatchToken(Token.NAME, "msg.no.name.after.dot");
- s = ts.String;
- decompiler.AddName(s);
- pn = nf.CreatePropertyGet(pn, null, s, memberTypeFlags);
- break;
- }
-
-
- tt = nextToken();
-
- switch (tt)
- {
-
- // handles: name, ns::name, ns::*, ns::[expr]
- case Token.NAME:
- s = ts.String;
- decompiler.AddName(s);
- pn = propertyName(pn, s, memberTypeFlags);
- break;
-
- // handles: *, *::name, *::*, *::[expr]
-
- case Token.MUL:
- decompiler.AddName("*");
- pn = propertyName(pn, "*", memberTypeFlags);
- break;
-
- // handles: '@attr', '@ns::attr', '@ns::*', '@ns::*',
- // '@::attr', '@::*', '@*', '@*::attr', '@*::*'
-
- case Token.XMLATTR:
- decompiler.AddToken(Token.XMLATTR);
- pn = attributeAccess(pn, memberTypeFlags);
- break;
-
-
- default:
- ReportError("msg.no.name.after.dot");
- break;
-
- }
- }
- break;
-
-
- case Token.DOTQUERY:
- consumeToken();
- mustHaveXML();
- decompiler.AddToken(Token.DOTQUERY);
- pn = nf.CreateDotQuery(pn, expr(false), ts.Lineno);
- mustMatchToken(Token.RP, "msg.no.paren");
- decompiler.AddToken(Token.RP);
- break;
-
-
- case Token.LB:
- consumeToken();
- decompiler.AddToken(Token.LB);
- pn = nf.CreateElementGet(pn, null, expr(false), 0);
- mustMatchToken(Token.RB, "msg.no.bracket.index");
- decompiler.AddToken(Token.RB);
- break;
-
-
- case Token.LP:
- if (!allowCallSyntax)
- {
-
- goto tailLoop_brk;
- }
- consumeToken();
- decompiler.AddToken(Token.LP);
- pn = nf.CreateCallOrNew(Token.CALL, pn);
- /* Add the arguments to pn, if any are supplied. */
- argumentList(pn);
- break;
-
-
- default:
-
- goto tailLoop_brk;
-
- }
- }
-
- tailLoop_brk:
- ;
-
- return pn;
- }
-
- /*
- * Xml attribute expression:
- * '@attr', '@ns::attr', '@ns::*', '@ns::*', '@*', '@*::attr', '@*::*'
- */
- Node attributeAccess(Node pn, int memberTypeFlags)
- {
- memberTypeFlags |= Node.ATTRIBUTE_FLAG;
- int tt = nextToken();
-
- switch (tt)
- {
-
- // handles: @name, @ns::name, @ns::*, @ns::[expr]
- case Token.NAME:
- {
- string s = ts.String;
- decompiler.AddName(s);
- pn = propertyName(pn, s, memberTypeFlags);
- }
- break;
-
- // handles: @*, @*::name, @*::*, @*::[expr]
-
- case Token.MUL:
- decompiler.AddName("*");
- pn = propertyName(pn, "*", memberTypeFlags);
- break;
-
- // handles @[expr]
-
- case Token.LB:
- decompiler.AddToken(Token.LB);
- pn = nf.CreateElementGet(pn, null, expr(false), memberTypeFlags);
- mustMatchToken(Token.RB, "msg.no.bracket.index");
- decompiler.AddToken(Token.RB);
- break;
-
-
- default:
- ReportError("msg.no.name.after.xmlAttr");
- pn = nf.CreatePropertyGet(pn, null, "?", memberTypeFlags);
- break;
-
- }
-
- return pn;
- }
-
- /// Check if :: follows name in which case it becomes qualified name
- Node propertyName(Node pn, string name, int memberTypeFlags)
- {
- string ns = null;
- if (matchToken(Token.COLONCOLON))
- {
- decompiler.AddToken(Token.COLONCOLON);
- ns = name;
-
- int tt = nextToken();
- switch (tt)
- {
-
- // handles name::name
- case Token.NAME:
- name = ts.String;
- decompiler.AddName(name);
- break;
-
- // handles name::*
-
- case Token.MUL:
- decompiler.AddName("*");
- name = "*";
- break;
-
- // handles name::[expr]
-
- case Token.LB:
- decompiler.AddToken(Token.LB);
- pn = nf.CreateElementGet(pn, ns, expr(false), memberTypeFlags);
- mustMatchToken(Token.RB, "msg.no.bracket.index");
- decompiler.AddToken(Token.RB);
- return pn;
-
-
- default:
- ReportError("msg.no.name.after.coloncolon");
- name = "?";
- break;
-
- }
- }
-
- pn = nf.CreatePropertyGet(pn, ns, name, memberTypeFlags);
- return pn;
- }
-
- int currentStackIndex = 0;
-
-
- Node primaryExpr()
- {
- try
- {
- if (currentStackIndex++ > ScriptRuntime.MAXSTACKSIZE)
- {
- currentStackIndex = 0;
- throw Context.ReportRuntimeError(
- ScriptRuntime.GetMessage("mag.too.deep.parser.recursion"), sourceURI, ts.Lineno, null, 0);
- }
-
- Node pn;
-
- int ttFlagged = nextFlaggedToken();
- int tt = ttFlagged & CLEAR_TI_MASK;
-
- switch (tt)
- {
-
-
- case Token.FUNCTION:
- return function(FunctionNode.FUNCTION_EXPRESSION);
-
-
- case Token.LB:
- {
- ObjArray elems = new ObjArray();
- int skipCount = 0;
- decompiler.AddToken(Token.LB);
- bool after_lb_or_comma = true;
- for (; ; )
- {
- tt = peekToken();
-
- if (tt == Token.COMMA)
- {
- consumeToken();
- decompiler.AddToken(Token.COMMA);
- if (!after_lb_or_comma)
- {
- after_lb_or_comma = true;
- }
- else
- {
- elems.add((object)null);
- ++skipCount;
- }
- }
- else if (tt == Token.RB)
- {
- consumeToken();
- decompiler.AddToken(Token.RB);
- break;
- }
- else
- {
- if (!after_lb_or_comma)
- {
- ReportError("msg.no.bracket.arg");
- }
- elems.add(assignExpr(false));
- after_lb_or_comma = false;
- }
- }
- return nf.CreateArrayLiteral(elems, skipCount);
- }
-
-
- case Token.LC:
- {
- ObjArray elems = new ObjArray();
- decompiler.AddToken(Token.LC);
- if (!matchToken(Token.RC))
- {
-
- bool first = true;
- do
- {
- object property;
-
- if (!first)
- decompiler.AddToken(Token.COMMA);
- else
- first = false;
-
- tt = peekToken();
- switch (tt)
- {
-
- case Token.NAME:
- case Token.STRING:
- consumeToken();
- if (compilerEnv.getterAndSetterSupport)
- {
- if (tt == Token.NAME)
- if (CheckForGetOrSet(elems) || CheckForGetterOrSetter(elems))
- goto next_prop;
- }
-
-
- // map NAMEs to STRINGs in object literal context
- // but tell the decompiler the proper type
- string s = ts.String;
- if (tt == Token.NAME)
- {
- decompiler.AddName(s);
- }
- else
- {
- decompiler.AddString(s);
- }
- property = ScriptRuntime.getIndexObject(s);
-
- break;
-
-
- case Token.NUMBER:
- consumeToken();
- double n = ts.Number;
- decompiler.AddNumber(n);
- property = ScriptRuntime.getIndexObject(n);
- break;
-
-
- case Token.RC:
- // trailing comma is OK.
-
- goto commaloop_brk;
-
- default:
- ReportError("msg.bad.prop");
-
- goto commaloop_brk;
-
- }
- mustMatchToken(Token.COLON, "msg.no.colon.prop");
-
- // OBJLIT is used as ':' in object literal for
- // decompilation to solve spacing ambiguity.
- decompiler.AddToken(Token.OBJECTLIT);
- elems.add(property);
- elems.add(assignExpr(false));
-
- next_prop:
- ;
- }
- while (matchToken(Token.COMMA));
-
- commaloop_brk:
- ;
-
-
- mustMatchToken(Token.RC, "msg.no.brace.prop");
- }
- decompiler.AddToken(Token.RC);
- return nf.CreateObjectLiteral(elems);
- }
-
-
- case Token.LP:
-
- /* Brendan's IR-jsparse.c makes a new node tagged with
- * TOK_LP here... I'm not sure I understand why. Isn't
- * the grouping already implicit in the structure of the
- * parse tree? also TOK_LP is already overloaded (I
- * think) in the C IR as 'function call.' */
- decompiler.AddToken(Token.LP);
- pn = expr(false);
- decompiler.AddToken(Token.RP);
- mustMatchToken(Token.RP, "msg.no.paren");
- return pn;
-
-
- case Token.XMLATTR:
- mustHaveXML();
- decompiler.AddToken(Token.XMLATTR);
- pn = attributeAccess(null, 0);
- return pn;
-
-
- case Token.NAME:
- {
- string name = ts.String;
- if ((ttFlagged & TI_CHECK_LABEL) != 0)
- {
- if (peekToken() == Token.COLON)
- {
- // Do not consume colon, it is used as unwind indicator
- // to return to statementHelper.
- // TODO: Better way?
- return nf.CreateLabel(ts.Lineno);
- }
- }
-
- decompiler.AddName(name);
- if (compilerEnv.isXmlAvailable())
- {
- pn = propertyName(null, name, 0);
- }
- else
- {
- pn = nf.CreateName(name);
- }
- return pn;
- }
-
-
- case Token.NUMBER:
- {
- double n = ts.Number;
- decompiler.AddNumber(n);
- return nf.CreateNumber(n);
- }
-
-
- case Token.STRING:
- {
- string s = ts.String;
- decompiler.AddString(s);
- return nf.CreateString(s);
- }
-
-
- case Token.DIV:
- case Token.ASSIGN_DIV:
- {
- // Got / or /= which should be treated as regexp in fact
- ts.readRegExp(tt);
- string flags = ts.regExpFlags;
- ts.regExpFlags = null;
- string re = ts.String;
- decompiler.AddRegexp(re, flags);
- int index = currentScriptOrFn.addRegexp(re, flags);
- return nf.CreateRegExp(index);
- }
-
-
- case Token.NULL:
- case Token.THIS:
- case Token.FALSE:
- case Token.TRUE:
- decompiler.AddToken(tt);
- return nf.CreateLeaf(tt);
-
-
- case Token.RESERVED:
- ReportError("msg.reserved.id");
- break;
-
-
- case Token.ERROR:
- /* the scanner or one of its subroutines reported the error. */
- break;
-
-
- case Token.EOF:
- ReportError("msg.unexpected.eof");
- break;
-
-
- default:
- ReportError("msg.syntax");
- break;
-
- }
- return null; // should never reach here
- }
- finally
- {
- currentStackIndex--;
- }
- }
-
-
- ///
- /// Support for non-ecma "get"/"set" spidermonkey extension.
- ///
- ///
- /// get NAME () SCOPE
- /// set NAME () SCOPE
- ///
- bool CheckForGetOrSet(ObjArray elems)
- {
- int tt;
-
- string type = ts.String;
- if (type != "get" && type != "set")
- {
- return false;
- }
- tt = peekToken();
- if (tt != Token.NAME)
- return false;
- consumeToken();
-
- string name = ts.String;
-
- decompiler.AddName(name);
-
- Node func = function(FunctionNode.FUNCTION_EXPRESSION);
- object property = ScriptRuntime.getIndexObject(name);
-
- elems.add((type[0] == 'g') ? (object)new Node.GetterPropertyLiteral(property)
- : (object)new Node.SetterPropertyLiteral(property));
- elems.add(func);
-
- return true;
- }
-
- ///
- /// Support for non-ecma "get"/"set" spidermonkey extension.
- ///
- ///
- /// NAME getter: FUNCTION () SCOPE
- /// NAME setter: FUNCTION () SCOPE
- ///
- bool CheckForGetterOrSetter(ObjArray elems)
- {
- int tt;
-
- string name = ts.String;
- consumeToken();
-
- tt = peekToken();
- if (tt != Token.NAME)
- return false;
- string type = ts.String;
- if (type != "getter" && type != "setter")
- {
- return false;
- }
- consumeToken();
-
- matchToken(Token.COLON);
- matchToken(Token.FUNCTION);
-
- Node func = function(FunctionNode.FUNCTION_EXPRESSION);
- object property = ScriptRuntime.getIndexObject(name);
-
- elems.add((type[0] == 'g') ? (object)new Node.GetterPropertyLiteral(property)
- : (object)new Node.SetterPropertyLiteral(property));
- elems.add(func);
-
- return true;
- }
-
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+using System.Collections;
+using System.Text.RegularExpressions;
+using EcmaScript.NET.Collections;
+
+namespace EcmaScript.NET
+{
+
+ /// This class implements the JavaScript parser.
+ ///
+ /// It is based on the C source files jsparse.c and jsparse.h
+ /// in the jsref package.
+ ///
+ ///
+ public class Parser
+ {
+ public string EncodedSource
+ {
+ get
+ {
+ return encodedSource;
+ }
+
+ }
+ // TokenInformation flags : currentFlaggedToken stores them together
+ // with token type
+ internal const int CLEAR_TI_MASK = 0xFFFF;
+ internal const int TI_AFTER_EOL = 1 << 16;
+ internal const int TI_CHECK_LABEL = 1 << 17; // indicates to check for label
+ internal readonly Regex SIMPLE_IDENTIFIER_NAME_PATTERN = new Regex("^[a-zA-Z_][a-zA-Z0-9_]*$", RegexOptions.Compiled);
+
+ internal CompilerEnvirons compilerEnv;
+ ErrorReporter errorReporter;
+ string sourceURI;
+ internal bool calledByCompileFunction;
+
+ TokenStream ts;
+ int currentFlaggedToken;
+ int syntaxErrorCount;
+
+ NodeFactory nf;
+
+ int nestingOfFunction;
+
+ Decompiler decompiler;
+ string encodedSource;
+
+ // The following are per function variables and should be saved/restored
+ // during function parsing.
+ // TODO: Move to separated class?
+ internal ScriptOrFnNode currentScriptOrFn;
+ int nestingOfWith;
+ Hashtable labelSet; // map of label names into nodes
+ ObjArray loopSet;
+ ObjArray loopAndSwitchSet;
+ // end of per function variables
+
+ // Exception to unwind
+
+ class ParserException : Exception
+ {
+
+ }
+
+ public Parser(CompilerEnvirons compilerEnv, ErrorReporter errorReporter)
+ {
+ this.compilerEnv = compilerEnv;
+ this.errorReporter = errorReporter;
+ }
+
+ Decompiler CreateDecompiler(CompilerEnvirons compilerEnv)
+ {
+ return new Decompiler();
+ }
+
+ internal void AddWarning(string messageId, string messageArg)
+ {
+ string message = ScriptRuntime.GetMessage(messageId, messageArg);
+ errorReporter.Warning(message, sourceURI, ts.Lineno, ts.Line, ts.Offset);
+ }
+
+ internal void AddError(string messageId)
+ {
+ ++syntaxErrorCount;
+ string message = ScriptRuntime.GetMessage(messageId);
+ errorReporter.Error(message, sourceURI, ts.Lineno, ts.Line, ts.Offset);
+ }
+
+ internal Exception ReportError(string messageId)
+ {
+ AddError(messageId);
+
+ // Throw a ParserException exception to unwind the recursive descent
+ // parse.
+ throw new ParserException();
+ }
+
+ int peekToken()
+ {
+ int tt = currentFlaggedToken;
+ if (tt == Token.EOF)
+ {
+
+ while ((tt = ts.Token) == Token.CONDCOMMENT || tt == Token.KEEPCOMMENT)
+ {
+ if (tt == Token.CONDCOMMENT)
+ {
+ /* Support for JScript conditional comments */
+ decompiler.AddJScriptConditionalComment(ts.String);
+ }
+ else
+ {
+ /* Support for preserved comments */
+ decompiler.AddPreservedComment(ts.String);
+ }
+ }
+
+ if (tt == Token.EOL)
+ {
+ do
+ {
+ tt = ts.Token;
+
+ if (tt == Token.CONDCOMMENT)
+ {
+ /* Support for JScript conditional comments */
+ decompiler.AddJScriptConditionalComment(ts.String);
+ }
+ else if (tt == Token.KEEPCOMMENT)
+ {
+ /* Support for preserved comments */
+ decompiler.AddPreservedComment(ts.String);
+ }
+
+ }
+ while (tt == Token.EOL || tt == Token.CONDCOMMENT || tt == Token.KEEPCOMMENT);
+ tt |= TI_AFTER_EOL;
+ }
+ currentFlaggedToken = tt;
+ }
+ return tt & CLEAR_TI_MASK;
+ }
+
+ int peekFlaggedToken()
+ {
+ peekToken();
+ return currentFlaggedToken;
+ }
+
+ void consumeToken()
+ {
+ currentFlaggedToken = Token.EOF;
+ }
+
+ int nextToken()
+ {
+ int tt = peekToken();
+ consumeToken();
+ return tt;
+ }
+
+ int nextFlaggedToken()
+ {
+ peekToken();
+ int ttFlagged = currentFlaggedToken;
+ consumeToken();
+ return ttFlagged;
+ }
+
+ bool matchToken(int toMatch)
+ {
+ int tt = peekToken();
+ if (tt != toMatch)
+ {
+ return false;
+ }
+ consumeToken();
+ return true;
+ }
+
+ int peekTokenOrEOL()
+ {
+ int tt = peekToken();
+ // Check for last peeked token flags
+ if ((currentFlaggedToken & TI_AFTER_EOL) != 0)
+ {
+ tt = Token.EOL;
+ }
+ return tt;
+ }
+
+ void setCheckForLabel()
+ {
+ if ((currentFlaggedToken & CLEAR_TI_MASK) != Token.NAME)
+ throw Context.CodeBug();
+ currentFlaggedToken |= TI_CHECK_LABEL;
+ }
+
+ void mustMatchToken(int toMatch, string messageId)
+ {
+ if (!matchToken(toMatch))
+ {
+ ReportError(messageId);
+ }
+ }
+
+ void mustHaveXML()
+ {
+ if (!compilerEnv.isXmlAvailable())
+ {
+ ReportError("msg.XML.not.available");
+ }
+ }
+
+ public bool Eof
+ {
+ get
+ {
+ return ts.eof();
+ }
+ }
+
+ internal bool insideFunction()
+ {
+ return nestingOfFunction != 0;
+ }
+
+ Node enterLoop(Node loopLabel)
+ {
+ Node loop = nf.CreateLoopNode(loopLabel, ts.Lineno);
+ if (loopSet == null)
+ {
+ loopSet = new ObjArray();
+ if (loopAndSwitchSet == null)
+ {
+ loopAndSwitchSet = new ObjArray();
+ }
+ }
+ loopSet.push(loop);
+ loopAndSwitchSet.push(loop);
+ return loop;
+ }
+
+ void exitLoop()
+ {
+ loopSet.pop();
+ loopAndSwitchSet.pop();
+ }
+
+ Node enterSwitch(Node switchSelector, int lineno, Node switchLabel)
+ {
+ Node switchNode = nf.CreateSwitch(switchSelector, lineno);
+ if (loopAndSwitchSet == null)
+ {
+ loopAndSwitchSet = new ObjArray();
+ }
+ loopAndSwitchSet.push(switchNode);
+ return switchNode;
+ }
+
+ void exitSwitch()
+ {
+ loopAndSwitchSet.pop();
+ }
+
+ /*
+ * Build a parse tree from the given sourceString.
+ *
+ * @return an Object representing the parsed
+ * program. If the parse fails, null will be returned. (The
+ * parse failure will result in a call to the ErrorReporter from
+ * CompilerEnvirons.)
+ */
+ public ScriptOrFnNode Parse(string sourceString, string sourceURI, int lineno)
+ {
+ this.sourceURI = sourceURI;
+ this.ts = new TokenStream(this, null, sourceString, lineno);
+ try
+ {
+ return Parse();
+ }
+ catch (System.IO.IOException)
+ {
+ // Should never happen
+ throw new Exception();
+ }
+ }
+
+ /*
+ * Build a parse tree from the given sourceString.
+ *
+ * @return an Object representing the parsed
+ * program. If the parse fails, null will be returned. (The
+ * parse failure will result in a call to the ErrorReporter from
+ * CompilerEnvirons.)
+ */
+ public ScriptOrFnNode Parse(System.IO.StreamReader sourceReader, string sourceURI, int lineno)
+ {
+ this.sourceURI = sourceURI;
+ this.ts = new TokenStream(this, sourceReader, null, lineno);
+ return Parse();
+ }
+
+ ScriptOrFnNode Parse()
+ {
+ this.decompiler = CreateDecompiler(compilerEnv);
+ this.nf = new NodeFactory(this);
+ currentScriptOrFn = nf.CreateScript();
+ int sourceStartOffset = decompiler.CurrentOffset;
+ this.encodedSource = null;
+ decompiler.AddToken(Token.SCRIPT);
+
+ this.currentFlaggedToken = Token.EOF;
+ this.syntaxErrorCount = 0;
+
+ int baseLineno = ts.Lineno; // line number where source starts
+
+ /* so we have something to add nodes to until
+ * we've collected all the source */
+ Node pn = nf.CreateLeaf(Token.BLOCK);
+
+ for (; ; )
+ {
+ int tt = peekToken();
+
+ if (tt <= Token.EOF)
+ {
+ break;
+ }
+
+ Node n;
+ if (tt == Token.FUNCTION)
+ {
+ consumeToken();
+ try
+ {
+ n = function(calledByCompileFunction ? FunctionNode.FUNCTION_EXPRESSION : FunctionNode.FUNCTION_STATEMENT);
+ }
+ catch (ParserException)
+ {
+ break;
+ }
+ }
+ else
+ {
+ n = statement();
+ }
+ nf.addChildToBack(pn, n);
+ }
+
+ if (this.syntaxErrorCount != 0)
+ {
+ string msg = Convert.ToString(this.syntaxErrorCount);
+ msg = ScriptRuntime.GetMessage("msg.got.syntax.errors", msg);
+ throw errorReporter.RuntimeError(msg, sourceURI, baseLineno, null, 0);
+ }
+
+ currentScriptOrFn.SourceName = sourceURI;
+ currentScriptOrFn.BaseLineno = baseLineno;
+ currentScriptOrFn.EndLineno = ts.Lineno;
+
+ int sourceEndOffset = decompiler.CurrentOffset;
+ currentScriptOrFn.setEncodedSourceBounds(sourceStartOffset, sourceEndOffset);
+
+ nf.initScript(currentScriptOrFn, pn);
+
+ if (compilerEnv.isGeneratingSource())
+ {
+ encodedSource = decompiler.EncodedSource;
+ }
+ this.decompiler = null; // It helps GC
+
+ return currentScriptOrFn;
+ }
+
+ /*
+ * The C version of this function takes an argument list,
+ * which doesn't seem to be needed for tree generation...
+ * it'd only be useful for checking argument hiding, which
+ * I'm not doing anyway...
+ */
+ Node parseFunctionBody()
+ {
+ ++nestingOfFunction;
+ Node pn = nf.CreateBlock(ts.Lineno);
+ try
+ {
+ for (; ; )
+ {
+ Node n;
+ int tt = peekToken();
+ switch (tt)
+ {
+
+ case Token.ERROR:
+ case Token.EOF:
+ case Token.RC:
+
+ goto bodyLoop_brk;
+
+
+ case Token.FUNCTION:
+ consumeToken();
+ n = function(FunctionNode.FUNCTION_STATEMENT);
+ break;
+
+ default:
+ n = statement();
+ break;
+
+ }
+ nf.addChildToBack(pn, n);
+ }
+
+ bodyLoop_brk:
+ ;
+
+ }
+ catch (ParserException)
+ {
+ // Ignore it
+ }
+ finally
+ {
+ --nestingOfFunction;
+ }
+
+ return pn;
+ }
+
+ Node function(int functionType)
+ {
+ using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier(1024))
+ {
+ int syntheticType = functionType;
+ int baseLineno = ts.Lineno; // line number where source starts
+
+ int functionSourceStart = decompiler.MarkFunctionStart(functionType);
+ string name;
+ Node memberExprNode = null;
+ if (matchToken(Token.NAME))
+ {
+ name = ts.String;
+ decompiler.AddName(name);
+ if (!matchToken(Token.LP))
+ {
+ if (compilerEnv.isAllowMemberExprAsFunctionName())
+ {
+ // Extension to ECMA: if 'function ' does not follow
+ // by '(', assume starts memberExpr
+ Node memberExprHead = nf.CreateName(name);
+ name = "";
+ memberExprNode = memberExprTail(false, memberExprHead);
+ }
+ mustMatchToken(Token.LP, "msg.no.paren.parms");
+ }
+ }
+ else if (matchToken(Token.LP))
+ {
+ // Anonymous function
+ name = "";
+ }
+ else
+ {
+ name = "";
+ if (compilerEnv.isAllowMemberExprAsFunctionName())
+ {
+ // Note that memberExpr can not start with '(' like
+ // in function (1+2).toString(), because 'function (' already
+ // processed as anonymous function
+ memberExprNode = memberExpr(false);
+ }
+ mustMatchToken(Token.LP, "msg.no.paren.parms");
+ }
+
+ if (memberExprNode != null)
+ {
+ syntheticType = FunctionNode.FUNCTION_EXPRESSION;
+ }
+
+ bool nested = insideFunction();
+
+ FunctionNode fnNode = nf.CreateFunction(name);
+ if (nested || nestingOfWith > 0)
+ {
+ // 1. Nested functions are not affected by the dynamic scope flag
+ // as dynamic scope is already a parent of their scope.
+ // 2. Functions defined under the with statement also immune to
+ // this setup, in which case dynamic scope is ignored in favor
+ // of with object.
+ fnNode.itsIgnoreDynamicScope = true;
+ }
+
+ int functionIndex = currentScriptOrFn.addFunction(fnNode);
+
+ int functionSourceEnd;
+
+ ScriptOrFnNode savedScriptOrFn = currentScriptOrFn;
+ currentScriptOrFn = fnNode;
+ int savedNestingOfWith = nestingOfWith;
+ nestingOfWith = 0;
+ Hashtable savedLabelSet = labelSet;
+ labelSet = null;
+ ObjArray savedLoopSet = loopSet;
+ loopSet = null;
+ ObjArray savedLoopAndSwitchSet = loopAndSwitchSet;
+ loopAndSwitchSet = null;
+
+ Node body;
+ try
+ {
+ decompiler.AddToken(Token.LP);
+ if (!matchToken(Token.RP))
+ {
+ bool first = true;
+ do
+ {
+ if (!first)
+ decompiler.AddToken(Token.COMMA);
+ first = false;
+ mustMatchToken(Token.NAME, "msg.no.parm");
+ string s = ts.String;
+ if (fnNode.hasParamOrVar(s))
+ {
+ AddWarning("msg.dup.parms", s);
+ }
+ fnNode.addParam(s);
+ decompiler.AddName(s);
+ }
+ while (matchToken(Token.COMMA));
+
+ mustMatchToken(Token.RP, "msg.no.paren.after.parms");
+ }
+ decompiler.AddToken(Token.RP);
+
+ mustMatchToken(Token.LC, "msg.no.brace.body");
+ decompiler.AddEol(Token.LC);
+ body = parseFunctionBody();
+ mustMatchToken(Token.RC, "msg.no.brace.after.body");
+
+ decompiler.AddToken(Token.RC);
+ functionSourceEnd = decompiler.MarkFunctionEnd(functionSourceStart);
+ if (functionType != FunctionNode.FUNCTION_EXPRESSION)
+ {
+ if (compilerEnv.LanguageVersion >= Context.Versions.JS1_2)
+ {
+ // function f() {} function g() {} is not allowed in 1.2
+ // or later but for compatibility with old scripts
+ // the check is done only if language is
+ // explicitly set.
+ // TODO: warning needed if version == VERSION_DEFAULT ?
+ int tt = peekTokenOrEOL();
+ if (tt == Token.FUNCTION)
+ {
+ ReportError("msg.no.semi.stmt");
+ }
+ }
+ // Add EOL only if function is not part of expression
+ // since it gets SEMI + EOL from Statement in that case
+ decompiler.AddToken(Token.EOL);
+ }
+ }
+ finally
+ {
+ loopAndSwitchSet = savedLoopAndSwitchSet;
+ loopSet = savedLoopSet;
+ labelSet = savedLabelSet;
+ nestingOfWith = savedNestingOfWith;
+ currentScriptOrFn = savedScriptOrFn;
+ }
+
+ fnNode.setEncodedSourceBounds(functionSourceStart, functionSourceEnd);
+ fnNode.SourceName = sourceURI;
+ fnNode.BaseLineno = baseLineno;
+ fnNode.EndLineno = ts.Lineno;
+
+ Node pn = nf.initFunction(fnNode, functionIndex, body, syntheticType);
+ if (memberExprNode != null)
+ {
+ pn = nf.CreateAssignment(Token.ASSIGN, memberExprNode, pn);
+ if (functionType != FunctionNode.FUNCTION_EXPRESSION)
+ {
+ // TOOD: check JScript behavior: should it be createExprStatement?
+ pn = nf.CreateExprStatementNoReturn(pn, baseLineno);
+ }
+ }
+ return pn;
+ }
+ }
+
+ Node statements()
+ {
+ Node pn = nf.CreateBlock(ts.Lineno);
+
+ int tt;
+ while ((tt = peekToken()) > Token.EOF && tt != Token.RC)
+ {
+ nf.addChildToBack(pn, statement());
+ }
+
+ return pn;
+ }
+
+ Node condition()
+ {
+ Node pn;
+ mustMatchToken(Token.LP, "msg.no.paren.cond");
+ decompiler.AddToken(Token.LP);
+ pn = expr(false);
+ mustMatchToken(Token.RP, "msg.no.paren.after.cond");
+ decompiler.AddToken(Token.RP);
+
+ // there's a check here in jsparse.c that corrects = to ==
+
+ return pn;
+ }
+
+ // match a NAME; return null if no match.
+ Node matchJumpLabelName()
+ {
+ Node label = null;
+
+ int tt = peekTokenOrEOL();
+ if (tt == Token.NAME)
+ {
+ consumeToken();
+ string name = ts.String;
+ decompiler.AddName(name);
+ if (labelSet != null)
+ {
+ label = (Node)labelSet[name];
+ }
+ if (label == null)
+ {
+ ReportError("msg.undef.label");
+ }
+ }
+
+ return label;
+ }
+
+ Node statement()
+ {
+ using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier(512))
+ {
+ try
+ {
+ Node pn = statementHelper(null);
+ if (pn != null)
+ {
+ return pn;
+ }
+ }
+ catch (ParserException)
+ {
+ }
+ }
+
+ // skip to end of statement
+ int lineno = ts.Lineno;
+ for (; ; )
+ {
+ int tt = peekTokenOrEOL();
+ consumeToken();
+ switch (tt)
+ {
+
+ case Token.ERROR:
+ case Token.EOF:
+ case Token.EOL:
+ case Token.SEMI:
+
+ goto guessingStatementEnd_brk;
+ }
+ }
+
+ guessingStatementEnd_brk:
+ ;
+
+ return nf.CreateExprStatement(nf.CreateName("error"), lineno);
+ }
+
+ /// Whether the "catch (e: e instanceof Exception) { ... }" syntax
+ /// is implemented.
+ ///
+
+ Node statementHelper(Node statementLabel)
+ {
+ Node pn = null;
+
+ int tt;
+
+ tt = peekToken();
+
+ switch (tt)
+ {
+
+ case Token.IF:
+ {
+ consumeToken();
+
+ decompiler.AddToken(Token.IF);
+ int lineno = ts.Lineno;
+ Node cond = condition();
+ decompiler.AddEol(Token.LC);
+ Node ifTrue = statement();
+ Node ifFalse = null;
+ if (matchToken(Token.ELSE))
+ {
+ decompiler.AddToken(Token.RC);
+ decompiler.AddToken(Token.ELSE);
+ decompiler.AddEol(Token.LC);
+ ifFalse = statement();
+ }
+ decompiler.AddEol(Token.RC);
+ pn = nf.CreateIf(cond, ifTrue, ifFalse, lineno);
+ return pn;
+ }
+
+
+ case Token.SWITCH:
+ {
+ consumeToken();
+
+ decompiler.AddToken(Token.SWITCH);
+ int lineno = ts.Lineno;
+ mustMatchToken(Token.LP, "msg.no.paren.switch");
+ decompiler.AddToken(Token.LP);
+ pn = enterSwitch(expr(false), lineno, statementLabel);
+ try
+ {
+ mustMatchToken(Token.RP, "msg.no.paren.after.switch");
+ decompiler.AddToken(Token.RP);
+ mustMatchToken(Token.LC, "msg.no.brace.switch");
+ decompiler.AddEol(Token.LC);
+
+ bool hasDefault = false;
+ for (; ; )
+ {
+ tt = nextToken();
+ Node caseExpression;
+ switch (tt)
+ {
+
+ case Token.RC:
+
+ goto switchLoop_brk;
+
+
+ case Token.CASE:
+ decompiler.AddToken(Token.CASE);
+ caseExpression = expr(false);
+ mustMatchToken(Token.COLON, "msg.no.colon.case");
+ decompiler.AddEol(Token.COLON);
+ break;
+
+
+ case Token.DEFAULT:
+ if (hasDefault)
+ {
+ ReportError("msg.double.switch.default");
+ }
+ decompiler.AddToken(Token.DEFAULT);
+ hasDefault = true;
+ caseExpression = null;
+ mustMatchToken(Token.COLON, "msg.no.colon.case");
+ decompiler.AddEol(Token.COLON);
+ break;
+
+
+ default:
+ ReportError("msg.bad.switch");
+
+ goto switchLoop_brk;
+
+ }
+
+ Node block = nf.CreateLeaf(Token.BLOCK);
+ while ((tt = peekToken()) != Token.RC && tt != Token.CASE && tt != Token.DEFAULT && tt != Token.EOF)
+ {
+ nf.addChildToBack(block, statement());
+ }
+
+ // caseExpression == null => add default lable
+ nf.addSwitchCase(pn, caseExpression, block);
+ }
+
+ switchLoop_brk:
+ ;
+
+ decompiler.AddEol(Token.RC);
+ nf.closeSwitch(pn);
+ }
+ finally
+ {
+ exitSwitch();
+ }
+ return pn;
+ }
+
+
+ case Token.WHILE:
+ {
+ consumeToken();
+ decompiler.AddToken(Token.WHILE);
+
+ Node loop = enterLoop(statementLabel);
+ try
+ {
+ Node cond = condition();
+ decompiler.AddEol(Token.LC);
+ Node body = statement();
+ decompiler.AddEol(Token.RC);
+ pn = nf.CreateWhile(loop, cond, body);
+ }
+ finally
+ {
+ exitLoop();
+ }
+ return pn;
+ }
+
+
+ case Token.DO:
+ {
+ consumeToken();
+ decompiler.AddToken(Token.DO);
+ decompiler.AddEol(Token.LC);
+
+ Node loop = enterLoop(statementLabel);
+ try
+ {
+ Node body = statement();
+ decompiler.AddToken(Token.RC);
+ mustMatchToken(Token.WHILE, "msg.no.while.do");
+ decompiler.AddToken(Token.WHILE);
+ Node cond = condition();
+ pn = nf.CreateDoWhile(loop, body, cond);
+ }
+ finally
+ {
+ exitLoop();
+ }
+ // Always auto-insert semicon to follow SpiderMonkey:
+ // It is required by EMAScript but is ignored by the rest of
+ // world, see bug 238945
+ matchToken(Token.SEMI);
+ decompiler.AddEol(Token.SEMI);
+ return pn;
+ }
+
+
+ case Token.FOR:
+ {
+ consumeToken();
+ bool isForEach = false;
+ decompiler.AddToken(Token.FOR);
+
+ Node loop = enterLoop(statementLabel);
+ try
+ {
+
+ Node init; // Node init is also foo in 'foo in Object'
+ Node cond; // Node cond is also object in 'foo in Object'
+ Node incr = null; // to kill warning
+ Node body;
+
+ // See if this is a for each () instead of just a for ()
+ if (matchToken(Token.NAME))
+ {
+ decompiler.AddName(ts.String);
+ if (ts.String.Equals("each"))
+ {
+ isForEach = true;
+ }
+ else
+ {
+ ReportError("msg.no.paren.for");
+ }
+ }
+
+ mustMatchToken(Token.LP, "msg.no.paren.for");
+ decompiler.AddToken(Token.LP);
+ tt = peekToken();
+ if (tt == Token.SEMI)
+ {
+ init = nf.CreateLeaf(Token.EMPTY);
+ }
+ else
+ {
+ if (tt == Token.VAR)
+ {
+ // set init to a var list or initial
+ consumeToken(); // consume the 'var' token
+ init = variables(true);
+ }
+ else
+ {
+ init = expr(true);
+ }
+ }
+
+ if (matchToken(Token.IN))
+ {
+ decompiler.AddToken(Token.IN);
+ // 'cond' is the object over which we're iterating
+ cond = expr(false);
+ }
+ else
+ {
+ // ordinary for loop
+ mustMatchToken(Token.SEMI, "msg.no.semi.for");
+ decompiler.AddToken(Token.SEMI);
+ if (peekToken() == Token.SEMI)
+ {
+ // no loop condition
+ cond = nf.CreateLeaf(Token.EMPTY);
+ }
+ else
+ {
+ cond = expr(false);
+ }
+
+ mustMatchToken(Token.SEMI, "msg.no.semi.for.cond");
+ decompiler.AddToken(Token.SEMI);
+ if (peekToken() == Token.RP)
+ {
+ incr = nf.CreateLeaf(Token.EMPTY);
+ }
+ else
+ {
+ incr = expr(false);
+ }
+ }
+
+ mustMatchToken(Token.RP, "msg.no.paren.for.ctrl");
+ decompiler.AddToken(Token.RP);
+ decompiler.AddEol(Token.LC);
+ body = statement();
+ decompiler.AddEol(Token.RC);
+
+ if (incr == null)
+ {
+ // cond could be null if 'in obj' got eaten
+ // by the init node.
+ pn = nf.CreateForIn(loop, init, cond, body, isForEach);
+ }
+ else
+ {
+ pn = nf.CreateFor(loop, init, cond, incr, body);
+ }
+ }
+ finally
+ {
+ exitLoop();
+ }
+ return pn;
+ }
+
+
+ case Token.TRY:
+ {
+ consumeToken();
+ int lineno = ts.Lineno;
+
+ Node tryblock;
+ Node catchblocks = null;
+ Node finallyblock = null;
+
+ decompiler.AddToken(Token.TRY);
+ decompiler.AddEol(Token.LC);
+ tryblock = statement();
+ decompiler.AddEol(Token.RC);
+
+ catchblocks = nf.CreateLeaf(Token.BLOCK);
+
+ bool sawDefaultCatch = false;
+ int peek = peekToken();
+ if (peek == Token.CATCH)
+ {
+ while (matchToken(Token.CATCH))
+ {
+ if (sawDefaultCatch)
+ {
+ ReportError("msg.catch.unreachable");
+ }
+ decompiler.AddToken(Token.CATCH);
+ mustMatchToken(Token.LP, "msg.no.paren.catch");
+ decompiler.AddToken(Token.LP);
+
+ mustMatchToken(Token.NAME, "msg.bad.catchcond");
+ string varName = ts.String;
+ decompiler.AddName(varName);
+
+ Node catchCond = null;
+ if (matchToken(Token.IF))
+ {
+ decompiler.AddToken(Token.IF);
+ catchCond = expr(false);
+ }
+ else
+ {
+ sawDefaultCatch = true;
+ }
+
+ mustMatchToken(Token.RP, "msg.bad.catchcond");
+ decompiler.AddToken(Token.RP);
+ mustMatchToken(Token.LC, "msg.no.brace.catchblock");
+ decompiler.AddEol(Token.LC);
+
+ nf.addChildToBack(catchblocks, nf.CreateCatch(varName, catchCond, statements(), ts.Lineno));
+
+ mustMatchToken(Token.RC, "msg.no.brace.after.body");
+ decompiler.AddEol(Token.RC);
+ }
+ }
+ else if (peek != Token.FINALLY)
+ {
+ mustMatchToken(Token.FINALLY, "msg.try.no.catchfinally");
+ }
+
+ if (matchToken(Token.FINALLY))
+ {
+ decompiler.AddToken(Token.FINALLY);
+ decompiler.AddEol(Token.LC);
+ finallyblock = statement();
+ decompiler.AddEol(Token.RC);
+ }
+
+ pn = nf.CreateTryCatchFinally(tryblock, catchblocks, finallyblock, lineno);
+
+ return pn;
+ }
+
+
+ case Token.THROW:
+ {
+ consumeToken();
+ if (peekTokenOrEOL() == Token.EOL)
+ {
+ // ECMAScript does not allow new lines before throw expression,
+ // see bug 256617
+ ReportError("msg.bad.throw.eol");
+ }
+
+ int lineno = ts.Lineno;
+ decompiler.AddToken(Token.THROW);
+ pn = nf.CreateThrow(expr(false), lineno);
+ break;
+ }
+
+
+ case Token.BREAK:
+ {
+ consumeToken();
+ int lineno = ts.Lineno;
+
+ decompiler.AddToken(Token.BREAK);
+
+ // matchJumpLabelName only matches if there is one
+ Node breakStatement = matchJumpLabelName();
+ if (breakStatement == null)
+ {
+ if (loopAndSwitchSet == null || loopAndSwitchSet.size() == 0)
+ {
+ ReportError("msg.bad.break");
+ return null;
+ }
+ breakStatement = (Node)loopAndSwitchSet.peek();
+ }
+ pn = nf.CreateBreak(breakStatement, lineno);
+ break;
+ }
+
+
+ case Token.CONTINUE:
+ {
+ consumeToken();
+ int lineno = ts.Lineno;
+
+ decompiler.AddToken(Token.CONTINUE);
+
+ Node loop;
+ // matchJumpLabelName only matches if there is one
+ Node label = matchJumpLabelName();
+ if (label == null)
+ {
+ if (loopSet == null || loopSet.size() == 0)
+ {
+ ReportError("msg.continue.outside");
+ return null;
+ }
+ loop = (Node)loopSet.peek();
+ }
+ else
+ {
+ loop = nf.getLabelLoop(label);
+ if (loop == null)
+ {
+ ReportError("msg.continue.nonloop");
+ return null;
+ }
+ }
+ pn = nf.CreateContinue(loop, lineno);
+ break;
+ }
+
+
+ case Token.WITH:
+ {
+ consumeToken();
+
+ decompiler.AddToken(Token.WITH);
+ int lineno = ts.Lineno;
+ mustMatchToken(Token.LP, "msg.no.paren.with");
+ decompiler.AddToken(Token.LP);
+ Node obj = expr(false);
+ mustMatchToken(Token.RP, "msg.no.paren.after.with");
+ decompiler.AddToken(Token.RP);
+ decompiler.AddEol(Token.LC);
+
+ ++nestingOfWith;
+ Node body;
+ try
+ {
+ body = statement();
+ }
+ finally
+ {
+ --nestingOfWith;
+ }
+
+ decompiler.AddEol(Token.RC);
+
+ pn = nf.CreateWith(obj, body, lineno);
+ return pn;
+ }
+
+
+ case Token.VAR:
+ {
+ consumeToken();
+ pn = variables(false);
+ break;
+ }
+
+
+ case Token.RETURN:
+ {
+ if (!insideFunction())
+ {
+ ReportError("msg.bad.return");
+ }
+ consumeToken();
+ decompiler.AddToken(Token.RETURN);
+ int lineno = ts.Lineno;
+
+ Node retExpr;
+ /* This is ugly, but we don't want to require a semicolon. */
+ tt = peekTokenOrEOL();
+ switch (tt)
+ {
+
+ case Token.SEMI:
+ case Token.RC:
+ case Token.EOF:
+ case Token.EOL:
+ case Token.ERROR:
+ retExpr = null;
+ break;
+
+ default:
+ retExpr = expr(false);
+ break;
+
+ }
+ pn = nf.CreateReturn(retExpr, lineno);
+ break;
+ }
+
+ case Token.DEBUGGER:
+ consumeToken();
+ decompiler.AddToken(Token.DEBUGGER);
+ pn = nf.CreateDebugger(ts.Lineno);
+ break;
+
+ case Token.LC:
+ consumeToken();
+ if (statementLabel != null)
+ {
+ decompiler.AddToken(Token.LC);
+ }
+ pn = statements();
+ mustMatchToken(Token.RC, "msg.no.brace.block");
+ if (statementLabel != null)
+ {
+ decompiler.AddEol(Token.RC);
+ }
+ return pn;
+
+
+ case Token.ERROR:
+ // Fall thru, to have a node for error recovery to work on
+ case Token.SEMI:
+ consumeToken();
+ pn = nf.CreateLeaf(Token.EMPTY);
+ return pn;
+
+
+ case Token.FUNCTION:
+ {
+ consumeToken();
+ pn = function(FunctionNode.FUNCTION_EXPRESSION_STATEMENT);
+ return pn;
+ }
+
+
+ case Token.DEFAULT:
+ consumeToken();
+ mustHaveXML();
+
+ decompiler.AddToken(Token.DEFAULT);
+ int nsLine = ts.Lineno;
+
+ if (!(matchToken(Token.NAME) && ts.String.Equals("xml")))
+ {
+ ReportError("msg.bad.namespace");
+ }
+ decompiler.AddName(ts.String);
+
+ if (!(matchToken(Token.NAME) && ts.String.Equals("namespace")))
+ {
+ ReportError("msg.bad.namespace");
+ }
+ decompiler.AddName(ts.String);
+
+ if (!matchToken(Token.ASSIGN))
+ {
+ ReportError("msg.bad.namespace");
+ }
+ decompiler.AddToken(Token.ASSIGN);
+
+ Node e = expr(false);
+ pn = nf.CreateDefaultNamespace(e, nsLine);
+ break;
+
+
+ case Token.NAME:
+ {
+ int lineno = ts.Lineno;
+ string name = ts.String;
+ setCheckForLabel();
+ pn = expr(false);
+ if (pn.Type != Token.LABEL)
+ {
+
+ if (compilerEnv.getterAndSetterSupport)
+ {
+ tt = peekToken();
+ if (tt == Token.NAME)
+ {
+ if (ts.String == "getter" || ts.String == "setter")
+ {
+ pn.Type = (ts.String[0] == 'g' ? Token.SETPROP_GETTER
+ : Token.SETPROP_SETTER);
+ decompiler.AddName(" " + ts.String); // HACK: Hack (whitespace) for decmpiler
+ consumeToken();
+ matchToken(Token.ASSIGN);
+ decompiler.AddToken(Token.ASSIGN);
+ matchToken(Token.FUNCTION);
+ Node fn = function(FunctionNode.FUNCTION_EXPRESSION);
+ pn.addChildToBack(fn);
+ }
+ }
+ }
+ pn = nf.CreateExprStatement(pn, lineno);
+ }
+ else
+ {
+ // Parsed the label: push back token should be
+ // colon that primaryExpr left untouched.
+ if (peekToken() != Token.COLON)
+ Context.CodeBug();
+ consumeToken();
+ // depend on decompiling lookahead to guess that that
+ // last name was a label.
+ decompiler.AddName(name);
+ decompiler.AddEol(Token.COLON);
+
+ if (labelSet == null)
+ {
+ labelSet = Hashtable.Synchronized(new Hashtable());
+ }
+ else if (labelSet.ContainsKey(name))
+ {
+ ReportError("msg.dup.label");
+ }
+
+ bool firstLabel;
+ if (statementLabel == null)
+ {
+ firstLabel = true;
+ statementLabel = pn;
+ }
+ else
+ {
+ // Discard multiple label nodes and use only
+ // the first: it allows to simplify IRFactory
+ firstLabel = false;
+ }
+ labelSet[name] = statementLabel;
+ try
+ {
+ pn = statementHelper(statementLabel);
+ }
+ finally
+ {
+ labelSet.Remove(name);
+ }
+ if (firstLabel)
+ {
+ pn = nf.CreateLabeledStatement(statementLabel, pn);
+ }
+ return pn;
+ }
+ break;
+ }
+
+
+ default:
+ {
+ int lineno = ts.Lineno;
+ pn = expr(false);
+ pn = nf.CreateExprStatement(pn, lineno);
+ break;
+ }
+
+ }
+
+ // FINDME
+
+ int ttFlagged = peekFlaggedToken();
+ switch (ttFlagged & CLEAR_TI_MASK)
+ {
+
+ case Token.SEMI:
+ // Consume ';' as a part of expression
+ consumeToken();
+ break;
+
+ case Token.ERROR:
+ case Token.EOF:
+ case Token.RC:
+ // Autoinsert ;
+ break;
+
+ default:
+ if ((ttFlagged & TI_AFTER_EOL) == 0)
+ {
+ // Report error if no EOL or autoinsert ; otherwise
+ ReportError("msg.no.semi.stmt");
+ }
+ break;
+
+ }
+ decompiler.AddEol(Token.SEMI);
+
+ return pn;
+ }
+
+ Node variables(bool inForInit)
+ {
+ Node pn = nf.CreateVariables(ts.Lineno);
+ bool first = true;
+
+ decompiler.AddToken(Token.VAR);
+
+ for (; ; )
+ {
+ Node name;
+ Node init;
+ mustMatchToken(Token.NAME, "msg.bad.var");
+ string s = ts.String;
+
+ if (!first)
+ decompiler.AddToken(Token.COMMA);
+ first = false;
+
+ decompiler.AddName(s);
+ currentScriptOrFn.addVar(s);
+ name = nf.CreateName(s);
+
+ // omitted check for argument hiding
+
+ if (matchToken(Token.ASSIGN))
+ {
+ decompiler.AddToken(Token.ASSIGN);
+
+ init = assignExpr(inForInit);
+ nf.addChildToBack(name, init);
+ }
+ nf.addChildToBack(pn, name);
+ if (!matchToken(Token.COMMA))
+ break;
+ }
+ return pn;
+ }
+
+ Node expr(bool inForInit)
+ {
+ Node pn = assignExpr(inForInit);
+ while (matchToken(Token.COMMA))
+ {
+ decompiler.AddToken(Token.COMMA);
+ pn = nf.CreateBinary(Token.COMMA, pn, assignExpr(inForInit));
+ }
+ return pn;
+ }
+
+ Node assignExpr(bool inForInit)
+ {
+ Node pn = condExpr(inForInit);
+
+ int tt = peekToken();
+ if (Token.FIRST_ASSIGN <= tt && tt <= Token.LAST_ASSIGN)
+ {
+ consumeToken();
+ decompiler.AddToken(tt);
+ pn = nf.CreateAssignment(tt, pn, assignExpr(inForInit));
+ }
+
+ return pn;
+ }
+
+ Node condExpr(bool inForInit)
+ {
+ Node ifTrue;
+ Node ifFalse;
+
+ Node pn = orExpr(inForInit);
+
+ if (matchToken(Token.HOOK))
+ {
+ decompiler.AddToken(Token.HOOK);
+ ifTrue = assignExpr(false);
+ mustMatchToken(Token.COLON, "msg.no.colon.cond");
+ decompiler.AddToken(Token.COLON);
+ ifFalse = assignExpr(inForInit);
+ return nf.CreateCondExpr(pn, ifTrue, ifFalse);
+ }
+
+ return pn;
+ }
+
+ Node orExpr(bool inForInit)
+ {
+ Node pn = andExpr(inForInit);
+ if (matchToken(Token.OR))
+ {
+ decompiler.AddToken(Token.OR);
+ pn = nf.CreateBinary(Token.OR, pn, orExpr(inForInit));
+ }
+
+ return pn;
+ }
+
+ Node andExpr(bool inForInit)
+ {
+ Node pn = bitOrExpr(inForInit);
+ if (matchToken(Token.AND))
+ {
+ decompiler.AddToken(Token.AND);
+ pn = nf.CreateBinary(Token.AND, pn, andExpr(inForInit));
+ }
+
+ return pn;
+ }
+
+ Node bitOrExpr(bool inForInit)
+ {
+ Node pn = bitXorExpr(inForInit);
+ while (matchToken(Token.BITOR))
+ {
+ decompiler.AddToken(Token.BITOR);
+ pn = nf.CreateBinary(Token.BITOR, pn, bitXorExpr(inForInit));
+ }
+ return pn;
+ }
+
+ Node bitXorExpr(bool inForInit)
+ {
+ Node pn = bitAndExpr(inForInit);
+ while (matchToken(Token.BITXOR))
+ {
+ decompiler.AddToken(Token.BITXOR);
+ pn = nf.CreateBinary(Token.BITXOR, pn, bitAndExpr(inForInit));
+ }
+ return pn;
+ }
+
+ Node bitAndExpr(bool inForInit)
+ {
+ Node pn = eqExpr(inForInit);
+ while (matchToken(Token.BITAND))
+ {
+ decompiler.AddToken(Token.BITAND);
+ pn = nf.CreateBinary(Token.BITAND, pn, eqExpr(inForInit));
+ }
+ return pn;
+ }
+
+ Node eqExpr(bool inForInit)
+ {
+ Node pn = relExpr(inForInit);
+ for (; ; )
+ {
+ int tt = peekToken();
+ switch (tt)
+ {
+
+ case Token.EQ:
+ case Token.NE:
+ case Token.SHEQ:
+ case Token.SHNE:
+ consumeToken();
+ int decompilerToken = tt;
+ int parseToken = tt;
+ if (compilerEnv.LanguageVersion == Context.Versions.JS1_2)
+ {
+ // JavaScript 1.2 uses shallow equality for == and != .
+ // In addition, convert === and !== for decompiler into
+ // == and != since the decompiler is supposed to show
+ // canonical source and in 1.2 ===, !== are allowed
+ // only as an alias to ==, !=.
+ switch (tt)
+ {
+
+ case Token.EQ:
+ parseToken = Token.SHEQ;
+ break;
+
+ case Token.NE:
+ parseToken = Token.SHNE;
+ break;
+
+ case Token.SHEQ:
+ decompilerToken = Token.EQ;
+ break;
+
+ case Token.SHNE:
+ decompilerToken = Token.NE;
+ break;
+ }
+ }
+ decompiler.AddToken(decompilerToken);
+ pn = nf.CreateBinary(parseToken, pn, relExpr(inForInit));
+ continue;
+ }
+ break;
+ }
+ return pn;
+ }
+
+ Node relExpr(bool inForInit)
+ {
+ Node pn = shiftExpr();
+ for (; ; )
+ {
+ int tt = peekToken();
+ switch (tt)
+ {
+
+ case Token.IN:
+ if (inForInit)
+ break;
+ // fall through
+ goto case Token.INSTANCEOF;
+
+ case Token.INSTANCEOF:
+ case Token.LE:
+ case Token.LT:
+ case Token.GE:
+ case Token.GT:
+ consumeToken();
+ decompiler.AddToken(tt);
+ pn = nf.CreateBinary(tt, pn, shiftExpr());
+ continue;
+ }
+ break;
+ }
+ return pn;
+ }
+
+ Node shiftExpr()
+ {
+ Node pn = addExpr();
+ for (; ; )
+ {
+ int tt = peekToken();
+ switch (tt)
+ {
+
+ case Token.LSH:
+ case Token.URSH:
+ case Token.RSH:
+ consumeToken();
+ decompiler.AddToken(tt);
+ pn = nf.CreateBinary(tt, pn, addExpr());
+ continue;
+ }
+ break;
+ }
+ return pn;
+ }
+
+ Node addExpr()
+ {
+ Node pn = mulExpr();
+ for (; ; )
+ {
+ int tt = peekToken();
+ if (tt == Token.ADD || tt == Token.SUB)
+ {
+ consumeToken();
+ decompiler.AddToken(tt);
+ // flushNewLines
+ pn = nf.CreateBinary(tt, pn, mulExpr());
+ continue;
+ }
+ break;
+ }
+
+ return pn;
+ }
+
+ Node mulExpr()
+ {
+ Node pn = unaryExpr();
+ for (; ; )
+ {
+ int tt = peekToken();
+ switch (tt)
+ {
+
+ case Token.MUL:
+ case Token.DIV:
+ case Token.MOD:
+ consumeToken();
+ decompiler.AddToken(tt);
+ pn = nf.CreateBinary(tt, pn, unaryExpr());
+ continue;
+ }
+ break;
+ }
+
+ return pn;
+ }
+
+ Node unaryExpr()
+ {
+ using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier(4096))
+ {
+ int tt;
+
+ tt = peekToken();
+
+ switch (tt)
+ {
+
+ case Token.VOID:
+ case Token.NOT:
+ case Token.BITNOT:
+ case Token.TYPEOF:
+ consumeToken();
+ decompiler.AddToken(tt);
+ return nf.CreateUnary(tt, unaryExpr());
+
+
+ case Token.ADD:
+ consumeToken();
+ // Convert to special POS token in decompiler and parse tree
+ decompiler.AddToken(Token.POS);
+ return nf.CreateUnary(Token.POS, unaryExpr());
+
+
+ case Token.SUB:
+ consumeToken();
+ // Convert to special NEG token in decompiler and parse tree
+ decompiler.AddToken(Token.NEG);
+ return nf.CreateUnary(Token.NEG, unaryExpr());
+
+
+ case Token.INC:
+ case Token.DEC:
+ consumeToken();
+ decompiler.AddToken(tt);
+ return nf.CreateIncDec(tt, false, memberExpr(true));
+
+
+ case Token.DELPROP:
+ consumeToken();
+ decompiler.AddToken(Token.DELPROP);
+ return nf.CreateUnary(Token.DELPROP, unaryExpr());
+
+
+ case Token.ERROR:
+ consumeToken();
+ break;
+
+ // XML stream encountered in expression.
+
+ case Token.LT:
+ if (compilerEnv.isXmlAvailable())
+ {
+ consumeToken();
+ Node pn = xmlInitializer();
+ return memberExprTail(true, pn);
+ }
+ // Fall thru to the default handling of RELOP
+ goto default;
+
+
+ default:
+ {
+ Node pn = memberExpr(true);
+
+ // Don't look across a newline boundary for a postfix incop.
+ tt = peekTokenOrEOL();
+ if (tt == Token.INC || tt == Token.DEC)
+ {
+ consumeToken();
+ decompiler.AddToken(tt);
+ return nf.CreateIncDec(tt, true, pn);
+ }
+ return pn;
+ }
+
+ }
+ return nf.CreateName("err"); // Only reached on error. Try to continue.
+ }
+ }
+
+ Node xmlInitializer()
+ {
+ int tt = ts.FirstXMLToken;
+ if (tt != Token.XML && tt != Token.XMLEND)
+ {
+ ReportError("msg.syntax");
+ return null;
+ }
+
+ /* Make a NEW node to append to. */
+ Node pnXML = nf.CreateLeaf(Token.NEW);
+ decompiler.AddToken(Token.NEW);
+ decompiler.AddToken(Token.DOT);
+
+ string xml = ts.String;
+ bool fAnonymous = xml.Trim().StartsWith("<>");
+
+ decompiler.AddName(fAnonymous ? "XMLList" : "XML");
+ Node pn = nf.CreateName(fAnonymous ? "XMLList" : "XML");
+ nf.addChildToBack(pnXML, pn);
+
+ pn = null;
+ Node e;
+ for (; ; tt = ts.NextXMLToken)
+ {
+ switch (tt)
+ {
+
+ case Token.XML:
+ xml = ts.String;
+ decompiler.AddString(xml);
+ mustMatchToken(Token.LC, "msg.syntax");
+ decompiler.AddToken(Token.LC);
+ e = (peekToken() == Token.RC) ? nf.CreateString("") : expr(false);
+ mustMatchToken(Token.RC, "msg.syntax");
+ decompiler.AddToken(Token.RC);
+ if (pn == null)
+ {
+ pn = nf.CreateString(xml);
+ }
+ else
+ {
+ pn = nf.CreateBinary(Token.ADD, pn, nf.CreateString(xml));
+ }
+ int nodeType;
+ if (ts.XMLAttribute)
+ {
+ nodeType = Token.ESCXMLATTR;
+ }
+ else
+ {
+ nodeType = Token.ESCXMLTEXT;
+ }
+ e = nf.CreateUnary(nodeType, e);
+ pn = nf.CreateBinary(Token.ADD, pn, e);
+ break;
+
+ case Token.XMLEND:
+ xml = ts.String;
+ decompiler.AddString(xml);
+ if (pn == null)
+ {
+ pn = nf.CreateString(xml);
+ }
+ else
+ {
+ pn = nf.CreateBinary(Token.ADD, pn, nf.CreateString(xml));
+ }
+
+ nf.addChildToBack(pnXML, pn);
+ return pnXML;
+
+ default:
+ ReportError("msg.syntax");
+ return null;
+
+ }
+ }
+ }
+
+ void argumentList(Node listNode)
+ {
+ bool matched;
+ matched = matchToken(Token.RP);
+ if (!matched)
+ {
+ bool first = true;
+ do
+ {
+ if (!first)
+ decompiler.AddToken(Token.COMMA);
+ first = false;
+ nf.addChildToBack(listNode, assignExpr(false));
+ }
+ while (matchToken(Token.COMMA));
+
+ mustMatchToken(Token.RP, "msg.no.paren.arg");
+ }
+ decompiler.AddToken(Token.RP);
+ }
+
+ Node memberExpr(bool allowCallSyntax)
+ {
+ int tt;
+
+ Node pn;
+
+ /* Check for new expressions. */
+ tt = peekToken();
+ if (tt == Token.NEW)
+ {
+ /* Eat the NEW token. */
+ consumeToken();
+ decompiler.AddToken(Token.NEW);
+
+ /* Make a NEW node to append to. */
+ pn = nf.CreateCallOrNew(Token.NEW, memberExpr(false));
+
+ if (matchToken(Token.LP))
+ {
+ decompiler.AddToken(Token.LP);
+ /* Add the arguments to pn, if any are supplied. */
+ argumentList(pn);
+ }
+
+ // TODO: there's a check in the C source against
+ // TODO: "too many constructor arguments" - how many
+ // TODO: do we claim to support?
+
+ /* Experimental syntax: allow an object literal to follow a new expression,
+ * which will mean a kind of anonymous class built with the JavaAdapter.
+ * the object literal will be passed as an additional argument to the constructor.
+ */
+ tt = peekToken();
+ if (tt == Token.LC)
+ {
+ nf.addChildToBack(pn, primaryExpr());
+ }
+ }
+ else
+ {
+ pn = primaryExpr();
+ }
+
+ return memberExprTail(allowCallSyntax, pn);
+ }
+
+ Node memberExprTail(bool allowCallSyntax, Node pn)
+ {
+ for (; ; )
+ {
+ int tt = peekToken();
+ switch (tt)
+ {
+
+
+ case Token.DOT:
+ case Token.DOTDOT:
+ {
+ int memberTypeFlags;
+ string s;
+ Match match;
+
+ consumeToken();
+ decompiler.AddToken(tt);
+ memberTypeFlags = 0;
+ if (tt == Token.DOTDOT)
+ {
+ mustHaveXML();
+ memberTypeFlags = Node.DESCENDANTS_FLAG;
+ }
+ if (!compilerEnv.isXmlAvailable())
+ {
+ mustMatchToken(Token.NAME, "msg.no.name.after.dot");
+ s = ts.String;
+ decompiler.AddName(s);
+ pn = nf.CreatePropertyGet(pn, null, s, memberTypeFlags);
+ break;
+ }
+
+
+ tt = nextToken();
+
+ switch (tt)
+ {
+
+ // handles: name, ns::name, ns::*, ns::[expr]
+ case Token.NAME:
+ s = ts.String;
+ decompiler.AddName(s);
+ pn = propertyName(pn, s, memberTypeFlags);
+ break;
+
+ // handles: *, *::name, *::*, *::[expr]
+
+ case Token.MUL:
+ decompiler.AddName("*");
+ pn = propertyName(pn, "*", memberTypeFlags);
+ break;
+
+ // handles: '@attr', '@ns::attr', '@ns::*', '@ns::*',
+ // '@::attr', '@::*', '@*', '@*::attr', '@*::*'
+
+ case Token.XMLATTR:
+ decompiler.AddToken(Token.XMLATTR);
+ pn = attributeAccess(pn, memberTypeFlags);
+ break;
+
+
+ default:
+
+
+ s = ts.TokenString;
+ match = SIMPLE_IDENTIFIER_NAME_PATTERN.Match(s);
+ if (match.Success)
+ {
+ decompiler.AddName(s);
+ pn = propertyName(pn, s, memberTypeFlags);
+ AddWarning("msg.reserved.keyword", s);
+ } else
+ ReportError("msg.no.name.after.dot");
+
+ break;
+
+ }
+ }
+ break;
+
+
+ case Token.DOTQUERY:
+ consumeToken();
+ mustHaveXML();
+ decompiler.AddToken(Token.DOTQUERY);
+ pn = nf.CreateDotQuery(pn, expr(false), ts.Lineno);
+ mustMatchToken(Token.RP, "msg.no.paren");
+ decompiler.AddToken(Token.RP);
+ break;
+
+
+ case Token.LB:
+ consumeToken();
+ decompiler.AddToken(Token.LB);
+ pn = nf.CreateElementGet(pn, null, expr(false), 0);
+ mustMatchToken(Token.RB, "msg.no.bracket.index");
+ decompiler.AddToken(Token.RB);
+ break;
+
+
+ case Token.LP:
+ if (!allowCallSyntax)
+ {
+
+ goto tailLoop_brk;
+ }
+ consumeToken();
+ decompiler.AddToken(Token.LP);
+ pn = nf.CreateCallOrNew(Token.CALL, pn);
+ /* Add the arguments to pn, if any are supplied. */
+ argumentList(pn);
+ break;
+
+
+ default:
+
+ goto tailLoop_brk;
+
+ }
+ }
+
+ tailLoop_brk:
+ ;
+
+ return pn;
+ }
+
+ /*
+ * Xml attribute expression:
+ * '@attr', '@ns::attr', '@ns::*', '@ns::*', '@*', '@*::attr', '@*::*'
+ */
+ Node attributeAccess(Node pn, int memberTypeFlags)
+ {
+ memberTypeFlags |= Node.ATTRIBUTE_FLAG;
+ int tt = nextToken();
+
+ switch (tt)
+ {
+
+ // handles: @name, @ns::name, @ns::*, @ns::[expr]
+ case Token.NAME:
+ {
+ string s = ts.String;
+ decompiler.AddName(s);
+ pn = propertyName(pn, s, memberTypeFlags);
+ }
+ break;
+
+ // handles: @*, @*::name, @*::*, @*::[expr]
+
+ case Token.MUL:
+ decompiler.AddName("*");
+ pn = propertyName(pn, "*", memberTypeFlags);
+ break;
+
+ // handles @[expr]
+
+ case Token.LB:
+ decompiler.AddToken(Token.LB);
+ pn = nf.CreateElementGet(pn, null, expr(false), memberTypeFlags);
+ mustMatchToken(Token.RB, "msg.no.bracket.index");
+ decompiler.AddToken(Token.RB);
+ break;
+
+
+ default:
+ ReportError("msg.no.name.after.xmlAttr");
+ pn = nf.CreatePropertyGet(pn, null, "?", memberTypeFlags);
+ break;
+
+ }
+
+ return pn;
+ }
+
+ /// Check if :: follows name in which case it becomes qualified name
+ Node propertyName(Node pn, string name, int memberTypeFlags)
+ {
+ string ns = null;
+ if (matchToken(Token.COLONCOLON))
+ {
+ decompiler.AddToken(Token.COLONCOLON);
+ ns = name;
+
+ int tt = nextToken();
+ switch (tt)
+ {
+
+ // handles name::name
+ case Token.NAME:
+ name = ts.String;
+ decompiler.AddName(name);
+ break;
+
+ // handles name::*
+
+ case Token.MUL:
+ decompiler.AddName("*");
+ name = "*";
+ break;
+
+ // handles name::[expr]
+
+ case Token.LB:
+ decompiler.AddToken(Token.LB);
+ pn = nf.CreateElementGet(pn, ns, expr(false), memberTypeFlags);
+ mustMatchToken(Token.RB, "msg.no.bracket.index");
+ decompiler.AddToken(Token.RB);
+ return pn;
+
+
+ default:
+ ReportError("msg.no.name.after.coloncolon");
+ name = "?";
+ break;
+
+ }
+ }
+
+ pn = nf.CreatePropertyGet(pn, ns, name, memberTypeFlags);
+ return pn;
+ }
+
+ int currentStackIndex = 0;
+
+
+ Node primaryExpr()
+ {
+ try
+ {
+ if (currentStackIndex++ > ScriptRuntime.MAXSTACKSIZE)
+ {
+ currentStackIndex = 0;
+ throw Context.ReportRuntimeError(
+ ScriptRuntime.GetMessage("mag.too.deep.parser.recursion"), sourceURI, ts.Lineno, null, 0);
+ }
+
+ Node pn;
+
+ int ttFlagged = nextFlaggedToken();
+ int tt = ttFlagged & CLEAR_TI_MASK;
+
+ switch (tt)
+ {
+
+
+ case Token.FUNCTION:
+ return function(FunctionNode.FUNCTION_EXPRESSION);
+
+
+ case Token.LB:
+ {
+ ObjArray elems = new ObjArray();
+ int skipCount = 0;
+ decompiler.AddToken(Token.LB);
+ bool after_lb_or_comma = true;
+ for (; ; )
+ {
+ tt = peekToken();
+
+ if (tt == Token.COMMA)
+ {
+ consumeToken();
+ decompiler.AddToken(Token.COMMA);
+ if (!after_lb_or_comma)
+ {
+ after_lb_or_comma = true;
+ }
+ else
+ {
+ elems.add((object)null);
+ ++skipCount;
+ }
+ }
+ else if (tt == Token.RB)
+ {
+ consumeToken();
+ decompiler.AddToken(Token.RB);
+ break;
+ }
+ else
+ {
+ if (!after_lb_or_comma)
+ {
+ ReportError("msg.no.bracket.arg");
+ }
+ elems.add(assignExpr(false));
+ after_lb_or_comma = false;
+ }
+ }
+ return nf.CreateArrayLiteral(elems, skipCount);
+ }
+
+
+ case Token.LC:
+ {
+ ObjArray elems = new ObjArray();
+ decompiler.AddToken(Token.LC);
+ if (!matchToken(Token.RC))
+ {
+
+ bool first = true;
+ do
+ {
+ object property;
+
+ if (!first)
+ decompiler.AddToken(Token.COMMA);
+ else
+ first = false;
+
+ tt = peekToken();
+ switch (tt)
+ {
+
+ case Token.NAME:
+ case Token.STRING:
+ consumeToken();
+ if (compilerEnv.getterAndSetterSupport)
+ {
+ if (tt == Token.NAME)
+ if (CheckForGetOrSet(elems) || CheckForGetterOrSetter(elems))
+ goto next_prop;
+ }
+
+
+ // map NAMEs to STRINGs in object literal context
+ // but tell the decompiler the proper type
+ string s = ts.String;
+ if (tt == Token.NAME)
+ {
+ decompiler.AddName(s);
+ }
+ else
+ {
+ decompiler.AddString(s);
+ }
+ property = ScriptRuntime.getIndexObject(s);
+
+ break;
+
+
+ case Token.NUMBER:
+ consumeToken();
+ double n = ts.Number;
+ decompiler.AddNumber(n);
+ property = ScriptRuntime.getIndexObject(n);
+ break;
+
+
+ case Token.RC:
+ // trailing comma is OK.
+
+ goto commaloop_brk;
+
+ default:
+ ReportError("msg.bad.prop");
+
+ goto commaloop_brk;
+
+ }
+ mustMatchToken(Token.COLON, "msg.no.colon.prop");
+
+ // OBJLIT is used as ':' in object literal for
+ // decompilation to solve spacing ambiguity.
+ decompiler.AddToken(Token.OBJECTLIT);
+ elems.add(property);
+ elems.add(assignExpr(false));
+
+ next_prop:
+ ;
+ }
+ while (matchToken(Token.COMMA));
+
+ commaloop_brk:
+ ;
+
+
+ mustMatchToken(Token.RC, "msg.no.brace.prop");
+ }
+ decompiler.AddToken(Token.RC);
+ return nf.CreateObjectLiteral(elems);
+ }
+
+
+ case Token.LP:
+
+ /* Brendan's IR-jsparse.c makes a new node tagged with
+ * TOK_LP here... I'm not sure I understand why. Isn't
+ * the grouping already implicit in the structure of the
+ * parse tree? also TOK_LP is already overloaded (I
+ * think) in the C IR as 'function call.' */
+ decompiler.AddToken(Token.LP);
+ pn = expr(false);
+ decompiler.AddToken(Token.RP);
+ mustMatchToken(Token.RP, "msg.no.paren");
+ return pn;
+
+
+ case Token.XMLATTR:
+ mustHaveXML();
+ decompiler.AddToken(Token.XMLATTR);
+ pn = attributeAccess(null, 0);
+ return pn;
+
+
+ case Token.NAME:
+ {
+ string name = ts.String;
+ if ((ttFlagged & TI_CHECK_LABEL) != 0)
+ {
+ if (peekToken() == Token.COLON)
+ {
+ // Do not consume colon, it is used as unwind indicator
+ // to return to statementHelper.
+ // TODO: Better way?
+ return nf.CreateLabel(ts.Lineno);
+ }
+ }
+
+ decompiler.AddName(name);
+ if (compilerEnv.isXmlAvailable())
+ {
+ pn = propertyName(null, name, 0);
+ }
+ else
+ {
+ pn = nf.CreateName(name);
+ }
+ return pn;
+ }
+
+
+ case Token.NUMBER:
+ {
+ double n = ts.Number;
+ decompiler.AddNumber(n);
+ return nf.CreateNumber(n);
+ }
+
+
+ case Token.STRING:
+ {
+ string s = ts.String;
+ decompiler.AddString(s);
+ return nf.CreateString(s);
+ }
+
+
+ case Token.DIV:
+ case Token.ASSIGN_DIV:
+ {
+ // Got / or /= which should be treated as regexp in fact
+ ts.readRegExp(tt);
+ string flags = ts.regExpFlags;
+ ts.regExpFlags = null;
+ string re = ts.String;
+ decompiler.AddRegexp(re, flags);
+ int index = currentScriptOrFn.addRegexp(re, flags);
+ return nf.CreateRegExp(index);
+ }
+
+
+ case Token.NULL:
+ case Token.THIS:
+ case Token.FALSE:
+ case Token.TRUE:
+ decompiler.AddToken(tt);
+ return nf.CreateLeaf(tt);
+
+
+ case Token.RESERVED:
+ ReportError("msg.reserved.id");
+ break;
+
+
+ case Token.ERROR:
+ /* the scanner or one of its subroutines reported the error. */
+ break;
+
+
+ case Token.EOF:
+ ReportError("msg.unexpected.eof");
+ break;
+
+
+ default:
+ ReportError("msg.syntax");
+ break;
+
+ }
+ return null; // should never reach here
+ }
+ finally
+ {
+ currentStackIndex--;
+ }
+ }
+
+
+ ///
+ /// Support for non-ecma "get"/"set" spidermonkey extension.
+ ///
+ ///
+ /// get NAME () SCOPE
+ /// set NAME () SCOPE
+ ///
+ bool CheckForGetOrSet(ObjArray elems)
+ {
+ int tt;
+
+ string type = ts.String;
+ if (type != "get" && type != "set")
+ {
+ return false;
+ }
+ tt = peekToken();
+ if (tt != Token.NAME)
+ return false;
+ consumeToken();
+
+ string name = ts.String;
+
+ decompiler.AddName(name);
+
+ Node func = function(FunctionNode.FUNCTION_EXPRESSION);
+ object property = ScriptRuntime.getIndexObject(name);
+
+ elems.add((type[0] == 'g') ? (object)new Node.GetterPropertyLiteral(property)
+ : (object)new Node.SetterPropertyLiteral(property));
+ elems.add(func);
+
+ return true;
+ }
+
+ ///
+ /// Support for non-ecma "get"/"set" spidermonkey extension.
+ ///
+ ///
+ /// NAME getter: FUNCTION () SCOPE
+ /// NAME setter: FUNCTION () SCOPE
+ ///
+ bool CheckForGetterOrSetter(ObjArray elems)
+ {
+ int tt;
+
+ string name = ts.String;
+ consumeToken();
+
+ tt = peekToken();
+ if (tt != Token.NAME)
+ return false;
+ string type = ts.String;
+ if (type != "getter" && type != "setter")
+ {
+ return false;
+ }
+ consumeToken();
+
+ matchToken(Token.COLON);
+ matchToken(Token.FUNCTION);
+
+ Node func = function(FunctionNode.FUNCTION_EXPRESSION);
+ object property = ScriptRuntime.getIndexObject(name);
+
+ elems.add((type[0] == 'g') ? (object)new Node.GetterPropertyLiteral(property)
+ : (object)new Node.SetterPropertyLiteral(property));
+ elems.add(func);
+
+ return true;
+ }
+
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/RegExpProxy.cs b/src/EcmaScript.NET/RegExpProxy.cs
similarity index 96%
rename from Code/EcmaScript.NET/RegExpProxy.cs
rename to src/EcmaScript.NET/RegExpProxy.cs
index 9769fbf..c9b9b7a 100644
--- a/Code/EcmaScript.NET/RegExpProxy.cs
+++ b/src/EcmaScript.NET/RegExpProxy.cs
@@ -1,46 +1,46 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-namespace EcmaScript.NET
-{
-
-
- public enum RegExpActions
- {
- None = 0,
- Match = 1,
- Replace = 2,
- Search = 3
- }
-
- ///
- /// A proxy for the regexp package, so that the regexp package can be
- /// loaded optionally.
- ///
- public interface RegExpProxy
- {
-
- bool IsRegExp (IScriptable obj);
-
- object Compile (Context cx, string source, string flags);
-
- IScriptable Wrap (Context cx, IScriptable scope, object compiled);
-
- object Perform (Context cx, IScriptable scope, IScriptable thisObj, object [] args, RegExpActions actionType);
-
- int FindSplit (Context cx, IScriptable scope, string target, string separator, IScriptable re, int [] ip, int [] matchlen, bool [] matched, string [] [] parensp);
-
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+namespace EcmaScript.NET
+{
+
+
+ public enum RegExpActions
+ {
+ None = 0,
+ Match = 1,
+ Replace = 2,
+ Search = 3
+ }
+
+ ///
+ /// A proxy for the regexp package, so that the regexp package can be
+ /// loaded optionally.
+ ///
+ public interface RegExpProxy
+ {
+
+ bool IsRegExp (IScriptable obj);
+
+ object Compile (Context cx, string source, string flags);
+
+ IScriptable Wrap (Context cx, IScriptable scope, object compiled);
+
+ object Perform (Context cx, IScriptable scope, IScriptable thisObj, object [] args, RegExpActions actionType);
+
+ int FindSplit (Context cx, IScriptable scope, string target, string separator, IScriptable re, int [] ip, int [] matchlen, bool [] matched, string [] [] parensp);
+
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/Resources/ChangeLog b/src/EcmaScript.NET/Resources/ChangeLog
similarity index 97%
rename from Code/EcmaScript.NET/Resources/ChangeLog
rename to src/EcmaScript.NET/Resources/ChangeLog
index def77fd..58da71b 100644
--- a/Code/EcmaScript.NET/Resources/ChangeLog
+++ b/src/EcmaScript.NET/Resources/ChangeLog
@@ -1,35 +1,35 @@
-2007-01-01 Christian Birkl
-
- * Added 'it' object
- * typeof /x/ must return object, not function
-
-2006-12-30 Christian Birkl
-
- * Added Helpers.StackOverflowVerifier to prevent StackOverflowExceptions
- which aren't cachable in .NET 2.0
-
-2006-12-30 Christian Birkl
-
- * Added "gc" function to NativeGlobalObject
-
- * Duplicate regexp quantifiers now raise a SyntaxError (e.g. /x{1}{1}/)
-
- * Ported bugfix for https://bugzilla.mozilla.org/show_bug.cgi?id=289628
-
- * Fixed some OutOfMemoryExceptions in Array.concat/push/...
- by adding OutOfRange checks.
-
-2006-12-29 Christian Birkl
-
- * First public release (based partly on Rhino 1.6R5)
-
- * Major Changes are:
-
- - Removed support for compiling javascript sources
- - Removed LiveConnect and replaced it with a new .NET layer
- (See EcmaScript.NET.Types.Cli)
- - Rewrote E4X Support completely since it was based on
- javax.beans.* framework which has no counterpart in .NET.
- - Added support JavaScript 1.5 getter and setter
- - .NET'ished some bits here and there (e.g. refactoring methods
+2007-01-01 Christian Birkl
+
+ * Added 'it' object
+ * typeof /x/ must return object, not function
+
+2006-12-30 Christian Birkl
+
+ * Added Helpers.StackOverflowVerifier to prevent StackOverflowExceptions
+ which aren't cachable in .NET 2.0
+
+2006-12-30 Christian Birkl
+
+ * Added "gc" function to NativeGlobalObject
+
+ * Duplicate regexp quantifiers now raise a SyntaxError (e.g. /x{1}{1}/)
+
+ * Ported bugfix for https://bugzilla.mozilla.org/show_bug.cgi?id=289628
+
+ * Fixed some OutOfMemoryExceptions in Array.concat/push/...
+ by adding OutOfRange checks.
+
+2006-12-29 Christian Birkl
+
+ * First public release (based partly on Rhino 1.6R5)
+
+ * Major Changes are:
+
+ - Removed support for compiling javascript sources
+ - Removed LiveConnect and replaced it with a new .NET layer
+ (See EcmaScript.NET.Types.Cli)
+ - Rewrote E4X Support completely since it was based on
+ javax.beans.* framework which has no counterpart in .NET.
+ - Added support JavaScript 1.5 getter and setter
+ - .NET'ished some bits here and there (e.g. refactoring methods
into properties and events)
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/Resources/LICENSE b/src/EcmaScript.NET/Resources/LICENSE
similarity index 97%
rename from Code/EcmaScript.NET/Resources/LICENSE
rename to src/EcmaScript.NET/Resources/LICENSE
index 9b53555..b2b3b0a 100644
--- a/Code/EcmaScript.NET/Resources/LICENSE
+++ b/src/EcmaScript.NET/Resources/LICENSE
@@ -1,34 +1,34 @@
-/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Rhino code, released
- * May 6, 1999.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1997-1999
- * the Initial Developer. All Rights Reserved.
- *
- * Alternatively, the contents of this file may be used under the terms of
- * the GNU General Public License Version 2 or later (the "GPL"), in which
- * case the provisions of the GPL are applicable instead of those above. If
- * you wish to allow use of your version of this file only under the terms of
- * the GPL and not to allow others to use your version of this file under the
- * MPL, indicate your decision by deleting the provisions above and replacing
- * them with the notice and other provisions required by the GPL. If you do
- * not delete the provisions above, a recipient may use your version of this
- * file under either the MPL or the GPL.
- *
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Rhino code, released
+ * May 6, 1999.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1997-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
* ***** END LICENSE BLOCK ***** */
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/Resources/Messages.resx b/src/EcmaScript.NET/Resources/Messages.resx
similarity index 97%
rename from Code/EcmaScript.NET/Resources/Messages.resx
rename to src/EcmaScript.NET/Resources/Messages.resx
index b8b8d4c..02a6c08 100644
--- a/Code/EcmaScript.NET/Resources/Messages.resx
+++ b/src/EcmaScript.NET/Resources/Messages.resx
@@ -1,675 +1,675 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- missing name after . operator
-
-
- missing ( before function parameters.
-
-
- no source found to decompile function reference {0}
-
-
- missing } in compound statement
-
-
- missing ) after formal parameters
-
-
- missing name after .. operator
-
-
- Program too complex: too big jump offset.
-
-
- invalid property id
-
-
- illegal character
-
-
- Invalid increment operand.
-
-
- Function {0} can not be used as the left-hand side of assignment or as an operand of ++ or -- operator.
-
-
- unterminated string literal
-
-
- Construction of objects of type "{0}" is not supported.
-
-
- Internal error: type conversion of {0} to assign to {1} on {2} failed.
-
-
- XML runtime not available
-
-
- @IMPLEMENTATION.VERSION@
-
-
- missing ] in index expression
-
-
- Java method "{0}" was invoked with {1} as "this" value that can not be converted to Java type {2}.
-
-
- Method "{0}" must be static with the signature "(Context cx, Scriptable thisObj, Object[] args, Function funObj)" to define a variable arguments function.
-
-
- Unterminated character class {0}
-
-
- {0} must extend ScriptableObject in order to define property {1}.
-
-
- missing ) after for-loop control
-
-
- {0} is not a function, it is {1}.
-
-
- invalid return
-
-
- unmatched ) in regular expression.
-
-
- In order to define a property, getter {0} must have zero parameters or a single ScriptableObject parameter.
-
-
- Calling eval() with anything other than a primitive string value will simply return the value. Is this what you intended?
-
-
- Function "{0}" must be called directly, and not by way of a function of another name.
-
-
- missing ) after with-statement object
-
-
- invalid Unicode escape sequence
-
-
- Invalid assignment left-hand side.
-
-
- missing '{' before catch-block body
-
-
- no input for {0}
-
-
- Cannot apply "with" to {0}
-
-
- Calling eval() with anything other than a primitive string value is not allowed in the strict mode.
-
-
- undefined labe
-
-
- Only one argument may be specified if the first argument to RegExp.prototype.compile is a RegExp object.
-
-
- Cannot import "{0}" since a property by that name is already defined.
-
-
- Cyclic {0} value not allowed.
-
-
- missing ; before statement
-
-
- Two-parameter setter must take a ScriptableObject as its first parameter.
-
-
- Java package names may not be numbers.
-
-
- missing } after property list
-
-
- Too deep recursion while parsing
-
-
- Unterminated quantifier {0}
-
-
- Program too complex: internal index exceeds 64K limit.
-
-
- Unterminated parenthetical {0}
-
-
- Attempt to assign non-existing name "{0}" in the strict mode. It could indicate a missing variable statement.
-
-
- invalid switch statement
-
-
- illegal octal literal digit {0}; interpreting it as a decimal digit
-
-
- missing name after :: operator
-
-
- missing ( after for
-
-
- error instantiating ({0}): class {1} is interface or abstract
-
-
- Cannot convert {0} to interface {1} with no methods
-
-
- Function importPackage must be called with a package; had "{0}" instead.
-
-
- Can''t find converter method "{0}" on class {1}.
-
-
- Script objects are not constructors.
-
-
- "{0}" may only be invoked from a "new" expression.
-
-
- Maximum {0} less than minimum
-
-
- "{0}" is not a constructor.
-
-
- Array length {0} exceeds supported capacity limit.
-
-
- Method "{0}" called on incompatible object.
-
-
- missing : in conditional expression
-
-
- Cannot convert undefined to an object.
-
-
- missing ( before condition
-
-
- Object''s getDefaultValue() method returned an object.
-
-
- Invalid quantifier {0}
-
-
- Regular expressions are not available.
-
-
- Compilation produced {0} syntax errors.
-
-
- illegally formed XML syntax
-
-
- Overly large back reference {0}
-
-
- Argument {0} is not Java class: {1}.
-
-
- Cannot modify a property of a sealed object: {0}.
-
-
- The "{0}" constructor is deprecated.
-
-
- duplicatet label
-
-
- missing } after function body
-
-
- not a valid default namespace statement. Syntax is: default xml namespace = EXPRESSION;
-
-
- Trailing \ in regular expression.
-
-
- missing formal parameter
-
-
- missing ) after switch expression
-
-
- Primitive type expected (had {0} instead)
-
-
- "{0}" is not defined.
-
-
- missing '{' before switch body
-
-
- invalid catch block condition
-
-
- ''prototype'' property of {0} is not an object.
-
-
- missing ) after condition
-
-
- Can''t find method {0}.
-
-
- The undefined value has no properties.
-
-
- {0} is not a reference to read reference value.
-
-
- Unsupported return type "{0}" in method "{1}".
-
-
- Invalid JavaScript value of type {0}
-
-
- missing ( before catch-block condition
-
-
- Can''t define constructor or class {0} since more than one constructor has multiple parameters.
-
-
- Cannot add a property to a sealed object: {0}.
-
-
- Expected static or delegated setter {0} to take two parameters.
-
-
- Malformed URI sequence.
-
-
- continue can only use labeles of iteration statements
-
-
- Namespace object expected to left of :: (found {0} instead)
-
-
- Cannot set property "{1}" of {0} to "{2}"
-
-
- Unsupported parameter type "{0}" in setter "{1}".
-
-
- back-reference exceeds number of capturing parentheses.
-
-
- Cannot convert {0} to {1}
-
-
- Cannot remove a property from a sealed object: {0}.
-
-
- Invalid left-hand side of for..in loop.
-
-
- Unsupported parameter type "{0}" in method "{1}".
-
-
- Invalid range in character class.
-
-
- Ambiguous import: "{0}" and and "{1}".
-
-
- Method or constructor "{0}" must be static with the signature "(Context cx, Object[] args, Function ctorObj, boolean inNewExpr)" to define a variable arguments constructor.
-
-
- missing ; after for-loop condition
-
-
- Expected either one or two parameters for setter.
-
-
- Cannot delete property "{1}" of {0}
-
-
- Function importClass must be called with a class; had "{0}" instead.
-
-
- missing : after property id
-
-
- Cannot find default value for object.
-
-
- Cannot convert null to an object.
-
-
- invalid label
-
-
- missing variable name
-
-
- Can''t convert to type "{0}".
-
-
- Cannot read property "{1}" from {0}
-
-
- Cannot convert function {0} to interface since it contains methods with different signatures
-
-
- Method "{0}" occurs multiple times in class "{1}".
-
-
- Cannot call method "{1}" of {0}
-
-
- unlabelled break must be inside loop or switch
-
-
- Getter and setter must both be static or neither be static.
-
-
- missing ( before with-statement object
-
-
- Only one variable allowed in for..in loop.
-
-
- missing ; after for-loop initializer
-
-
- identifier is a reserved word
-
-
- Only one class may be extended by a JavaAdapter. Had {0} and {1}.
-
-
- invalid variable initialization
-
-
- JavaAdapter requires at least one argument.
-
-
- illegal usage of future reserved keyword {0}; interpreting it as ordinary identifier
-
-
- Unexpected end of file
-
-
- missing name after .@
-
-
- Can''t use instanceof on a non-object.
-
-
- missing ) after argument list
-
-
- missing ) in parenthetical
-
-
- missing exponent
-
-
- Invalid decerement operand.
-
-
- missing ( before switch expression
-
-
- unterminated comment
-
-
- Zero quantifier {0}
-
-
- illegal radix {0}.
-
-
- invalid string escape mask
-
-
- Duplicate parameter name "{0}".
-
-
- Java class "{0}" has no public instance field or method named "{1}".
-
-
- Expected static or delegated getter {0} to take a ScriptableObject parameter.
-
-
- Line terminator is not allowed between the throw keyword and throw expression.
-
-
- Method "{0}" not found in "{1}".
-
-
- The choice of Java constructor {0} matching JavaScript argument types ({1}) is ambiguous; candidate constructors are: {2}
-
-
- Internal error: attempt to access private/protected field "{0}".
-
-
- Cannot load class "{0}" which has no zero-parameter constructor.
-
-
- invalid flag after regular expression
-
-
- Property {0} not found.
-
-
- Expected argument to getClass() to be a Java object.
-
-
- number format error
-
-
- second argument to Function.prototype.apply must be an array
-
-
- {0} is not an xml object.
-
-
- The choice of Java method {0}.{1} matching JavaScript argument types ({2}) is ambiguous; candidate methods are: {3}
-
-
- Constructor for "Packages" expects argument of type java.lang.Classloader
-
-
- missing : after case expression
-
-
- any catch clauses following an unqualified catch are unreachable
-
-
- double default label in the switch statement
-
-
- unterminated regular expression literal
-
-
- continue must be inside loop
-
-
- function "{0}" redeclared; prior definition will be ignored
-
-
- Expected single parameter setter for {0}
-
-
- Constructor for "{0}" not found.
-
-
- syntax error
-
-
- Overly large minimum {0}
-
-
- missing '{' before function body
-
-
- missing ] after element list
-
-
- Found constructor with wrong signature: {0} calling {1} with signature {2}
-
-
- Inappropriate array length.
-
-
- missing while after do-loop body
-
-
- Java constructor for "{0}" with arguments "{1}" not found.
-
-
- ''try'' without ''catch'' or ''finally''
-
-
- Precision {0} out of range.
-
-
- Java method "{0}" cannot be assigned to.
-
-
- Cannot find function {0}.
-
-
- Overly large maximum {0}
-
-
- {0} is not a reference to set reference value tpo {1}.
-
-
- Exceeded maximum stack depth
-
-
- invalid instanceof usage
-
-
- {0} is read-only
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ missing name after . operator
+
+
+ missing ( before function parameters.
+
+
+ no source found to decompile function reference {0}
+
+
+ missing } in compound statement
+
+
+ missing ) after formal parameters
+
+
+ missing name after .. operator
+
+
+ Program too complex: too big jump offset.
+
+
+ invalid property id
+
+
+ illegal character
+
+
+ Invalid increment operand.
+
+
+ Function {0} can not be used as the left-hand side of assignment or as an operand of ++ or -- operator.
+
+
+ unterminated string literal
+
+
+ Construction of objects of type "{0}" is not supported.
+
+
+ Internal error: type conversion of {0} to assign to {1} on {2} failed.
+
+
+ XML runtime not available
+
+
+ @IMPLEMENTATION.VERSION@
+
+
+ missing ] in index expression
+
+
+ Java method "{0}" was invoked with {1} as "this" value that can not be converted to Java type {2}.
+
+
+ Method "{0}" must be static with the signature "(Context cx, Scriptable thisObj, Object[] args, Function funObj)" to define a variable arguments function.
+
+
+ Unterminated character class {0}
+
+
+ {0} must extend ScriptableObject in order to define property {1}.
+
+
+ missing ) after for-loop control
+
+
+ {0} is not a function, it is {1}.
+
+
+ invalid return
+
+
+ unmatched ) in regular expression.
+
+
+ In order to define a property, getter {0} must have zero parameters or a single ScriptableObject parameter.
+
+
+ Calling eval() with anything other than a primitive string value will simply return the value. Is this what you intended?
+
+
+ Function "{0}" must be called directly, and not by way of a function of another name.
+
+
+ missing ) after with-statement object
+
+
+ invalid Unicode escape sequence
+
+
+ Invalid assignment left-hand side.
+
+
+ missing '{' before catch-block body
+
+
+ no input for {0}
+
+
+ Cannot apply "with" to {0}
+
+
+ Calling eval() with anything other than a primitive string value is not allowed in the strict mode.
+
+
+ undefined labe
+
+
+ Only one argument may be specified if the first argument to RegExp.prototype.compile is a RegExp object.
+
+
+ Cannot import "{0}" since a property by that name is already defined.
+
+
+ Cyclic {0} value not allowed.
+
+
+ missing ; before statement
+
+
+ Two-parameter setter must take a ScriptableObject as its first parameter.
+
+
+ Java package names may not be numbers.
+
+
+ missing } after property list
+
+
+ Too deep recursion while parsing
+
+
+ Unterminated quantifier {0}
+
+
+ Program too complex: internal index exceeds 64K limit.
+
+
+ Unterminated parenthetical {0}
+
+
+ Attempt to assign non-existing name "{0}" in the strict mode. It could indicate a missing variable statement.
+
+
+ invalid switch statement
+
+
+ illegal octal literal digit {0}; interpreting it as a decimal digit
+
+
+ missing name after :: operator
+
+
+ missing ( after for
+
+
+ error instantiating ({0}): class {1} is interface or abstract
+
+
+ Cannot convert {0} to interface {1} with no methods
+
+
+ Function importPackage must be called with a package; had "{0}" instead.
+
+
+ Can''t find converter method "{0}" on class {1}.
+
+
+ Script objects are not constructors.
+
+
+ "{0}" may only be invoked from a "new" expression.
+
+
+ Maximum {0} less than minimum
+
+
+ "{0}" is not a constructor.
+
+
+ Array length {0} exceeds supported capacity limit.
+
+
+ Method "{0}" called on incompatible object.
+
+
+ missing : in conditional expression
+
+
+ Cannot convert undefined to an object.
+
+
+ missing ( before condition
+
+
+ Object''s getDefaultValue() method returned an object.
+
+
+ Invalid quantifier {0}
+
+
+ Regular expressions are not available.
+
+
+ Compilation produced {0} syntax errors.
+
+
+ illegally formed XML syntax
+
+
+ Overly large back reference {0}
+
+
+ Argument {0} is not Java class: {1}.
+
+
+ Cannot modify a property of a sealed object: {0}.
+
+
+ The "{0}" constructor is deprecated.
+
+
+ duplicatet label
+
+
+ missing } after function body
+
+
+ not a valid default namespace statement. Syntax is: default xml namespace = EXPRESSION;
+
+
+ Trailing \ in regular expression.
+
+
+ missing formal parameter
+
+
+ missing ) after switch expression
+
+
+ Primitive type expected (had {0} instead)
+
+
+ "{0}" is not defined.
+
+
+ missing '{' before switch body
+
+
+ invalid catch block condition
+
+
+ ''prototype'' property of {0} is not an object.
+
+
+ missing ) after condition
+
+
+ Can''t find method {0}.
+
+
+ The undefined value has no properties.
+
+
+ {0} is not a reference to read reference value.
+
+
+ Unsupported return type "{0}" in method "{1}".
+
+
+ Invalid JavaScript value of type {0}
+
+
+ missing ( before catch-block condition
+
+
+ Can''t define constructor or class {0} since more than one constructor has multiple parameters.
+
+
+ Cannot add a property to a sealed object: {0}.
+
+
+ Expected static or delegated setter {0} to take two parameters.
+
+
+ Malformed URI sequence.
+
+
+ continue can only use labeles of iteration statements
+
+
+ Namespace object expected to left of :: (found {0} instead)
+
+
+ Cannot set property "{1}" of {0} to "{2}"
+
+
+ Unsupported parameter type "{0}" in setter "{1}".
+
+
+ back-reference exceeds number of capturing parentheses.
+
+
+ Cannot convert {0} to {1}
+
+
+ Cannot remove a property from a sealed object: {0}.
+
+
+ Invalid left-hand side of for..in loop.
+
+
+ Unsupported parameter type "{0}" in method "{1}".
+
+
+ Invalid range in character class.
+
+
+ Ambiguous import: "{0}" and and "{1}".
+
+
+ Method or constructor "{0}" must be static with the signature "(Context cx, Object[] args, Function ctorObj, boolean inNewExpr)" to define a variable arguments constructor.
+
+
+ missing ; after for-loop condition
+
+
+ Expected either one or two parameters for setter.
+
+
+ Cannot delete property "{1}" of {0}
+
+
+ Function importClass must be called with a class; had "{0}" instead.
+
+
+ missing : after property id
+
+
+ Cannot find default value for object.
+
+
+ Cannot convert null to an object.
+
+
+ invalid label
+
+
+ missing variable name
+
+
+ Can''t convert to type "{0}".
+
+
+ Cannot read property "{1}" from {0}
+
+
+ Cannot convert function {0} to interface since it contains methods with different signatures
+
+
+ Method "{0}" occurs multiple times in class "{1}".
+
+
+ Cannot call method "{1}" of {0}
+
+
+ unlabelled break must be inside loop or switch
+
+
+ Getter and setter must both be static or neither be static.
+
+
+ missing ( before with-statement object
+
+
+ Only one variable allowed in for..in loop.
+
+
+ missing ; after for-loop initializer
+
+
+ identifier is a reserved word
+
+
+ Only one class may be extended by a JavaAdapter. Had {0} and {1}.
+
+
+ invalid variable initialization
+
+
+ JavaAdapter requires at least one argument.
+
+
+ illegal usage of future reserved keyword {0}; interpreting it as ordinary identifier
+
+
+ Unexpected end of file
+
+
+ missing name after .@
+
+
+ Can''t use instanceof on a non-object.
+
+
+ missing ) after argument list
+
+
+ missing ) in parenthetical
+
+
+ missing exponent
+
+
+ Invalid decerement operand.
+
+
+ missing ( before switch expression
+
+
+ unterminated comment
+
+
+ Zero quantifier {0}
+
+
+ illegal radix {0}.
+
+
+ invalid string escape mask
+
+
+ Duplicate parameter name "{0}".
+
+
+ Java class "{0}" has no public instance field or method named "{1}".
+
+
+ Expected static or delegated getter {0} to take a ScriptableObject parameter.
+
+
+ Line terminator is not allowed between the throw keyword and throw expression.
+
+
+ Method "{0}" not found in "{1}".
+
+
+ The choice of Java constructor {0} matching JavaScript argument types ({1}) is ambiguous; candidate constructors are: {2}
+
+
+ Internal error: attempt to access private/protected field "{0}".
+
+
+ Cannot load class "{0}" which has no zero-parameter constructor.
+
+
+ invalid flag after regular expression
+
+
+ Property {0} not found.
+
+
+ Expected argument to getClass() to be a Java object.
+
+
+ number format error
+
+
+ second argument to Function.prototype.apply must be an array
+
+
+ {0} is not an xml object.
+
+
+ The choice of Java method {0}.{1} matching JavaScript argument types ({2}) is ambiguous; candidate methods are: {3}
+
+
+ Constructor for "Packages" expects argument of type java.lang.Classloader
+
+
+ missing : after case expression
+
+
+ any catch clauses following an unqualified catch are unreachable
+
+
+ double default label in the switch statement
+
+
+ unterminated regular expression literal
+
+
+ continue must be inside loop
+
+
+ function "{0}" redeclared; prior definition will be ignored
+
+
+ Expected single parameter setter for {0}
+
+
+ Constructor for "{0}" not found.
+
+
+ syntax error
+
+
+ Overly large minimum {0}
+
+
+ missing '{' before function body
+
+
+ missing ] after element list
+
+
+ Found constructor with wrong signature: {0} calling {1} with signature {2}
+
+
+ Inappropriate array length.
+
+
+ missing while after do-loop body
+
+
+ Java constructor for "{0}" with arguments "{1}" not found.
+
+
+ ''try'' without ''catch'' or ''finally''
+
+
+ Precision {0} out of range.
+
+
+ Java method "{0}" cannot be assigned to.
+
+
+ Cannot find function {0}.
+
+
+ Overly large maximum {0}
+
+
+ {0} is not a reference to set reference value tpo {1}.
+
+
+ Exceeded maximum stack depth
+
+
+ invalid instanceof usage
+
+
+ {0} is read-only
+
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/Resources/TODO b/src/EcmaScript.NET/Resources/TODO
similarity index 96%
rename from Code/EcmaScript.NET/Resources/TODO
rename to src/EcmaScript.NET/Resources/TODO
index c273548..ac550d4 100644
--- a/Code/EcmaScript.NET/Resources/TODO
+++ b/src/EcmaScript.NET/Resources/TODO
@@ -1,36 +1,36 @@
-* Fix "NumberToString" Conversions (my math knowledge is too basic to figure out
- how to write an algorithm which generates correct toString () representation of double)
-
-* DateTime tests fails with wrong (?) timezone (daylight saving time).
-
-* Remove ErrorReporter and make events (OnError, OnWarning)
-
-* Way too much public methods/classes
-
-* Way too much virtual methods
-
-* Fix Date Tests
-
-* Fix E4X part
-
-* .NET'ish lower case named methods
-
-* .NET'ish getXXX and setXXX methods
-
-* Tell Rhino guys about bugfixes made (e.g. /x{1}{1}/, RangeChecks in Array, ...)
-
-* Implement full JS 1.6 and JS 1.7
-
-* Find a better solution for handling StackOverflowExceptions than using StackOverflowVerifier.
-
-* Fix Interpreter.InterpreterLoop throw (Excpetion)throwable which screwes up StackTrace
-
-* I've broken Array.toString () (reverted to original state - see #if FALSE in BuiltinArray.cs)
-
-* Merge NativeGlobal and NativeGlobalObject
-
-* Implement __noSucheMethod__ handler (see bug #196097)
-
-* Implement "LongRunningScript" Handler
-
-* Implement "const" keyword (http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Statements:const)
+* Fix "NumberToString" Conversions (my math knowledge is too basic to figure out
+ how to write an algorithm which generates correct toString () representation of double)
+
+* DateTime tests fails with wrong (?) timezone (daylight saving time).
+
+* Remove ErrorReporter and make events (OnError, OnWarning)
+
+* Way too much public methods/classes
+
+* Way too much virtual methods
+
+* Fix Date Tests
+
+* Fix E4X part
+
+* .NET'ish lower case named methods
+
+* .NET'ish getXXX and setXXX methods
+
+* Tell Rhino guys about bugfixes made (e.g. /x{1}{1}/, RangeChecks in Array, ...)
+
+* Implement full JS 1.6 and JS 1.7
+
+* Find a better solution for handling StackOverflowExceptions than using StackOverflowVerifier.
+
+* Fix Interpreter.InterpreterLoop throw (Excpetion)throwable which screwes up StackTrace
+
+* I've broken Array.toString () (reverted to original state - see #if FALSE in BuiltinArray.cs)
+
+* Merge NativeGlobal and NativeGlobalObject
+
+* Implement __noSucheMethod__ handler (see bug #196097)
+
+* Implement "LongRunningScript" Handler
+
+* Implement "const" keyword (http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Statements:const)
diff --git a/Code/EcmaScript.NET/ScriptConvert.cs b/src/EcmaScript.NET/ScriptConvert.cs
similarity index 97%
rename from Code/EcmaScript.NET/ScriptConvert.cs
rename to src/EcmaScript.NET/ScriptConvert.cs
index 642f84f..f4071a0 100644
--- a/Code/EcmaScript.NET/ScriptConvert.cs
+++ b/src/EcmaScript.NET/ScriptConvert.cs
@@ -1,660 +1,660 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-using System.Text;
-using System.Globalization;
-
-namespace EcmaScript.NET
-{
-
- public sealed class ScriptConvert
- {
-
-
- ///
- /// If character c is a hexadecimal digit, return
- /// accumulator * 16 plus corresponding
- /// number. Otherise return -1.
- ///
- internal static int XDigitToInt (int c, int accumulator)
- {
- {
- // Use 0..9 < A..Z < a..z
- if (c <= '9') {
- c -= '0';
- if (0 <= c) {
-
- goto check_brk;
- }
- }
- else if (c <= 'F') {
- if ('A' <= c) {
- c -= ('A' - 10);
-
- goto check_brk;
- }
- }
- else if (c <= 'f') {
- if ('a' <= c) {
- c -= ('a' - 10);
-
- goto check_brk;
- }
- }
- return -1;
- }
-
- check_brk:
- ;
-
- return (accumulator << 4) | c;
- }
-
-
- public static IScriptable ToObject (IScriptable scope, object val)
- {
- if (val is IScriptable) {
- return (IScriptable)val;
- }
- return ToObject (null, scope, val);
- }
-
- public static IScriptable ToObjectOrNull (Context cx, object obj)
- {
- if (obj is IScriptable) {
- return (IScriptable)obj;
- }
- else if (obj != null && obj != Undefined.Value) {
- return ToObject (cx, ScriptRuntime.getTopCallScope (cx), obj);
- }
- return null;
- }
-
- /// Convert the value to an object.
- ///
- /// See ECMA 9.9.
- ///
- public static IScriptable ToObject (Context cx, IScriptable scope, object val)
- {
- if (val is IScriptable) {
- return (IScriptable)val;
- }
- if (val == null) {
- throw ScriptRuntime.TypeErrorById ("msg.null.to.object");
- }
- if (val == Undefined.Value) {
- throw ScriptRuntime.TypeErrorById ("msg.undef.to.object");
- }
- string className = val is string ? "String" : (CliHelper.IsNumber (val) ? "Number" : (val is bool ? "Boolean" : null));
- if (className != null) {
- object [] args = new object [] { val };
- scope = ScriptableObject.GetTopLevelScope (scope);
- return ScriptRuntime.NewObject (cx == null ? Context.CurrentContext : cx, scope, className, args);
- }
-
- // Extension: Wrap as a LiveConnect object.
- object wrapped = cx.Wrap (scope, val, null);
- if (wrapped is IScriptable)
- return (IScriptable)wrapped;
- throw ScriptRuntime.errorWithClassName ("msg.invalid.type", val);
- }
-
-
- ///
- /// See ECMA 9.4.
- ///
- public static double ToInteger (object val)
- {
- return ToInteger (ToNumber (val));
- }
-
- // convenience method
- public static double ToInteger (double d)
- {
- // if it's double.NaN
- if (double.IsNaN (d))
- return +0.0;
-
- if (d == 0.0 || d == System.Double.PositiveInfinity || d == System.Double.NegativeInfinity)
- return d;
-
- if (d > 0.0)
- return Math.Floor (d);
- else
- return Math.Ceiling (d);
- }
-
- public static double ToInteger (object [] args, int index)
- {
- return (index < args.Length) ? ToInteger (args [index]) : +0.0;
- }
-
- ///
- /// See ECMA 9.5.
- ///
- public static int ToInt32 (object val)
- {
- // short circuit for common integer values
- if (val is int)
- return ((int)val);
-
- return ToInt32 (ToNumber (val));
- }
-
- public static int ToInt32 (object [] args, int index)
- {
- return (index < args.Length) ? ToInt32 (args [index]) : 0;
- }
-
- public static int ToInt32 (double d)
- {
- int id = (int)d;
- if (id == d) {
- // This covers -0.0 as well
- return id;
- }
-
- if (double.IsNaN (d) || d == System.Double.PositiveInfinity || d == System.Double.NegativeInfinity) {
- return 0;
- }
-
- d = (d >= 0) ? Math.Floor (d) : Math.Ceiling (d);
-
- double two32 = 4294967296.0;
- d = Math.IEEERemainder (d, two32);
- // (double)(long)d == d should hold here
-
- long l = (long)d;
- // returning (int)d does not work as d can be outside int range
- // but the result must always be 32 lower bits of l
- return (int)l;
- }
-
- /// See ECMA 9.6.
- /// long value representing 32 bits unsigned integer
- ///
- public static long ToUint32 (double d)
- {
- long l = (long)d;
- if (l == d) {
- // This covers -0.0 as well
- return l & 0xffffffffL;
- }
-
- if (double.IsNaN (d) || d == System.Double.PositiveInfinity || d == System.Double.NegativeInfinity) {
- return 0;
- }
-
- d = (d >= 0) ? Math.Floor (d) : Math.Ceiling (d);
-
- double two32 = 4294967296.0;
- l = (long)Math.IEEERemainder (d, two32);
- unchecked {
- return l & (int)0xffffffffL;
- }
- }
-
- public static long ToUint32 (object val)
- {
- return ToUint32 (ToNumber (val));
- }
-
-
- /// Convert the value to a boolean.
- ///
- /// See ECMA 9.2.
- ///
- public static bool ToBoolean (object val)
- {
- for (; ; ) {
- if (val is bool)
- return ((bool)val);
- if (val == null || val == Undefined.Value)
- return false;
- if (val is string)
- return ((string)val).Length != 0;
- if (CliHelper.IsNumber (val)) {
- double d = Convert.ToDouble (val);
- return (!double.IsNaN (d) && d != 0.0);
- }
- if (val is IScriptable) {
- if (Context.CurrentContext.VersionECMA1) {
- // pure ECMA
- return true;
- }
- // ECMA extension
- val = ((IScriptable)val).GetDefaultValue (typeof (bool));
- if (val is IScriptable)
- throw ScriptRuntime.errorWithClassName ("msg.primitive.expected", val);
- continue;
- }
- ScriptRuntime.WarnAboutNonJSObject (val);
- return true;
- }
- }
-
- public static bool ToBoolean (object [] args, int index)
- {
- return (index < args.Length) ? ToBoolean (args [index]) : false;
- }
-
- /// Convert the value to a number.
- ///
- /// See ECMA 9.3.
- ///
- public static double ToNumber (object val)
- {
- for (; ; ) {
- if (val is double)
- return (double)val;
- if (CliHelper.IsNumber (val))
- return Convert.ToDouble (val);
- if (val == null)
- return +0.0;
- if (val == Undefined.Value)
- return double.NaN;
- if (val is string)
- return ToNumber ((string)val);
- if (val is bool)
- return ((bool)val) ? 1 : +0.0;
- if (val is IScriptable) {
- val = ((IScriptable)val).GetDefaultValue (typeof (long));
- if (val is IScriptable)
- throw ScriptRuntime.errorWithClassName ("msg.primitive.expected", val);
- continue;
- }
- ScriptRuntime.WarnAboutNonJSObject (val);
- return double.NaN;
- }
- }
-
- public static double ToNumber (object [] args, int index)
- {
- return (index < args.Length) ? ToNumber (args [index]) : double.NaN;
- }
-
- internal static double ToNumber (string s, int start, int radix)
- {
- char digitMax = '9';
- char lowerCaseBound = 'a';
- char upperCaseBound = 'A';
- int len = s.Length;
- if (radix < 10) {
- digitMax = (char)('0' + radix - 1);
- }
- if (radix > 10) {
- lowerCaseBound = (char)('a' + radix - 10);
- upperCaseBound = (char)('A' + radix - 10);
- }
- int end;
- double sum = 0.0;
- for (end = start; end < len; end++) {
- char c = s [end];
- int newDigit;
- if ('0' <= c && c <= digitMax)
- newDigit = c - '0';
- else if ('a' <= c && c < lowerCaseBound)
- newDigit = c - 'a' + 10;
- else if ('A' <= c && c < upperCaseBound)
- newDigit = c - 'A' + 10;
- else
- break;
- sum = sum * radix + newDigit;
- }
- if (start == end) {
- return double.NaN;
- }
- if (sum >= 9007199254740992.0) {
- if (radix == 10) {
- /* If we're accumulating a decimal number and the number
- * is >= 2^53, then the result from the repeated multiply-add
- * above may be inaccurate. Call Java to get the correct
- * answer.
- */
- try {
- return System.Double.Parse (s.Substring (start, (end) - (start)));
- }
- catch (System.FormatException) {
- return double.NaN;
- }
- }
- else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32) {
- /* The number may also be inaccurate for one of these bases.
- * This happens if the addition in value*radix + digit causes
- * a round-down to an even least significant mantissa bit
- * when the first dropped bit is a one. If any of the
- * following digits in the number (which haven't been added
- * in yet) are nonzero then the correct action would have
- * been to round up instead of down. An example of this
- * occurs when reading the number 0x1000000000000081, which
- * rounds to 0x1000000000000000 instead of 0x1000000000000100.
- */
- int bitShiftInChar = 1;
- int digit = 0;
-
- const int SKIP_LEADING_ZEROS = 0;
- const int FIRST_EXACT_53_BITS = 1;
- const int AFTER_BIT_53 = 2;
- const int ZEROS_AFTER_54 = 3;
- const int MIXED_AFTER_54 = 4;
-
- int state = SKIP_LEADING_ZEROS;
- int exactBitsLimit = 53;
- double factor = 0.0;
- bool bit53 = false;
- // bit54 is the 54th bit (the first dropped from the mantissa)
- bool bit54 = false;
-
- for (; ; ) {
- if (bitShiftInChar == 1) {
- if (start == end)
- break;
- digit = s [start++];
- if ('0' <= digit && digit <= '9')
- digit -= '0';
- else if ('a' <= digit && digit <= 'z')
- digit -= ('a' - 10);
- else
- digit -= ('A' - 10);
- bitShiftInChar = radix;
- }
- bitShiftInChar >>= 1;
- bool bit = (digit & bitShiftInChar) != 0;
-
- switch (state) {
-
- case SKIP_LEADING_ZEROS:
- if (bit) {
- --exactBitsLimit;
- sum = 1.0;
- state = FIRST_EXACT_53_BITS;
- }
- break;
-
- case FIRST_EXACT_53_BITS:
- sum *= 2.0;
- if (bit)
- sum += 1.0;
- --exactBitsLimit;
- if (exactBitsLimit == 0) {
- bit53 = bit;
- state = AFTER_BIT_53;
- }
- break;
-
- case AFTER_BIT_53:
- bit54 = bit;
- factor = 2.0;
- state = ZEROS_AFTER_54;
- break;
-
- case ZEROS_AFTER_54:
- if (bit) {
- state = MIXED_AFTER_54;
- }
- // fallthrough
- goto case MIXED_AFTER_54;
-
- case MIXED_AFTER_54:
- factor *= 2;
- break;
- }
- }
- switch (state) {
-
- case SKIP_LEADING_ZEROS:
- sum = 0.0;
- break;
-
- case FIRST_EXACT_53_BITS:
- case AFTER_BIT_53:
- // do nothing
- break;
-
- case ZEROS_AFTER_54:
- // x1.1 -> x1 + 1 (round up)
- // x0.1 -> x0 (round down)
- if (bit54 & bit53)
- sum += 1.0;
- sum *= factor;
- break;
-
- case MIXED_AFTER_54:
- // x.100...1.. -> x + 1 (round up)
- // x.0anything -> x (round down)
- if (bit54)
- sum += 1.0;
- sum *= factor;
- break;
- }
- }
- /* We don't worry about inaccurate numbers for any other base. */
- }
- return sum;
- }
-
-
- public static string ToString (object [] args, int index)
- {
- return (index < args.Length) ? ToString (args [index]) : "undefined";
- }
-
- internal static object ToPrimitive (object val)
- {
- if (!(val is IScriptable)) {
- return val;
- }
- IScriptable s = (IScriptable)val;
- object result = s.GetDefaultValue (null);
- if (result is IScriptable)
- throw ScriptRuntime.TypeErrorById ("msg.bad.default.value");
- return result;
- }
-
- /// Convert the value to a string.
- ///
- /// See ECMA 9.8.
- ///
- public static string ToString (object val)
- {
- for (; ; ) {
- if (val == null) {
- return "null";
- }
- if (val == Undefined.Value) {
- return "undefined";
- }
- if (val is string) {
- return (string)val;
- }
- if (val is Boolean)
- return ((bool)val) ? "true" : "false";
- if (CliHelper.IsNumber (val)) {
- // TODO: should we just teach NativeNumber.stringValue()
- // TODO: about Numbers?
- return ToString (Convert.ToDouble (val), 10);
- }
- if (val is IScriptable) {
- val = ((IScriptable)val).GetDefaultValue (typeof (string));
- if (val is IScriptable) {
- throw ScriptRuntime.errorWithClassName ("msg.primitive.expected", val);
- }
- continue;
- }
- return val.ToString ();
- }
- }
-
-
-
- /// ToNumber applied to the String type
- ///
- /// See ECMA 9.3.1
- ///
- public static double ToNumber (string input)
- {
- int len = input.Length;
- int start = 0;
- char [] chars = input.ToCharArray ();
- char startChar;
- for (; ; ) {
- if (start == len) {
- // Empty or contains only whitespace
- return +0.0;
- }
- startChar = chars [start];
- if (!char.IsWhiteSpace (startChar))
- break;
- start++;
- }
-
- if (startChar == '0') {
- if (start + 2 < len) {
- int c1 = chars [start + 1];
- if (c1 == 'x' || c1 == 'X') {
- // A hexadecimal number
- return ToNumber (input, start + 2, 16);
- }
- }
- }
- else if (startChar == '+' || startChar == '-') {
- if (start + 3 < len && chars [start + 1] == '0') {
- int c2 = chars [start + 2];
- if (c2 == 'x' || c2 == 'X') {
- // A hexadecimal number with sign
- double val = ToNumber (input, start + 3, 16);
- return startChar == '-' ? -val : val;
- }
- }
- }
-
- int end = len - 1;
- char endChar;
- while (char.IsWhiteSpace (endChar = chars [end]))
- end--;
- if (endChar == 'y') {
- // check for "Infinity"
- if (startChar == '+' || startChar == '-')
- start++;
- if (start + 7 == end && String.Compare (input, start, "Infinity", 0, 8) == 0)
- return startChar == '-' ? System.Double.NegativeInfinity : System.Double.PositiveInfinity;
- return double.NaN;
- }
- // A non-hexadecimal, non-infinity number:
- // just try a normal floating point conversion
- string sub = input.Substring (start, (end + 1) - (start));
-
- // MS.NET will accept non-conformant strings
- // rather than throwing a NumberFormatException
- // as it should (like with \0).
- for (int i = sub.Length - 1; i >= 0; i--) {
- char c = sub [i];
- if (('0' <= c && c <= '9') || c == '.' ||
- c == 'e' || c == 'E' ||
- c == '+' || c == '-')
- continue;
- return double.NaN;
- }
-
- try {
- double ret = double.Parse (sub);
- if (ret == 0) {
- // IMHO a bug in MS.NET: double.Parse("-0.0") == 0.0 so we retard the "-" sign here
- if (sub [0] == '-')
- ret = -ret;
- }
- return ret;
- }
- catch (OverflowException) {
- // HACK
- if (sub [0] == '-')
- return double.NegativeInfinity;
- else
- return double.PositiveInfinity;
- }
- catch (Exception) {
- return double.NaN;
- }
- }
-
- ///
- /// See ECMA 9.7.
- ///
- public static char ToUint16 (object val)
- {
- double d = ToNumber (val);
-
- int i = (int)d;
- if (i == d) {
- return (char)i;
- }
-
- if (double.IsNaN (d) || d == System.Double.PositiveInfinity || d == System.Double.NegativeInfinity) {
- return (char)(0);
- }
-
- d = (d >= 0) ? Math.Floor (d) : Math.Ceiling (d);
-
- int int16 = 0x10000;
- i = (int)Math.IEEERemainder (d, int16);
- return (char)i;
- }
-
- /// Optimized version of toString(Object) for numbers.
- public static string ToString (double val)
- {
- return ToString (val, 10);
- }
-
- ///
- /// See ECMA 9.8.1
- ///
- ///
- ///
- ///
- public static string ToString (double d, int toBase)
- {
- if (double.IsNaN (d))
- return "NaN";
- if (d == System.Double.PositiveInfinity)
- return "Infinity";
- if (d == System.Double.NegativeInfinity)
- return "-Infinity";
- if (d == 0.0)
- return "0";
-
- if ((toBase < 2) || (toBase > 36)) {
- throw Context.ReportRuntimeErrorById ("msg.bad.radix", Convert.ToString (toBase));
- }
-
- if (double.IsNaN (d))
- return "NaN";
- else if (Double.IsPositiveInfinity (d))
- return "Infinity";
- else if (Double.IsNegativeInfinity (d))
- return "-Infinity";
- else {
- // BugFix: Item 9856 - g16 yields better results than "g". Not perfect, but better
- string ret = d.ToString ("g16");
- // TODO: This is plain wrong, but as close as we can get
- // without converting DtoA to C#.
- return ret;
- }
- }
-
-
-
- }
-
-}
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+using System.Text;
+using System.Globalization;
+
+namespace EcmaScript.NET
+{
+
+ public sealed class ScriptConvert
+ {
+
+
+ ///
+ /// If character c is a hexadecimal digit, return
+ /// accumulator * 16 plus corresponding
+ /// number. Otherise return -1.
+ ///
+ internal static int XDigitToInt (int c, int accumulator)
+ {
+ {
+ // Use 0..9 < A..Z < a..z
+ if (c <= '9') {
+ c -= '0';
+ if (0 <= c) {
+
+ goto check_brk;
+ }
+ }
+ else if (c <= 'F') {
+ if ('A' <= c) {
+ c -= ('A' - 10);
+
+ goto check_brk;
+ }
+ }
+ else if (c <= 'f') {
+ if ('a' <= c) {
+ c -= ('a' - 10);
+
+ goto check_brk;
+ }
+ }
+ return -1;
+ }
+
+ check_brk:
+ ;
+
+ return (accumulator << 4) | c;
+ }
+
+
+ public static IScriptable ToObject (IScriptable scope, object val)
+ {
+ if (val is IScriptable) {
+ return (IScriptable)val;
+ }
+ return ToObject (null, scope, val);
+ }
+
+ public static IScriptable ToObjectOrNull (Context cx, object obj)
+ {
+ if (obj is IScriptable) {
+ return (IScriptable)obj;
+ }
+ else if (obj != null && obj != Undefined.Value) {
+ return ToObject (cx, ScriptRuntime.getTopCallScope (cx), obj);
+ }
+ return null;
+ }
+
+ /// Convert the value to an object.
+ ///
+ /// See ECMA 9.9.
+ ///
+ public static IScriptable ToObject (Context cx, IScriptable scope, object val)
+ {
+ if (val is IScriptable) {
+ return (IScriptable)val;
+ }
+ if (val == null) {
+ throw ScriptRuntime.TypeErrorById ("msg.null.to.object");
+ }
+ if (val == Undefined.Value) {
+ throw ScriptRuntime.TypeErrorById ("msg.undef.to.object");
+ }
+ string className = val is string ? "String" : (CliHelper.IsNumber (val) ? "Number" : (val is bool ? "Boolean" : null));
+ if (className != null) {
+ object [] args = new object [] { val };
+ scope = ScriptableObject.GetTopLevelScope (scope);
+ return ScriptRuntime.NewObject (cx == null ? Context.CurrentContext : cx, scope, className, args);
+ }
+
+ // Extension: Wrap as a LiveConnect object.
+ object wrapped = cx.Wrap (scope, val, null);
+ if (wrapped is IScriptable)
+ return (IScriptable)wrapped;
+ throw ScriptRuntime.errorWithClassName ("msg.invalid.type", val);
+ }
+
+
+ ///
+ /// See ECMA 9.4.
+ ///
+ public static double ToInteger (object val)
+ {
+ return ToInteger (ToNumber (val));
+ }
+
+ // convenience method
+ public static double ToInteger (double d)
+ {
+ // if it's double.NaN
+ if (double.IsNaN (d))
+ return +0.0;
+
+ if (d == 0.0 || d == System.Double.PositiveInfinity || d == System.Double.NegativeInfinity)
+ return d;
+
+ if (d > 0.0)
+ return Math.Floor (d);
+ else
+ return Math.Ceiling (d);
+ }
+
+ public static double ToInteger (object [] args, int index)
+ {
+ return (index < args.Length) ? ToInteger (args [index]) : +0.0;
+ }
+
+ ///
+ /// See ECMA 9.5.
+ ///
+ public static int ToInt32 (object val)
+ {
+ // short circuit for common integer values
+ if (val is int)
+ return ((int)val);
+
+ return ToInt32 (ToNumber (val));
+ }
+
+ public static int ToInt32 (object [] args, int index)
+ {
+ return (index < args.Length) ? ToInt32 (args [index]) : 0;
+ }
+
+ public static int ToInt32 (double d)
+ {
+ int id = (int)d;
+ if (id == d) {
+ // This covers -0.0 as well
+ return id;
+ }
+
+ if (double.IsNaN (d) || d == System.Double.PositiveInfinity || d == System.Double.NegativeInfinity) {
+ return 0;
+ }
+
+ d = (d >= 0) ? Math.Floor (d) : Math.Ceiling (d);
+
+ double two32 = 4294967296.0;
+ d = Math.IEEERemainder (d, two32);
+ // (double)(long)d == d should hold here
+
+ long l = (long)d;
+ // returning (int)d does not work as d can be outside int range
+ // but the result must always be 32 lower bits of l
+ return (int)l;
+ }
+
+ /// See ECMA 9.6.
+ /// long value representing 32 bits unsigned integer
+ ///
+ public static long ToUint32 (double d)
+ {
+ long l = (long)d;
+ if (l == d) {
+ // This covers -0.0 as well
+ return l & 0xffffffffL;
+ }
+
+ if (double.IsNaN (d) || d == System.Double.PositiveInfinity || d == System.Double.NegativeInfinity) {
+ return 0;
+ }
+
+ d = (d >= 0) ? Math.Floor (d) : Math.Ceiling (d);
+
+ double two32 = 4294967296.0;
+ l = (long)Math.IEEERemainder (d, two32);
+ unchecked {
+ return l & (int)0xffffffffL;
+ }
+ }
+
+ public static long ToUint32 (object val)
+ {
+ return ToUint32 (ToNumber (val));
+ }
+
+
+ /// Convert the value to a boolean.
+ ///
+ /// See ECMA 9.2.
+ ///
+ public static bool ToBoolean (object val)
+ {
+ for (; ; ) {
+ if (val is bool)
+ return ((bool)val);
+ if (val == null || val == Undefined.Value)
+ return false;
+ if (val is string)
+ return ((string)val).Length != 0;
+ if (CliHelper.IsNumber (val)) {
+ double d = Convert.ToDouble (val);
+ return (!double.IsNaN (d) && d != 0.0);
+ }
+ if (val is IScriptable) {
+ if (Context.CurrentContext.VersionECMA1) {
+ // pure ECMA
+ return true;
+ }
+ // ECMA extension
+ val = ((IScriptable)val).GetDefaultValue (typeof (bool));
+ if (val is IScriptable)
+ throw ScriptRuntime.errorWithClassName ("msg.primitive.expected", val);
+ continue;
+ }
+ ScriptRuntime.WarnAboutNonJSObject (val);
+ return true;
+ }
+ }
+
+ public static bool ToBoolean (object [] args, int index)
+ {
+ return (index < args.Length) ? ToBoolean (args [index]) : false;
+ }
+
+ /// Convert the value to a number.
+ ///
+ /// See ECMA 9.3.
+ ///
+ public static double ToNumber (object val)
+ {
+ for (; ; ) {
+ if (val is double)
+ return (double)val;
+ if (CliHelper.IsNumber (val))
+ return Convert.ToDouble (val);
+ if (val == null)
+ return +0.0;
+ if (val == Undefined.Value)
+ return double.NaN;
+ if (val is string)
+ return ToNumber ((string)val);
+ if (val is bool)
+ return ((bool)val) ? 1 : +0.0;
+ if (val is IScriptable) {
+ val = ((IScriptable)val).GetDefaultValue (typeof (long));
+ if (val is IScriptable)
+ throw ScriptRuntime.errorWithClassName ("msg.primitive.expected", val);
+ continue;
+ }
+ ScriptRuntime.WarnAboutNonJSObject (val);
+ return double.NaN;
+ }
+ }
+
+ public static double ToNumber (object [] args, int index)
+ {
+ return (index < args.Length) ? ToNumber (args [index]) : double.NaN;
+ }
+
+ internal static double ToNumber (string s, int start, int radix)
+ {
+ char digitMax = '9';
+ char lowerCaseBound = 'a';
+ char upperCaseBound = 'A';
+ int len = s.Length;
+ if (radix < 10) {
+ digitMax = (char)('0' + radix - 1);
+ }
+ if (radix > 10) {
+ lowerCaseBound = (char)('a' + radix - 10);
+ upperCaseBound = (char)('A' + radix - 10);
+ }
+ int end;
+ double sum = 0.0;
+ for (end = start; end < len; end++) {
+ char c = s [end];
+ int newDigit;
+ if ('0' <= c && c <= digitMax)
+ newDigit = c - '0';
+ else if ('a' <= c && c < lowerCaseBound)
+ newDigit = c - 'a' + 10;
+ else if ('A' <= c && c < upperCaseBound)
+ newDigit = c - 'A' + 10;
+ else
+ break;
+ sum = sum * radix + newDigit;
+ }
+ if (start == end) {
+ return double.NaN;
+ }
+ if (sum >= 9007199254740992.0) {
+ if (radix == 10) {
+ /* If we're accumulating a decimal number and the number
+ * is >= 2^53, then the result from the repeated multiply-add
+ * above may be inaccurate. Call Java to get the correct
+ * answer.
+ */
+ try {
+ return System.Double.Parse (s.Substring (start, (end) - (start)));
+ }
+ catch (System.FormatException) {
+ return double.NaN;
+ }
+ }
+ else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32) {
+ /* The number may also be inaccurate for one of these bases.
+ * This happens if the addition in value*radix + digit causes
+ * a round-down to an even least significant mantissa bit
+ * when the first dropped bit is a one. If any of the
+ * following digits in the number (which haven't been added
+ * in yet) are nonzero then the correct action would have
+ * been to round up instead of down. An example of this
+ * occurs when reading the number 0x1000000000000081, which
+ * rounds to 0x1000000000000000 instead of 0x1000000000000100.
+ */
+ int bitShiftInChar = 1;
+ int digit = 0;
+
+ const int SKIP_LEADING_ZEROS = 0;
+ const int FIRST_EXACT_53_BITS = 1;
+ const int AFTER_BIT_53 = 2;
+ const int ZEROS_AFTER_54 = 3;
+ const int MIXED_AFTER_54 = 4;
+
+ int state = SKIP_LEADING_ZEROS;
+ int exactBitsLimit = 53;
+ double factor = 0.0;
+ bool bit53 = false;
+ // bit54 is the 54th bit (the first dropped from the mantissa)
+ bool bit54 = false;
+
+ for (; ; ) {
+ if (bitShiftInChar == 1) {
+ if (start == end)
+ break;
+ digit = s [start++];
+ if ('0' <= digit && digit <= '9')
+ digit -= '0';
+ else if ('a' <= digit && digit <= 'z')
+ digit -= ('a' - 10);
+ else
+ digit -= ('A' - 10);
+ bitShiftInChar = radix;
+ }
+ bitShiftInChar >>= 1;
+ bool bit = (digit & bitShiftInChar) != 0;
+
+ switch (state) {
+
+ case SKIP_LEADING_ZEROS:
+ if (bit) {
+ --exactBitsLimit;
+ sum = 1.0;
+ state = FIRST_EXACT_53_BITS;
+ }
+ break;
+
+ case FIRST_EXACT_53_BITS:
+ sum *= 2.0;
+ if (bit)
+ sum += 1.0;
+ --exactBitsLimit;
+ if (exactBitsLimit == 0) {
+ bit53 = bit;
+ state = AFTER_BIT_53;
+ }
+ break;
+
+ case AFTER_BIT_53:
+ bit54 = bit;
+ factor = 2.0;
+ state = ZEROS_AFTER_54;
+ break;
+
+ case ZEROS_AFTER_54:
+ if (bit) {
+ state = MIXED_AFTER_54;
+ }
+ // fallthrough
+ goto case MIXED_AFTER_54;
+
+ case MIXED_AFTER_54:
+ factor *= 2;
+ break;
+ }
+ }
+ switch (state) {
+
+ case SKIP_LEADING_ZEROS:
+ sum = 0.0;
+ break;
+
+ case FIRST_EXACT_53_BITS:
+ case AFTER_BIT_53:
+ // do nothing
+ break;
+
+ case ZEROS_AFTER_54:
+ // x1.1 -> x1 + 1 (round up)
+ // x0.1 -> x0 (round down)
+ if (bit54 & bit53)
+ sum += 1.0;
+ sum *= factor;
+ break;
+
+ case MIXED_AFTER_54:
+ // x.100...1.. -> x + 1 (round up)
+ // x.0anything -> x (round down)
+ if (bit54)
+ sum += 1.0;
+ sum *= factor;
+ break;
+ }
+ }
+ /* We don't worry about inaccurate numbers for any other base. */
+ }
+ return sum;
+ }
+
+
+ public static string ToString (object [] args, int index)
+ {
+ return (index < args.Length) ? ToString (args [index]) : "undefined";
+ }
+
+ internal static object ToPrimitive (object val)
+ {
+ if (!(val is IScriptable)) {
+ return val;
+ }
+ IScriptable s = (IScriptable)val;
+ object result = s.GetDefaultValue (null);
+ if (result is IScriptable)
+ throw ScriptRuntime.TypeErrorById ("msg.bad.default.value");
+ return result;
+ }
+
+ /// Convert the value to a string.
+ ///
+ /// See ECMA 9.8.
+ ///
+ public static string ToString (object val)
+ {
+ for (; ; ) {
+ if (val == null) {
+ return "null";
+ }
+ if (val == Undefined.Value) {
+ return "undefined";
+ }
+ if (val is string) {
+ return (string)val;
+ }
+ if (val is Boolean)
+ return ((bool)val) ? "true" : "false";
+ if (CliHelper.IsNumber (val)) {
+ // TODO: should we just teach NativeNumber.stringValue()
+ // TODO: about Numbers?
+ return ToString (Convert.ToDouble (val), 10);
+ }
+ if (val is IScriptable) {
+ val = ((IScriptable)val).GetDefaultValue (typeof (string));
+ if (val is IScriptable) {
+ throw ScriptRuntime.errorWithClassName ("msg.primitive.expected", val);
+ }
+ continue;
+ }
+ return val.ToString ();
+ }
+ }
+
+
+
+ /// ToNumber applied to the String type
+ ///
+ /// See ECMA 9.3.1
+ ///
+ public static double ToNumber (string input)
+ {
+ int len = input.Length;
+ int start = 0;
+ char [] chars = input.ToCharArray ();
+ char startChar;
+ for (; ; ) {
+ if (start == len) {
+ // Empty or contains only whitespace
+ return +0.0;
+ }
+ startChar = chars [start];
+ if (!char.IsWhiteSpace (startChar))
+ break;
+ start++;
+ }
+
+ if (startChar == '0') {
+ if (start + 2 < len) {
+ int c1 = chars [start + 1];
+ if (c1 == 'x' || c1 == 'X') {
+ // A hexadecimal number
+ return ToNumber (input, start + 2, 16);
+ }
+ }
+ }
+ else if (startChar == '+' || startChar == '-') {
+ if (start + 3 < len && chars [start + 1] == '0') {
+ int c2 = chars [start + 2];
+ if (c2 == 'x' || c2 == 'X') {
+ // A hexadecimal number with sign
+ double val = ToNumber (input, start + 3, 16);
+ return startChar == '-' ? -val : val;
+ }
+ }
+ }
+
+ int end = len - 1;
+ char endChar;
+ while (char.IsWhiteSpace (endChar = chars [end]))
+ end--;
+ if (endChar == 'y') {
+ // check for "Infinity"
+ if (startChar == '+' || startChar == '-')
+ start++;
+ if (start + 7 == end && String.Compare (input, start, "Infinity", 0, 8) == 0)
+ return startChar == '-' ? System.Double.NegativeInfinity : System.Double.PositiveInfinity;
+ return double.NaN;
+ }
+ // A non-hexadecimal, non-infinity number:
+ // just try a normal floating point conversion
+ string sub = input.Substring (start, (end + 1) - (start));
+
+ // MS.NET will accept non-conformant strings
+ // rather than throwing a NumberFormatException
+ // as it should (like with \0).
+ for (int i = sub.Length - 1; i >= 0; i--) {
+ char c = sub [i];
+ if (('0' <= c && c <= '9') || c == '.' ||
+ c == 'e' || c == 'E' ||
+ c == '+' || c == '-')
+ continue;
+ return double.NaN;
+ }
+
+ try {
+ double ret = double.Parse (sub);
+ if (ret == 0) {
+ // IMHO a bug in MS.NET: double.Parse("-0.0") == 0.0 so we retard the "-" sign here
+ if (sub [0] == '-')
+ ret = -ret;
+ }
+ return ret;
+ }
+ catch (OverflowException) {
+ // HACK
+ if (sub [0] == '-')
+ return double.NegativeInfinity;
+ else
+ return double.PositiveInfinity;
+ }
+ catch (Exception) {
+ return double.NaN;
+ }
+ }
+
+ ///
+ /// See ECMA 9.7.
+ ///
+ public static char ToUint16 (object val)
+ {
+ double d = ToNumber (val);
+
+ int i = (int)d;
+ if (i == d) {
+ return (char)i;
+ }
+
+ if (double.IsNaN (d) || d == System.Double.PositiveInfinity || d == System.Double.NegativeInfinity) {
+ return (char)(0);
+ }
+
+ d = (d >= 0) ? Math.Floor (d) : Math.Ceiling (d);
+
+ int int16 = 0x10000;
+ i = (int)Math.IEEERemainder (d, int16);
+ return (char)i;
+ }
+
+ /// Optimized version of toString(Object) for numbers.
+ public static string ToString (double val)
+ {
+ return ToString (val, 10);
+ }
+
+ ///
+ /// See ECMA 9.8.1
+ ///
+ ///
+ ///
+ ///
+ public static string ToString (double d, int toBase)
+ {
+ if (double.IsNaN (d))
+ return "NaN";
+ if (d == System.Double.PositiveInfinity)
+ return "Infinity";
+ if (d == System.Double.NegativeInfinity)
+ return "-Infinity";
+ if (d == 0.0)
+ return "0";
+
+ if ((toBase < 2) || (toBase > 36)) {
+ throw Context.ReportRuntimeErrorById ("msg.bad.radix", Convert.ToString (toBase));
+ }
+
+ if (double.IsNaN (d))
+ return "NaN";
+ else if (Double.IsPositiveInfinity (d))
+ return "Infinity";
+ else if (Double.IsNegativeInfinity (d))
+ return "-Infinity";
+ else {
+ // BugFix: Item 9856 - g16 yields better results than "g". Not perfect, but better
+ string ret = d.ToString ("g16");
+ // TODO: This is plain wrong, but as close as we can get
+ // without converting DtoA to C#.
+ return ret;
+ }
+ }
+
+
+
+ }
+
+}
diff --git a/Code/EcmaScript.NET/ScriptOrFnNode.cs b/src/EcmaScript.NET/ScriptOrFnNode.cs
similarity index 95%
rename from Code/EcmaScript.NET/ScriptOrFnNode.cs
rename to src/EcmaScript.NET/ScriptOrFnNode.cs
index 6e4e45c..323616b 100644
--- a/Code/EcmaScript.NET/ScriptOrFnNode.cs
+++ b/src/EcmaScript.NET/ScriptOrFnNode.cs
@@ -1,278 +1,278 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-using EcmaScript.NET.Collections;
-
-namespace EcmaScript.NET
-{
-
- public class ScriptOrFnNode : Node
- {
- virtual public string SourceName
- {
- get
- {
- return sourceName;
- }
-
- set
- {
- this.sourceName = value;
- }
-
- }
- virtual public int EncodedSourceStart
- {
- get
- {
- return encodedSourceStart;
- }
-
- }
- virtual public int EncodedSourceEnd
- {
- get
- {
- return encodedSourceEnd;
- }
-
- }
- virtual public int BaseLineno
- {
- get
- {
- return baseLineno;
- }
-
- set
- {
- // One time action
- if (value < 0 || baseLineno >= 0)
- Context.CodeBug ();
- baseLineno = value;
- }
-
- }
- virtual public int EndLineno
- {
- get
- {
- return baseLineno;
- }
-
- set
- {
- // One time action
- if (value < 0 || endLineno >= 0)
- Context.CodeBug ();
- endLineno = value;
- }
-
- }
- virtual public int FunctionCount
- {
- get
- {
- if (functions == null) {
- return 0;
- }
- return functions.size ();
- }
-
- }
- virtual public int RegexpCount
- {
- get
- {
- if (regexps == null) {
- return 0;
- }
- return regexps.size () / 2;
- }
-
- }
- virtual public int ParamCount
- {
- get
- {
- return varStart;
- }
-
- }
- virtual public int ParamAndVarCount
- {
- get
- {
- return itsVariables.size ();
- }
-
- }
- virtual public string [] ParamAndVarNames
- {
- get
- {
- int N = itsVariables.size ();
- if (N == 0) {
- return ScriptRuntime.EmptyStrings;
- }
- string [] array = new string [N];
- itsVariables.ToArray (array);
- return array;
- }
-
- }
- virtual public object CompilerData
- {
- get
- {
- return compilerData;
- }
-
- set
- {
- if (value == null)
- throw new ArgumentException ();
- // Can only call once
- if (compilerData != null)
- throw new ApplicationException ();
- compilerData = value;
- }
-
- }
-
- public ScriptOrFnNode (int nodeType)
- : base (nodeType)
- {
- }
-
- public void setEncodedSourceBounds (int start, int end)
- {
- this.encodedSourceStart = start;
- this.encodedSourceEnd = end;
- }
-
- public FunctionNode getFunctionNode (int i)
- {
- return (FunctionNode)functions.Get (i);
- }
-
- public int addFunction (FunctionNode fnNode)
- {
- if (fnNode == null)
- Context.CodeBug ();
- if (functions == null) {
- functions = new ObjArray ();
- }
- functions.add (fnNode);
- return functions.size () - 1;
- }
-
- public string getRegexpString (int index)
- {
- return (string)regexps.Get (index * 2);
- }
-
- public string getRegexpFlags (int index)
- {
- return (string)regexps.Get (index * 2 + 1);
- }
-
- public int addRegexp (string str, string flags)
- {
- if (str == null)
- Context.CodeBug ();
- if (regexps == null) {
- regexps = new ObjArray ();
- }
- regexps.add (str);
- regexps.add (flags);
- return regexps.size () / 2 - 1;
- }
-
- public bool hasParamOrVar (string name)
- {
- return itsVariableNames.has (name);
- }
-
- public int getParamOrVarIndex (string name)
- {
- return itsVariableNames.Get (name, -1);
- }
-
- public string getParamOrVarName (int index)
- {
- return (string)itsVariables.Get (index);
- }
-
- public void addParam (string name)
- {
- // Check addparam is not called after addLocal
- if (varStart != itsVariables.size ())
- Context.CodeBug ();
- // Allow non-unique parameter names: use the last occurrence
- int index = varStart++;
- itsVariables.add (name);
- itsVariableNames.put (name, index);
- }
-
- public void addVar (string name)
- {
- int vIndex = itsVariableNames.Get (name, -1);
- if (vIndex != -1) {
- // There's already a variable or parameter with this name.
- return;
- }
- int index = itsVariables.size ();
- itsVariables.add (name);
- itsVariableNames.put (name, index);
- }
-
- public void removeParamOrVar (string name)
- {
- int i = itsVariableNames.Get (name, -1);
- if (i != -1) {
- itsVariables.remove (i);
- itsVariableNames.remove (name);
- ObjToIntMap.Iterator iter = itsVariableNames.newIterator ();
- for (iter.start (); !iter.done (); iter.next ()) {
- int v = iter.Value;
- if (v > i) {
- iter.Value = v - 1;
- }
- }
- }
- }
-
- private int encodedSourceStart;
- private int encodedSourceEnd;
- private string sourceName;
- private int baseLineno = -1;
- private int endLineno = -1;
-
- private ObjArray functions;
-
- private ObjArray regexps;
-
- // a list of the formal parameters and local variables
- private ObjArray itsVariables = new ObjArray ();
-
- // mapping from name to index in list
- private ObjToIntMap itsVariableNames = new ObjToIntMap (11);
-
- private int varStart; // index in list of first variable
-
- private object compilerData;
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+using EcmaScript.NET.Collections;
+
+namespace EcmaScript.NET
+{
+
+ public class ScriptOrFnNode : Node
+ {
+ virtual public string SourceName
+ {
+ get
+ {
+ return sourceName;
+ }
+
+ set
+ {
+ this.sourceName = value;
+ }
+
+ }
+ virtual public int EncodedSourceStart
+ {
+ get
+ {
+ return encodedSourceStart;
+ }
+
+ }
+ virtual public int EncodedSourceEnd
+ {
+ get
+ {
+ return encodedSourceEnd;
+ }
+
+ }
+ virtual public int BaseLineno
+ {
+ get
+ {
+ return baseLineno;
+ }
+
+ set
+ {
+ // One time action
+ if (value < 0 || baseLineno >= 0)
+ Context.CodeBug ();
+ baseLineno = value;
+ }
+
+ }
+ virtual public int EndLineno
+ {
+ get
+ {
+ return baseLineno;
+ }
+
+ set
+ {
+ // One time action
+ if (value < 0 || endLineno >= 0)
+ Context.CodeBug ();
+ endLineno = value;
+ }
+
+ }
+ virtual public int FunctionCount
+ {
+ get
+ {
+ if (functions == null) {
+ return 0;
+ }
+ return functions.size ();
+ }
+
+ }
+ virtual public int RegexpCount
+ {
+ get
+ {
+ if (regexps == null) {
+ return 0;
+ }
+ return regexps.size () / 2;
+ }
+
+ }
+ virtual public int ParamCount
+ {
+ get
+ {
+ return varStart;
+ }
+
+ }
+ virtual public int ParamAndVarCount
+ {
+ get
+ {
+ return itsVariables.size ();
+ }
+
+ }
+ virtual public string [] ParamAndVarNames
+ {
+ get
+ {
+ int N = itsVariables.size ();
+ if (N == 0) {
+ return ScriptRuntime.EmptyStrings;
+ }
+ string [] array = new string [N];
+ itsVariables.ToArray (array);
+ return array;
+ }
+
+ }
+ virtual public object CompilerData
+ {
+ get
+ {
+ return compilerData;
+ }
+
+ set
+ {
+ if (value == null)
+ throw new ArgumentException ();
+ // Can only call once
+ if (compilerData != null)
+ throw new Exception ();
+ compilerData = value;
+ }
+
+ }
+
+ public ScriptOrFnNode (int nodeType)
+ : base (nodeType)
+ {
+ }
+
+ public void setEncodedSourceBounds (int start, int end)
+ {
+ this.encodedSourceStart = start;
+ this.encodedSourceEnd = end;
+ }
+
+ public FunctionNode getFunctionNode (int i)
+ {
+ return (FunctionNode)functions.Get (i);
+ }
+
+ public int addFunction (FunctionNode fnNode)
+ {
+ if (fnNode == null)
+ Context.CodeBug ();
+ if (functions == null) {
+ functions = new ObjArray ();
+ }
+ functions.add (fnNode);
+ return functions.size () - 1;
+ }
+
+ public string getRegexpString (int index)
+ {
+ return (string)regexps.Get (index * 2);
+ }
+
+ public string getRegexpFlags (int index)
+ {
+ return (string)regexps.Get (index * 2 + 1);
+ }
+
+ public int addRegexp (string str, string flags)
+ {
+ if (str == null)
+ Context.CodeBug ();
+ if (regexps == null) {
+ regexps = new ObjArray ();
+ }
+ regexps.add (str);
+ regexps.add (flags);
+ return regexps.size () / 2 - 1;
+ }
+
+ public bool hasParamOrVar (string name)
+ {
+ return itsVariableNames.has (name);
+ }
+
+ public int getParamOrVarIndex (string name)
+ {
+ return itsVariableNames.Get (name, -1);
+ }
+
+ public string getParamOrVarName (int index)
+ {
+ return (string)itsVariables.Get (index);
+ }
+
+ public void addParam (string name)
+ {
+ // Check addparam is not called after addLocal
+ if (varStart != itsVariables.size ())
+ Context.CodeBug ();
+ // Allow non-unique parameter names: use the last occurrence
+ int index = varStart++;
+ itsVariables.add (name);
+ itsVariableNames.put (name, index);
+ }
+
+ public void addVar (string name)
+ {
+ int vIndex = itsVariableNames.Get (name, -1);
+ if (vIndex != -1) {
+ // There's already a variable or parameter with this name.
+ return;
+ }
+ int index = itsVariables.size ();
+ itsVariables.add (name);
+ itsVariableNames.put (name, index);
+ }
+
+ public void removeParamOrVar (string name)
+ {
+ int i = itsVariableNames.Get (name, -1);
+ if (i != -1) {
+ itsVariables.remove (i);
+ itsVariableNames.remove (name);
+ ObjToIntMap.Iterator iter = itsVariableNames.newIterator ();
+ for (iter.start (); !iter.done (); iter.next ()) {
+ int v = iter.Value;
+ if (v > i) {
+ iter.Value = v - 1;
+ }
+ }
+ }
+ }
+
+ private int encodedSourceStart;
+ private int encodedSourceEnd;
+ private string sourceName;
+ private int baseLineno = -1;
+ private int endLineno = -1;
+
+ private ObjArray functions;
+
+ private ObjArray regexps;
+
+ // a list of the formal parameters and local variables
+ private ObjArray itsVariables = new ObjArray ();
+
+ // mapping from name to index in list
+ private ObjToIntMap itsVariableNames = new ObjToIntMap (11);
+
+ private int varStart; // index in list of first variable
+
+ private object compilerData;
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/ScriptRuntime.cs b/src/EcmaScript.NET/ScriptRuntime.cs
similarity index 96%
rename from Code/EcmaScript.NET/ScriptRuntime.cs
rename to src/EcmaScript.NET/ScriptRuntime.cs
index 8b581be..7ef35fe 100644
--- a/Code/EcmaScript.NET/ScriptRuntime.cs
+++ b/src/EcmaScript.NET/ScriptRuntime.cs
@@ -1,2610 +1,2610 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-using System.Resources;
-using System.Globalization;
-using System.Text;
-using System.Threading;
-
-using EcmaScript.NET;
-using EcmaScript.NET.Types;
-using EcmaScript.NET.Types.RegExp;
-using EcmaScript.NET.Types.E4X;
-using EcmaScript.NET.Collections;
-
-namespace EcmaScript.NET
-{
-
- /// This is the class that implements the runtime.
- ///
- ///
- public class ScriptRuntime
- {
-
- /// No instances should be created.
- protected internal ScriptRuntime ()
- {
- }
-
- public const int MAXSTACKSIZE = 1000;
-
- private const string XML_INIT_CLASS = "EcmaScript.NET.Xml.Impl.XMLLib";
-
- private static readonly object LIBRARY_SCOPE_KEY = new object ();
-
- public static bool IsNativeRuntimeType (Type cl)
- {
- if (cl.IsPrimitive) {
- return (cl != typeof (char));
- }
- else {
- return (cl == typeof (string) || cl == typeof (bool)
- || CliHelper.IsNumberType (cl)
- || typeof (IScriptable).IsAssignableFrom (cl));
- }
- }
-
- public static ScriptableObject InitStandardObjects (Context cx, ScriptableObject scope, bool zealed)
- {
- if (scope == null) {
- scope = new BuiltinObject ();
- }
- scope.AssociateValue (LIBRARY_SCOPE_KEY, scope);
-
- BaseFunction.Init (scope, zealed);
- BuiltinObject.Init (scope, zealed);
-
- IScriptable objectProto = ScriptableObject.GetObjectPrototype (scope);
-
- // Function.prototype.__proto__ should be Object.prototype
- IScriptable functionProto = ScriptableObject.GetFunctionPrototype (scope);
- functionProto.SetPrototype (objectProto);
-
- // Set the prototype of the object passed in if need be
- if (scope.GetPrototype () == null)
- scope.SetPrototype (objectProto);
-
- // must precede NativeGlobal since it's needed therein
- BuiltinError.Init (scope, zealed);
- BuiltinGlobal.Init (cx, scope, zealed);
-
- if (scope is BuiltinGlobalObject) {
- ((BuiltinGlobalObject)scope).Init (scope, zealed);
- }
-
- BuiltinArray.Init (scope, zealed);
- BuiltinString.Init (scope, zealed);
- BuiltinBoolean.Init (scope, zealed);
- BuiltinNumber.Init (scope, zealed);
- BuiltinDate.Init (scope, zealed);
- BuiltinMath.Init (scope, zealed);
-
- BuiltinWith.Init (scope, zealed);
- BuiltinCall.Init (scope, zealed);
- BuiltinScript.Init (scope, zealed);
-
- BuiltinRegExp.Init (scope, zealed);
-
- if (cx.HasFeature (Context.Features.E4x)) {
- Types.E4X.XMLLib.Init (scope, zealed);
- }
-
- Continuation.Init (scope, zealed);
-
- if (cx.HasFeature (Context.Features.NonEcmaItObject)) {
- InitItObject (cx, scope);
- }
-
- return scope;
- }
-
- static void InitItObject (Context cx, ScriptableObject scope) {
- BuiltinObject itObj = new BuiltinObject ();
- itObj.SetPrototype (scope);
- itObj.DefineProperty ("color", Undefined.Value, ScriptableObject.PERMANENT);
- itObj.DefineProperty ("height", Undefined.Value, ScriptableObject.PERMANENT);
- itObj.DefineProperty ("width", Undefined.Value, ScriptableObject.PERMANENT);
- itObj.DefineProperty ("funny", Undefined.Value, ScriptableObject.PERMANENT);
- itObj.DefineProperty ("array", Undefined.Value, ScriptableObject.PERMANENT);
- itObj.DefineProperty ("rdonly", Undefined.Value, ScriptableObject.READONLY);
- scope.DefineProperty ("it", itObj, ScriptableObject.PERMANENT);
- }
-
- public static ScriptableObject getLibraryScopeOrNull (IScriptable scope)
- {
- ScriptableObject libScope;
- libScope = (ScriptableObject)ScriptableObject.GetTopScopeValue (scope, LIBRARY_SCOPE_KEY);
- return libScope;
- }
-
- // It is public so NativeRegExp can access it .
- public static bool isJSLineTerminator (int c)
- {
- // Optimization for faster check for eol character:
- // they do not have 0xDFD0 bits set
- if ((c & 0xDFD0) != 0) {
- return false;
- }
- return c == '\n' || c == '\r' || c == 0x2028 || c == 0x2029;
- }
-
-
- /// Helper function for builtin objects that use the varargs form.
- /// ECMA function formal arguments are undefined if not supplied;
- /// this function pads the argument array out to the expected
- /// length, if necessary.
- ///
- public static object [] padArguments (object [] args, int count)
- {
- if (count < args.Length)
- return args;
-
- int i;
- object [] result = new object [count];
- for (i = 0; i < args.Length; i++) {
- result [i] = args [i];
- }
-
- for (; i < count; i++) {
- result [i] = Undefined.Value;
- }
-
- return result;
- }
-
-
- public static string escapeString (string s)
- {
- return escapeString (s, '"');
- }
-
- /// For escaping strings printed by object and array literals; not quite
- /// the same as 'escape.'
- ///
- public static string escapeString (string s, char escapeQuote)
- {
- if (!(escapeQuote == '"' || escapeQuote == '\''))
- Context.CodeBug ();
- System.Text.StringBuilder sb = null;
-
- for (int i = 0, L = s.Length; i != L; ++i) {
- int c = s [i];
-
- if (' ' <= c && c <= '~' && c != escapeQuote && c != '\\') {
- // an ordinary print character (like C isprint()) and not "
- // or \ .
- if (sb != null) {
- sb.Append ((char)c);
- }
- continue;
- }
- if (sb == null) {
- sb = new System.Text.StringBuilder (L + 3);
- sb.Append (s);
- sb.Length = i;
- }
-
- int escape = -1;
- switch (c) {
-
- case '\b':
- escape = 'b';
- break;
-
- case '\f':
- escape = 'f';
- break;
-
- case '\n':
- escape = 'n';
- break;
-
- case '\r':
- escape = 'r';
- break;
-
- case '\t':
- escape = 't';
- break;
-
- case 0xb:
- escape = 'v';
- break; // Java lacks \v.
-
- case ' ':
- escape = ' ';
- break;
-
- case '\\':
- escape = '\\';
- break;
- }
- if (escape >= 0) {
- // an \escaped sort of character
- sb.Append ('\\');
- sb.Append ((char)escape);
- }
- else if (c == escapeQuote) {
- sb.Append ('\\');
- sb.Append (escapeQuote);
- }
- else {
- int hexSize;
- if (c < 256) {
- // 2-digit hex
- sb.Append ("\\x");
- hexSize = 2;
- }
- else {
- // Unicode.
- sb.Append ("\\u");
- hexSize = 4;
- }
- // append hexadecimal form of c left-padded with 0
- for (int shift = (hexSize - 1) * 4; shift >= 0; shift -= 4) {
- int digit = 0xf & (c >> shift);
- int hc = (digit < 10) ? '0' + digit : 'a' - 10 + digit;
- sb.Append ((char)hc);
- }
- }
- }
- return (sb == null) ? s : sb.ToString ();
- }
-
- internal static bool isValidIdentifierName (string s)
- {
- int L = s.Length;
- if (L == 0)
- return false;
- if (!(char.IsLetter (s [0]) || s [0].CompareTo ('$') == 0 || s [0].CompareTo ('_') == 0))
- return false;
- for (int i = 1; i != L; ++i) {
- if (!TokenStream.IsJavaIdentifierPart (s [i]))
- return false;
- }
- return !TokenStream.isKeyword (s);
- }
-
-
-
- internal static string DefaultObjectToString (IScriptable obj)
- {
- return "[object " + obj.ClassName + ']';
- }
-
- internal static string uneval (Context cx, IScriptable scope, object value)
- {
- if (value == null) {
- return "null";
- }
- if (value == Undefined.Value) {
- return "undefined";
- }
- if (value is string) {
- string escaped = escapeString ((string)value);
- System.Text.StringBuilder sb = new System.Text.StringBuilder (escaped.Length + 2);
- sb.Append ('\"');
- sb.Append (escaped);
- sb.Append ('\"');
- return sb.ToString ();
- }
- if (CliHelper.IsNumber (value)) {
- double d = Convert.ToDouble (value);
- if (d == 0 && 1 / d < 0) {
- return "-0";
- }
- return ScriptConvert.ToString (d);
- }
- if (value is bool) {
- return ScriptConvert.ToString (value);
- }
- if (value is IScriptable) {
- IScriptable obj = (IScriptable)value;
- object v = ScriptableObject.GetProperty (obj, "toSource");
- if (v is IFunction) {
- IFunction f = (IFunction)v;
- return ScriptConvert.ToString (f.Call (cx, scope, obj, EmptyArgs));
- }
- return ScriptConvert.ToString (value);
- }
- WarnAboutNonJSObject (value);
- return value.ToString ();
- }
-
- internal static string defaultObjectToSource (Context cx, IScriptable scope, IScriptable thisObj, object [] args)
- {
- using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier (1024)) {
- bool toplevel, iterating;
- if (cx.iterating == null) {
- toplevel = true;
- iterating = false;
- cx.iterating = new ObjToIntMap (31);
- }
- else {
- toplevel = false;
- iterating = cx.iterating.has (thisObj);
- }
-
- System.Text.StringBuilder result = new System.Text.StringBuilder (128);
- if (toplevel) {
- result.Append ("(");
- }
- result.Append ('{');
-
- // Make sure cx.iterating is set to null when done
- // so we don't leak memory
- try {
- if (!iterating) {
- cx.iterating.intern (thisObj); // stop recursion.
- object [] ids = thisObj.GetIds ();
- for (int i = 0; i < ids.Length; i++) {
- if (i > 0)
- result.Append (", ");
- object id = ids [i];
- object value;
- if (id is int) {
- int intId = ((int)id);
- value = thisObj.Get (intId, thisObj);
- result.Append (intId);
- }
- else {
- string strId = (string)id;
- value = thisObj.Get (strId, thisObj);
- if (ScriptRuntime.isValidIdentifierName (strId)) {
- result.Append (strId);
- }
- else {
- result.Append ('\'');
- result.Append (ScriptRuntime.escapeString (strId, '\''));
- result.Append ('\'');
- }
- }
- result.Append (':');
- result.Append (ScriptRuntime.uneval (cx, scope, value));
- }
- }
- }
- finally {
- if (toplevel) {
- cx.iterating = null;
- }
- }
-
- result.Append ('}');
- if (toplevel) {
- result.Append (')');
- }
- return result.ToString ();
- }
- }
-
-
-
-
- public static IScriptable NewObject (Context cx, IScriptable scope, string constructorName, object [] args)
- {
- scope = ScriptableObject.GetTopLevelScope (scope);
- IFunction ctor = getExistingCtor (cx, scope, constructorName);
- if (args == null) {
- args = ScriptRuntime.EmptyArgs;
- }
- return ctor.Construct (cx, scope, args);
- }
-
-
- // TODO: this is until setDefaultNamespace will learn how to store NS
- // TODO: properly and separates namespace form Scriptable.get etc.
- private const string DEFAULT_NS_TAG = "__default_namespace__";
-
- public static object setDefaultNamespace (object ns, Context cx)
- {
- IScriptable scope = cx.currentActivationCall;
- if (scope == null) {
- scope = getTopCallScope (cx);
- }
-
- XMLLib xmlLib = CurrentXMLLib (cx);
- object obj = xmlLib.ToDefaultXmlNamespace (cx, ns);
-
- // TODO: this should be in separated namesapce from Scriptable.get/put
- if (!scope.Has (DEFAULT_NS_TAG, scope)) {
- // TODO: this is racy of cause
- ScriptableObject.DefineProperty (scope, DEFAULT_NS_TAG, obj, ScriptableObject.PERMANENT | ScriptableObject.DONTENUM);
- }
- else {
- scope.Put (DEFAULT_NS_TAG, scope, obj);
- }
-
- return Undefined.Value;
- }
-
- public static object searchDefaultNamespace (Context cx)
- {
- IScriptable scope = cx.currentActivationCall;
- if (scope == null) {
- scope = getTopCallScope (cx);
- }
- object nsObject;
- for (; ; ) {
- IScriptable parent = scope.ParentScope;
- if (parent == null) {
- nsObject = ScriptableObject.GetProperty (scope, DEFAULT_NS_TAG);
- if (nsObject == UniqueTag.NotFound) {
- return null;
- }
- break;
- }
- nsObject = scope.Get (DEFAULT_NS_TAG, scope);
- if (nsObject != UniqueTag.NotFound) {
- break;
- }
- scope = parent;
- }
- return nsObject;
- }
-
- public static object getTopLevelProp (IScriptable scope, string id)
- {
- scope = ScriptableObject.GetTopLevelScope (scope);
- return ScriptableObject.GetProperty (scope, id);
- }
-
- internal static IFunction getExistingCtor (Context cx, IScriptable scope, string constructorName)
- {
- object ctorVal = ScriptableObject.GetProperty (scope, constructorName);
- if (ctorVal is IFunction) {
- return (IFunction)ctorVal;
- }
- if (ctorVal == UniqueTag.NotFound) {
- throw Context.ReportRuntimeErrorById ("msg.ctor.not.found", constructorName);
- }
- else {
- throw Context.ReportRuntimeErrorById ("msg.not.ctor", constructorName);
- }
- }
-
- /// Return -1L if str is not an index or the index value as lower 32
- /// bits of the result.
- ///
- private static long indexFromString (string str)
- {
- // The length of the decimal string representation of
- // Integer.MAX_VALUE, 2147483647
- const int MAX_VALUE_LENGTH = 10;
-
- int len = str.Length;
- if (len > 0) {
- int i = 0;
- bool negate = false;
- int c = str [0];
- if (c == '-') {
- if (len > 1) {
- c = str [1];
- i = 1;
- negate = true;
- }
- }
- c -= '0';
- if (0 <= c && c <= 9 && len <= (negate ? MAX_VALUE_LENGTH + 1 : MAX_VALUE_LENGTH)) {
- // Use negative numbers to accumulate index to handle
- // Integer.MIN_VALUE that is greater by 1 in absolute value
- // then Integer.MAX_VALUE
- int index = -c;
- int oldIndex = 0;
- i++;
- if (index != 0) {
- // Note that 00, 01, 000 etc. are not indexes
- while (i != len && 0 <= (c = str [i] - '0') && c <= 9) {
- oldIndex = index;
- index = 10 * index - c;
- i++;
- }
- }
- // Make sure all characters were consumed and that it couldn't
- // have overflowed.
- if (i == len && (oldIndex > (int.MinValue / 10) || (oldIndex == (int.MinValue / 10) && c <= (negate ? -(int.MinValue % 10) : (int.MaxValue % 10))))) {
- return unchecked ((int)0xFFFFFFFFL) & (negate ? index : -index);
- }
- }
- }
- return -1L;
- }
-
- /// If str is a decimal presentation of Uint32 value, return it as long.
- /// Othewise return -1L;
- ///
- public static long testUint32String (string str)
- {
- // The length of the decimal string representation of
- // UINT32_MAX_VALUE, 4294967296
- const int MAX_VALUE_LENGTH = 10;
-
- int len = str.Length;
- if (1 <= len && len <= MAX_VALUE_LENGTH) {
- int c = str [0];
- c -= '0';
- if (c == 0) {
- // Note that 00,01 etc. are not valid Uint32 presentations
- return (len == 1) ? 0L : -1L;
- }
- if (1 <= c && c <= 9) {
- long v = c;
- for (int i = 1; i != len; ++i) {
- c = str [i] - '0';
- if (!(0 <= c && c <= 9)) {
- return -1;
- }
- v = 10 * v + c;
- }
- // Check for overflow
- if ((ulong)v >> 32 == 0) {
- return v;
- }
- }
- }
- return -1;
- }
-
- /// If s represents index, then return index value wrapped as Integer
- /// and othewise return s.
- ///
- internal static object getIndexObject (string s)
- {
- long indexTest = indexFromString (s);
- if (indexTest >= 0) {
- return (int)indexTest;
- }
- return s;
- }
-
- /// If d is exact int value, return its value wrapped as Integer
- /// and othewise return d converted to String.
- ///
- internal static object getIndexObject (double d)
- {
- int i = (int)d;
- if ((double)i == d) {
- return (int)i;
- }
- return ScriptConvert.ToString (d);
- }
-
- /// If ScriptConvert.ToString(id) is a decimal presentation of int32 value, then id
- /// is index. In this case return null and make the index available
- /// as ScriptRuntime.lastIndexResult(cx). Otherwise return ScriptConvert.ToString(id).
- ///
- internal static string ToStringIdOrIndex (Context cx, object id)
- {
- if (CliHelper.IsNumber (id)) {
- double d = Convert.ToDouble (id);
- int index = (int)d;
- if (((double)index) == d) {
- storeIndexResult (cx, index);
- return null;
- }
- return ScriptConvert.ToString (id);
- }
- else {
- string s;
- if (id is string) {
- s = ((string)id);
- }
- else {
- s = ScriptConvert.ToString (id);
- }
- long indexTest = indexFromString (s);
- if (indexTest >= 0) {
- storeIndexResult (cx, (int)indexTest);
- return null;
- }
- return s;
- }
- }
-
- /// Call obj.[[Get]](id)
- public static object getObjectElem (object obj, object elem, Context cx)
- {
- IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj);
- if (sobj == null) {
- throw UndefReadError (obj, elem);
- }
- return getObjectElem (sobj, elem, cx);
- }
-
- public static object getObjectElem (IScriptable obj, object elem, Context cx)
- {
- if (obj is XMLObject) {
- XMLObject xmlObject = (XMLObject)obj;
- return xmlObject.EcmaGet (cx, elem);
- }
-
- object result;
-
- string s = ScriptRuntime.ToStringIdOrIndex (cx, elem);
- if (s == null) {
- int index = lastIndexResult (cx);
- result = ScriptableObject.GetProperty (obj, index);
- }
- else {
- result = ScriptableObject.GetProperty (obj, s);
- }
-
- if (result == UniqueTag.NotFound) {
- result = Undefined.Value;
- }
-
- return result;
- }
-
- /// Version of getObjectElem when elem is a valid JS identifier name.
- public static object getObjectProp (object obj, string property, Context cx)
- {
- IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj);
- if (sobj == null) {
- throw UndefReadError (obj, property);
- }
- return getObjectProp (sobj, property, cx);
- }
-
- public static object getObjectProp (IScriptable obj, string property, Context cx)
- {
- if (obj is XMLObject) {
- XMLObject xmlObject = (XMLObject)obj;
- return xmlObject.EcmaGet (cx, property);
- }
-
- object result = ScriptableObject.GetProperty (obj, property);
- if (result == UniqueTag.NotFound) {
- result = Undefined.Value;
- }
-
- return result;
- }
-
- /*
- * A cheaper and less general version of the above for well-known argument
- * types.
- */
- public static object getObjectIndex (object obj, double dblIndex, Context cx)
- {
- IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj);
- if (sobj == null) {
- throw UndefReadError (obj, ScriptConvert.ToString (dblIndex));
- }
- int index = (int)dblIndex;
- if ((double)index == dblIndex) {
- return getObjectIndex (sobj, index, cx);
- }
- else {
- string s = ScriptConvert.ToString (dblIndex);
- return getObjectProp (sobj, s, cx);
- }
- }
-
- public static object getObjectIndex (IScriptable obj, int index, Context cx)
- {
- if (obj is XMLObject) {
- XMLObject xmlObject = (XMLObject)obj;
- return xmlObject.EcmaGet (cx, (object)index);
- }
-
- object result = ScriptableObject.GetProperty (obj, index);
- if (result == UniqueTag.NotFound) {
- result = Undefined.Value;
- }
-
- return result;
- }
-
- /*
- * Call obj.[[Put]](id, value)
- */
- public static object setObjectElem (object obj, object elem, object value, Context cx)
- {
- IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj);
- if (sobj == null) {
- throw UndefWriteError (obj, elem, value);
- }
- return setObjectElem (sobj, elem, value, cx);
- }
-
- public static object setObjectElem (IScriptable obj, object elem, object value, Context cx)
- {
- if (obj is XMLObject) {
- XMLObject xmlObject = (XMLObject)obj;
- xmlObject.EcmaPut (cx, elem, value);
- return value;
- }
-
- string s = ScriptRuntime.ToStringIdOrIndex (cx, elem);
- if (s == null) {
- int index = lastIndexResult (cx);
- ScriptableObject.PutProperty (obj, index, value);
- }
- else {
- ScriptableObject.PutProperty (obj, s, value);
- }
-
- return value;
- }
-
- /// Version of setObjectElem when elem is a valid JS identifier name.
- public static object setObjectProp (object obj, string property, object value, Context cx)
- {
- IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj);
- if (sobj == null) {
- throw UndefWriteError (obj, property, value);
- }
- return setObjectProp (sobj, property, value, cx);
- }
-
- public static object setObjectProp (IScriptable obj, string property, object value, Context cx)
- {
- if (obj is XMLObject) {
- XMLObject xmlObject = (XMLObject)obj;
- xmlObject.EcmaPut (cx, property, value);
- }
- else {
- return ScriptableObject.PutProperty (obj, property, value);
- }
- return value;
- }
-
- /*
- * A cheaper and less general version of the above for well-known argument
- * types.
- */
- public static object setObjectIndex (object obj, double dblIndex, object value, Context cx)
- {
- IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj);
- if (sobj == null) {
- throw UndefWriteError (obj, Convert.ToString (dblIndex), value);
- }
- int index = (int)dblIndex;
- if ((double)index == dblIndex) {
- return setObjectIndex (sobj, index, value, cx);
- }
- else {
- string s = ScriptConvert.ToString (dblIndex);
- return setObjectProp (sobj, s, value, cx);
- }
- }
-
- public static object setObjectIndex (IScriptable obj, int index, object value, Context cx)
- {
- if (obj is XMLObject) {
- XMLObject xmlObject = (XMLObject)obj;
- xmlObject.EcmaPut (cx, (object)index, value);
- }
- else {
- return ScriptableObject.PutProperty (obj, index, value);
- }
- return value;
- }
-
- public static bool deleteObjectElem (IScriptable target, object elem, Context cx)
- {
- bool result;
- if (target is XMLObject) {
- XMLObject xmlObject = (XMLObject)target;
- result = xmlObject.EcmaDelete (cx, elem);
- }
- else {
- string s = ScriptRuntime.ToStringIdOrIndex (cx, elem);
- if (s == null) {
- int index = lastIndexResult (cx);
- result = ScriptableObject.DeleteProperty (target, index);
- }
- else {
- result = ScriptableObject.DeleteProperty (target, s);
- }
- }
- return result;
- }
-
- public static bool hasObjectElem (IScriptable target, object elem, Context cx)
- {
- bool result;
-
- if (target is XMLObject) {
- XMLObject xmlObject = (XMLObject)target;
- result = xmlObject.EcmaHas (cx, elem);
- }
- else {
- string s = ScriptRuntime.ToStringIdOrIndex (cx, elem);
- if (s == null) {
- int index = lastIndexResult (cx);
- result = ScriptableObject.HasProperty (target, index);
- }
- else {
- result = ScriptableObject.HasProperty (target, s);
- }
- }
-
- return result;
- }
-
- public static object refGet (IRef rf, Context cx)
- {
- return rf.Get (cx);
- }
-
- public static object refSet (IRef rf, object value, Context cx)
- {
- return rf.Set (cx, value);
- }
-
- public static object refDel (IRef rf, Context cx)
- {
- return rf.Delete (cx);
- }
-
- internal static bool isSpecialProperty (string s)
- {
- return s.Equals ("__proto__") || s.Equals ("__parent__");
- }
-
- public static IRef specialRef (object obj, string specialProperty, Context cx)
- {
- return SpecialRef.createSpecial (cx, obj, specialProperty);
- }
-
- /// The delete operator
- ///
- /// See ECMA 11.4.1
- ///
- /// In ECMA 0.19, the description of the delete operator (11.4.1)
- /// assumes that the [[Delete]] method returns a value. However,
- /// the definition of the [[Delete]] operator (8.6.2.5) does not
- /// define a return value. Here we assume that the [[Delete]]
- /// method doesn't return a value.
- ///
- public static object delete (object obj, object id, Context cx)
- {
- IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj);
- if (sobj == null) {
- string idStr = (id == null) ? "null" : id.ToString ();
- throw TypeErrorById ("msg.undef.prop.delete", ScriptConvert.ToString (obj), idStr);
- }
- bool result = deleteObjectElem (sobj, id, cx);
- return result;
- }
-
- /// Looks up a name in the scope chain and returns its value.
- public static object name (Context cx, IScriptable scope, string name)
- {
- IScriptable parent = scope.ParentScope;
- if (parent == null) {
- object result = topScopeName (cx, scope, name);
- if (result == UniqueTag.NotFound) {
- throw NotFoundError (scope, name);
- }
- return result;
- }
-
- return nameOrFunction (cx, scope, parent, name, false);
- }
-
- private static object nameOrFunction (Context cx, IScriptable scope, IScriptable parentScope, string name, bool asFunctionCall)
- {
- object result;
- IScriptable thisObj = scope; // It is used only if asFunctionCall==true.
-
- XMLObject firstXMLObject = null;
- for (; ; ) {
- if (scope is BuiltinWith) {
- IScriptable withObj = scope.GetPrototype ();
- if (withObj is XMLObject) {
- XMLObject xmlObj = (XMLObject)withObj;
- if (xmlObj.EcmaHas (cx, name)) {
- // function this should be the target object of with
- thisObj = xmlObj;
- result = xmlObj.EcmaGet (cx, name);
- break;
- }
- if (firstXMLObject == null) {
- firstXMLObject = xmlObj;
- }
- }
- else {
- result = ScriptableObject.GetProperty (withObj, name);
- if (result != UniqueTag.NotFound) {
- // function this should be the target object of with
- thisObj = withObj;
- break;
- }
- }
- }
- else if (scope is BuiltinCall) {
- // NativeCall does not prototype chain and Scriptable.get
- // can be called directly.
- result = scope.Get (name, scope);
- if (result != UniqueTag.NotFound) {
- if (asFunctionCall) {
- // ECMA 262 requires that this for nested funtions
- // should be top scope
- thisObj = ScriptableObject.GetTopLevelScope (parentScope);
- }
- break;
- }
- }
- else {
- // Can happen if embedding decided that nested
- // scopes are useful for what ever reasons.
- result = ScriptableObject.GetProperty (scope, name);
- if (result != UniqueTag.NotFound) {
- thisObj = scope;
- break;
- }
- }
- scope = parentScope;
- parentScope = parentScope.ParentScope;
- if (parentScope == null) {
- result = topScopeName (cx, scope, name);
- if (result == UniqueTag.NotFound) {
- if (firstXMLObject == null || asFunctionCall) {
- throw NotFoundError (scope, name);
- }
- // The name was not found, but we did find an XML
- // object in the scope chain and we are looking for name,
- // not function. The result should be an empty XMLList
- // in name context.
- result = firstXMLObject.EcmaGet (cx, name);
- }
- // For top scope thisObj for functions is always scope itself.
- thisObj = scope;
- break;
- }
- }
-
- if (asFunctionCall) {
- if (!(result is ICallable)) {
- throw NotFunctionError (result, name);
- }
- storeScriptable (cx, thisObj);
- }
-
- return result;
- }
-
- private static object topScopeName (Context cx, IScriptable scope, string name)
- {
- if (cx.useDynamicScope) {
- scope = checkDynamicScope (cx.topCallScope, scope);
- }
- return ScriptableObject.GetProperty (scope, name);
- }
-
-
- /// Returns the object in the scope chain that has a given property.
- ///
- /// The order of evaluation of an assignment expression involves
- /// evaluating the lhs to a reference, evaluating the rhs, and then
- /// modifying the reference with the rhs value. This method is used
- /// to 'bind' the given name to an object containing that property
- /// so that the side effects of evaluating the rhs do not affect
- /// which property is modified.
- /// Typically used in conjunction with setName.
- ///
- /// See ECMA 10.1.4
- ///
- public static IScriptable bind (Context cx, IScriptable scope, string id)
- {
- IScriptable firstXMLObject = null;
- IScriptable parent = scope.ParentScope;
- if (parent != null) {
- // Check for possibly nested "with" scopes first
- while (scope is BuiltinWith) {
- IScriptable withObj = scope.GetPrototype ();
- if (withObj is XMLObject) {
- XMLObject xmlObject = (XMLObject)withObj;
- if (xmlObject.EcmaHas (cx, id)) {
- return xmlObject;
- }
- if (firstXMLObject == null) {
- firstXMLObject = xmlObject;
- }
- }
- else {
- if (ScriptableObject.HasProperty (withObj, id)) {
- return withObj;
- }
- }
- scope = parent;
- parent = parent.ParentScope;
- if (parent == null) {
-
- goto childScopesChecks_brk;
- }
- }
- for (; ; ) {
- if (ScriptableObject.HasProperty (scope, id)) {
- return scope;
- }
- scope = parent;
- parent = parent.ParentScope;
- if (parent == null) {
-
- goto childScopesChecks_brk;
- }
- }
- }
-
- childScopesChecks_brk:
- ;
-
- // scope here is top scope
- if (cx.useDynamicScope) {
- scope = checkDynamicScope (cx.topCallScope, scope);
- }
- if (ScriptableObject.HasProperty (scope, id)) {
- return scope;
- }
- // Nothing was found, but since XML objects always bind
- // return one if found
- return firstXMLObject;
- }
-
- public static object setName (IScriptable bound, object value, Context cx, IScriptable scope, string id)
- {
- if (bound != null) {
- if (bound is XMLObject) {
- XMLObject xmlObject = (XMLObject)bound;
- xmlObject.EcmaPut (cx, id, value);
- }
- else {
- ScriptableObject.PutProperty (bound, id, value);
- }
- }
- else {
- // "newname = 7;", where 'newname' has not yet
- // been defined, creates a new property in the
- // top scope unless strict mode is specified.
- if (cx.HasFeature (Context.Features.StrictVars)) {
- throw Context.ReportRuntimeErrorById ("msg.assn.create.strict", id);
- }
- // Find the top scope by walking up the scope chain.
- bound = ScriptableObject.GetTopLevelScope (scope);
- if (cx.useDynamicScope) {
- bound = checkDynamicScope (cx.topCallScope, bound);
- }
- bound.Put (id, bound, value);
- }
- return value;
- }
-
-
-
-
-
-
- /// Prepare for calling name(...): return function corresponding to
- /// name and make current top scope available
- /// as ScriptRuntime.lastStoredScriptable() for consumption as thisObj.
- /// The caller must call ScriptRuntime.lastStoredScriptable() immediately
- /// after calling this method.
- ///
- public static ICallable getNameFunctionAndThis (string name, Context cx, IScriptable scope)
- {
- IScriptable parent = scope.ParentScope;
- if (parent == null) {
- object result = topScopeName (cx, scope, name);
- if (!(result is ICallable)) {
- if (result == UniqueTag.NotFound) {
- throw NotFoundError (scope, name);
- }
- else {
- throw NotFunctionError (result, name);
- }
- }
- // Top scope is not NativeWith or NativeCall => thisObj == scope
- IScriptable thisObj = scope;
- storeScriptable (cx, thisObj);
- return (ICallable)result;
- }
-
- // name will call storeScriptable(cx, thisObj);
- return (ICallable)nameOrFunction (cx, scope, parent, name, true);
- }
-
- /// Prepare for calling obj[id](...): return function corresponding to
- /// obj[id] and make obj properly converted to Scriptable available
- /// as ScriptRuntime.lastStoredScriptable() for consumption as thisObj.
- /// The caller must call ScriptRuntime.lastStoredScriptable() immediately
- /// after calling this method.
- ///
- public static ICallable GetElemFunctionAndThis (object obj, object elem, Context cx)
- {
- string s = ScriptRuntime.ToStringIdOrIndex (cx, elem);
- if (s != null) {
- return getPropFunctionAndThis (obj, s, cx);
- }
- int index = lastIndexResult (cx);
-
- IScriptable thisObj = ScriptConvert.ToObjectOrNull (cx, obj);
- if (thisObj == null) {
- throw UndefCallError (obj, Convert.ToString (index));
- }
-
- object value;
- for (; ; ) {
- // Ignore XML lookup as requred by ECMA 357, 11.2.2.1
- value = ScriptableObject.GetProperty (thisObj, index);
- if (value != UniqueTag.NotFound) {
- break;
- }
- if (!(thisObj is XMLObject)) {
- break;
- }
- XMLObject xmlObject = (XMLObject)thisObj;
- IScriptable extra = xmlObject.GetExtraMethodSource (cx);
- if (extra == null) {
- break;
- }
- thisObj = extra;
- }
- if (!(value is ICallable)) {
- throw NotFunctionError (value, elem);
- }
-
- storeScriptable (cx, thisObj);
- return (ICallable)value;
- }
-
- /// Prepare for calling obj.property(...): return function corresponding to
- /// obj.property and make obj properly converted to Scriptable available
- /// as ScriptRuntime.lastStoredScriptable() for consumption as thisObj.
- /// The caller must call ScriptRuntime.lastStoredScriptable() immediately
- /// after calling this method.
- ///
- public static ICallable getPropFunctionAndThis (object obj, string property, Context cx)
- {
- IScriptable thisObj = ScriptConvert.ToObjectOrNull (cx, obj);
- if (thisObj == null) {
- throw UndefCallError (obj, property);
- }
-
- object value;
- for (; ; ) {
- // Ignore XML lookup as requred by ECMA 357, 11.2.2.1
- value = ScriptableObject.GetProperty (thisObj, property);
- if (value != UniqueTag.NotFound) {
- break;
- }
- if (!(thisObj is XMLObject)) {
- break;
- }
- XMLObject xmlObject = (XMLObject)thisObj;
- IScriptable extra = xmlObject.GetExtraMethodSource (cx);
- if (extra == null) {
- break;
- }
- thisObj = extra;
- }
-
- if (value == UniqueTag.NotFound) {
- //if (thisObj.Get ("__noSuchMethod__", thisObj) as ICallable != null) {
- // return UniqueTag.NoSuchMethodMark;
- //}
- }
-
- if (!(value is ICallable)) {
- throw NotFunctionError (value, property);
- }
-
- storeScriptable (cx, thisObj);
- return (ICallable)value;
- }
-
- /// Prepare for calling (...): return function corresponding to
- /// and make parent scope of the function available
- /// as ScriptRuntime.lastStoredScriptable() for consumption as thisObj.
- /// The caller must call ScriptRuntime.lastStoredScriptable() immediately
- /// after calling this method.
- ///
- public static ICallable getValueFunctionAndThis (object value, Context cx)
- {
- if (!(value is ICallable)) {
- throw NotFunctionError (value);
- }
-
- ICallable f = (ICallable)value;
- IScriptable thisObj;
- if (f is IScriptable) {
- thisObj = ((IScriptable)f).ParentScope;
- }
- else {
- if (cx.topCallScope == null)
- throw new Exception ();
- thisObj = cx.topCallScope;
- }
- if (thisObj.ParentScope != null) {
- if (thisObj is BuiltinWith) {
- // functions defined inside with should have with target
- // as their thisObj
- }
- else if (thisObj is BuiltinCall) {
- // nested functions should have top scope as their thisObj
- thisObj = ScriptableObject.GetTopLevelScope (thisObj);
- }
- }
- storeScriptable (cx, thisObj);
- return f;
- }
-
- /// Perform function call in reference context. Should always
- /// return value that can be passed to
- /// {@link #refGet(Object)} or @link #refSet(Object, Object)}
- /// arbitrary number of times.
- /// The args array reference should not be stored in any object that is
- /// can be GC-reachable after this method returns. If this is necessary,
- /// store args.clone(), not args array itself.
- ///
- public static IRef callRef (ICallable function, IScriptable thisObj, object [] args, Context cx)
- {
- if (function is IRefCallable) {
- IRefCallable rfunction = (IRefCallable)function;
- IRef rf = rfunction.RefCall (cx, thisObj, args);
- if (rf == null) {
- throw new ApplicationException (rfunction.GetType ().FullName + ".refCall() returned null");
- }
- return rf;
- }
- // No runtime support for now
- string msg = GetMessage ("msg.no.ref.from.function", ScriptConvert.ToString (function));
- throw ConstructError ("ReferenceError", msg);
- }
-
- /// Operator new.
- ///
- /// See ECMA 11.2.2
- ///
- public static IScriptable NewObject (object fun, Context cx, IScriptable scope, object [] args)
- {
- if (!(fun is IFunction)) {
- throw NotFunctionError (fun);
- }
- IFunction function = (IFunction)fun;
- return function.Construct (cx, scope, args);
- }
-
- public static object callSpecial (Context cx, ICallable fun, IScriptable thisObj, object [] args, IScriptable scope, IScriptable callerThis, int callType, string filename, int lineNumber)
- {
- if (callType == Node.SPECIALCALL_EVAL) {
- if (BuiltinGlobal.isEvalFunction (fun)) {
- return evalSpecial (cx, scope, callerThis, args, filename, lineNumber);
- }
- }
- else if (callType == Node.SPECIALCALL_WITH) {
- if (BuiltinWith.IsWithFunction (fun)) {
- throw Context.ReportRuntimeErrorById ("msg.only.from.new", "With");
- }
- }
- else {
- throw Context.CodeBug ();
- }
-
- return fun.Call (cx, scope, thisObj, args);
- }
-
- public static object newSpecial (Context cx, object fun, object [] args, IScriptable scope, int callType)
- {
- if (callType == Node.SPECIALCALL_EVAL) {
- if (BuiltinGlobal.isEvalFunction (fun)) {
- throw TypeErrorById ("msg.not.ctor", "eval");
- }
- }
- else if (callType == Node.SPECIALCALL_WITH) {
- if (BuiltinWith.IsWithFunction (fun)) {
- return BuiltinWith.NewWithSpecial (cx, scope, args);
- }
- }
- else {
- throw Context.CodeBug ();
- }
-
- return NewObject (fun, cx, scope, args);
- }
-
- /// Function.prototype.apply and Function.prototype.call
- ///
- /// See Ecma 15.3.4.[34]
- ///
- public static object applyOrCall (bool isApply, Context cx, IScriptable scope, IScriptable thisObj, object [] args)
- {
- int L = args.Length;
- ICallable function;
- if (thisObj is ICallable) {
- function = (ICallable)thisObj;
- }
- else {
- object value = thisObj.GetDefaultValue (typeof (IFunction));
- if (!(value is ICallable)) {
- throw ScriptRuntime.NotFunctionError (value, thisObj);
- }
- function = (ICallable)value;
- }
-
- IScriptable callThis = null;
- if (L != 0) {
- callThis = ScriptConvert.ToObjectOrNull (cx, args [0]);
- }
- if (callThis == null) {
- // This covers the case of args[0] == (null|undefined) as well.
- callThis = getTopCallScope (cx);
- }
-
- object [] callArgs;
- if (isApply) {
- // Follow Ecma 15.3.4.3
- if (L <= 1) {
- callArgs = ScriptRuntime.EmptyArgs;
- }
- else {
- object arg1 = args [1];
- if (arg1 == null || arg1 == Undefined.Value) {
- callArgs = ScriptRuntime.EmptyArgs;
- }
- else if (arg1 is BuiltinArray || arg1 is Arguments) {
- callArgs = cx.GetElements ((IScriptable)arg1);
- }
- else {
- throw ScriptRuntime.TypeErrorById ("msg.arg.isnt.array");
- }
- }
- }
- else {
- // Follow Ecma 15.3.4.4
- if (L <= 1) {
- callArgs = ScriptRuntime.EmptyArgs;
- }
- else {
- callArgs = new object [L - 1];
- Array.Copy (args, 1, callArgs, 0, L - 1);
- }
- }
-
- return function.Call (cx, scope, callThis, callArgs);
- }
-
- /// The eval function property of the global object.
- ///
- /// See ECMA 15.1.2.1
- ///
- public static object evalSpecial (Context cx, IScriptable scope, object thisArg, object [] args, string filename, int lineNumber)
- {
- if (args.Length < 1)
- return Undefined.Value;
- object x = args [0];
- if (!(x is string)) {
- if (cx.HasFeature (Context.Features.StrictEval)) {
- throw Context.ReportRuntimeErrorById ("msg.eval.nonstring.strict");
- }
- string message = ScriptRuntime.GetMessage ("msg.eval.nonstring");
- Context.ReportWarning (message);
- return x;
- }
- if (filename == null) {
- int [] linep = new int [1];
- filename = Context.GetSourcePositionFromStack (linep);
- if (filename != null) {
- lineNumber = linep [0];
- }
- else {
- filename = "";
- }
- }
- string sourceName = ScriptRuntime.makeUrlForGeneratedScript (true, filename, lineNumber);
-
- ErrorReporter reporter;
- reporter = DefaultErrorReporter.ForEval (cx.ErrorReporter);
-
- // Compile with explicit interpreter instance to force interpreter
- // mode.
- IScript script = cx.CompileString ((string)x, new Interpreter (), reporter, sourceName, 1, (object)null);
- ((InterpretedFunction)script).idata.evalScriptFlag = true;
- ICallable c = (ICallable)script;
- return c.Call (cx, scope, (IScriptable)thisArg, ScriptRuntime.EmptyArgs);
- }
-
- /// The typeof operator
- public static string Typeof (object value)
- {
- if (value == null)
- return "object";
- if (value == Undefined.Value)
- return "undefined";
- if (value is IScriptable) {
- if (value is XMLObject)
- return "xml";
-
- return (value is ICallable && !(value is BuiltinRegExp)) ? "function" : "object";
- }
- if (value is string)
- return "string";
- if (value is char || CliHelper.IsNumber (value))
- return "number";
- if (value is bool)
- return "boolean";
- throw errorWithClassName ("msg.invalid.type", value);
- }
-
-
- internal static ApplicationException errorWithClassName (string msg, object val)
- {
- return Context.ReportRuntimeErrorById (msg, val.GetType ().FullName);
- }
-
- /// The typeof operator that correctly handles the undefined case
- public static string TypeofName (IScriptable scope, string id)
- {
- Context cx = Context.CurrentContext;
- IScriptable val = bind (cx, scope, id);
- if (val == null)
- return "undefined";
- return Typeof (getObjectProp (val, id, cx));
- }
-
- // neg:
- // implement the '-' operator inline in the caller
- // as "-ScriptConvert.ToNumber(val)"
-
- // not:
- // implement the '!' operator inline in the caller
- // as "!toBoolean(val)"
-
- // bitnot:
- // implement the '~' operator inline in the caller
- // as "~toInt32(val)"
-
- public static object Add (object val1, object val2, Context cx)
- {
- if (CliHelper.IsNumber (val1) && CliHelper.IsNumber (val2)) {
- return (double)val1 + (double)val2;
- }
- if (val1 is XMLObject) {
- object test = ((XMLObject)val1).AddValues (cx, true, val2);
- if (test != UniqueTag.NotFound) {
- return test;
- }
- }
- if (val2 is XMLObject) {
- object test = ((XMLObject)val2).AddValues (cx, false, val1);
- if (test != UniqueTag.NotFound) {
- return test;
- }
- }
- if (val1 is EcmaScript.NET.Types.Cli.CliEventInfo) {
- return ((EcmaScript.NET.Types.Cli.CliEventInfo)val1).Add (val2, cx);
- }
- if (val1 is IScriptable)
- val1 = ((IScriptable)val1).GetDefaultValue (null);
- if (val2 is IScriptable)
- val2 = ((IScriptable)val2).GetDefaultValue (null);
- if (!(val1 is string) && !(val2 is string))
- if ((CliHelper.IsNumber (val1)) && (CliHelper.IsNumber (val2)))
- return (double)val1 + (double)val2;
- else
- return ScriptConvert.ToNumber (val1) + ScriptConvert.ToNumber (val2);
- return string.Concat (ScriptConvert.ToString (val1), ScriptConvert.ToString (val2));
- }
-
- public static object nameIncrDecr (IScriptable scopeChain, string id, int incrDecrMask)
- {
- IScriptable target;
- object value;
- {
- do {
- target = scopeChain;
- do {
- value = target.Get (id, scopeChain);
- if (value != UniqueTag.NotFound) {
-
- goto search_brk;
- }
- target = target.GetPrototype ();
- }
- while (target != null);
- scopeChain = scopeChain.ParentScope;
- }
- while (scopeChain != null);
- throw NotFoundError (scopeChain, id);
- }
-
- search_brk:
- ;
-
- return doScriptableIncrDecr (target, id, scopeChain, value, incrDecrMask);
- }
-
- public static object propIncrDecr (object obj, string id, Context cx, int incrDecrMask)
- {
- IScriptable start = ScriptConvert.ToObjectOrNull (cx, obj);
- if (start == null) {
- throw UndefReadError (obj, id);
- }
-
- IScriptable target = start;
- object value;
- {
- do {
- value = target.Get (id, start);
- if (value != UniqueTag.NotFound) {
-
- goto search1_brk;
- }
- target = target.GetPrototype ();
- }
- while (target != null);
- start.Put (id, start, double.NaN);
- return double.NaN;
- }
-
- search1_brk:
- ;
-
- return doScriptableIncrDecr (target, id, start, value, incrDecrMask);
- }
-
- private static object doScriptableIncrDecr (IScriptable target, string id, IScriptable protoChainStart, object value, int incrDecrMask)
- {
- bool post = ((incrDecrMask & Node.POST_FLAG) != 0);
- double number;
- if (CliHelper.IsNumber (value)) {
- number = Convert.ToDouble (value);
- }
- else {
- number = ScriptConvert.ToNumber (value);
- if (post) {
- // convert result to number
- value = number;
- }
- }
- if ((incrDecrMask & Node.DECR_FLAG) == 0) {
- ++number;
- }
- else {
- --number;
- }
- object result = number;
- target.Put (id, protoChainStart, result);
- if (post) {
- return value;
- }
- else {
- return result;
- }
- }
-
- public static object elemIncrDecr (object obj, object index, Context cx, int incrDecrMask)
- {
- object value = getObjectElem (obj, index, cx);
- bool post = ((incrDecrMask & Node.POST_FLAG) != 0);
- double number;
- if (CliHelper.IsNumber (value)) {
- number = Convert.ToDouble (value);
- }
- else {
- number = ScriptConvert.ToNumber (value);
- if (post) {
- // convert result to number
- value = number;
- }
- }
- if ((incrDecrMask & Node.DECR_FLAG) == 0) {
- ++number;
- }
- else {
- --number;
- }
- object result = number;
- setObjectElem (obj, index, result, cx);
- if (post) {
- return value;
- }
- else {
- return result;
- }
- }
-
- public static object refIncrDecr (IRef rf, Context cx, int incrDecrMask)
- {
- object value = rf.Get (cx);
- bool post = ((incrDecrMask & Node.POST_FLAG) != 0);
- double number;
- if (CliHelper.IsNumber (value)) {
- number = Convert.ToDouble (value);
- }
- else {
- number = ScriptConvert.ToNumber (value);
- if (post) {
- // convert result to number
- value = number;
- }
- }
- if ((incrDecrMask & Node.DECR_FLAG) == 0) {
- ++number;
- }
- else {
- --number;
- }
- rf.Set (cx, number);
- if (post) {
- return value;
- }
- else {
- return number;
- }
- }
-
-
- /// Equality
- ///
- /// See ECMA 11.9
- ///
- public static bool eq (object x, object y)
- {
- if (x == null || x == Undefined.Value) {
- if (y == null || y == Undefined.Value) {
- return true;
- }
- if (y is ScriptableObject) {
- object test = ((ScriptableObject)y).EquivalentValues (x);
- if (test != UniqueTag.NotFound) {
- return ((bool)test);
- }
- }
- return false;
- }
- else if (CliHelper.IsNumber (x)) {
- return eqNumber (Convert.ToDouble (x), y);
- }
- else if (x is string) {
- return eqString ((string)x, y);
- }
- else if (x is bool) {
- bool b = ((bool)x);
- if (y is bool) {
- return b == ((bool)y);
- }
- if (y is ScriptableObject) {
- object test = ((ScriptableObject)y).EquivalentValues (x);
- if (test != UniqueTag.NotFound) {
- return ((bool)test);
- }
- }
- return eqNumber (b ? 1.0 : 0.0, y);
- }
- else if (x is IScriptable) {
- if (y is IScriptable) {
- if (x == y) {
- return true;
- }
- if (x is ScriptableObject) {
- object test = ((ScriptableObject)x).EquivalentValues (y);
- if (test != UniqueTag.NotFound) {
- return ((bool)test);
- }
- }
- if (y is ScriptableObject) {
- object test = ((ScriptableObject)y).EquivalentValues (x);
- if (test != UniqueTag.NotFound) {
- return ((bool)test);
- }
- }
- if (x is Wrapper && y is Wrapper) {
- return ((Wrapper)x).Unwrap () == ((Wrapper)y).Unwrap ();
- }
- return false;
- }
- else if (y is bool) {
- if (x is ScriptableObject) {
- object test = ((ScriptableObject)x).EquivalentValues (y);
- if (test != UniqueTag.NotFound) {
- return ((bool)test);
- }
- }
- double d = ((bool)y) ? 1.0 : 0.0;
- return eqNumber (d, x);
- }
- else if (CliHelper.IsNumber (y)) {
- return eqNumber (Convert.ToDouble (y), x);
- }
- else if (y is string) {
- return eqString ((string)y, x);
- }
- // covers the case when y == Undefined.instance as well
- return false;
- }
- else {
- WarnAboutNonJSObject (x);
- return x == y;
- }
- }
-
- internal static bool eqNumber (double x, object y)
- {
- for (; ; ) {
- if (y == null || y == Undefined.Value) {
- return false;
- }
- else if (CliHelper.IsNumber (y)) {
- return x == Convert.ToDouble (y);
- }
- else if (y is string) {
- return x == ScriptConvert.ToNumber (y);
- }
- else if (y is bool) {
- return x == (((bool)y) ? 1.0 : +0.0);
- }
- else if (y is IScriptable) {
- if (y is ScriptableObject) {
- object xval = x;
- object test = ((ScriptableObject)y).EquivalentValues (xval);
- if (test != UniqueTag.NotFound) {
- return ((bool)test);
- }
- }
- y = ScriptConvert.ToPrimitive (y);
- }
- else {
- WarnAboutNonJSObject (y);
- return false;
- }
- }
- }
-
- private static bool eqString (string x, object y)
- {
- for (; ; ) {
- if (y == null || y == Undefined.Value) {
- return false;
- }
- else if (y is string) {
- return x.Equals (y);
- }
- else if (CliHelper.IsNumber (y)) {
- return ScriptConvert.ToNumber (x) == Convert.ToDouble (y);
- }
- else if (y is bool) {
- return ScriptConvert.ToNumber (x) == (((bool)y) ? 1.0 : 0.0);
- }
- else if (y is IScriptable) {
- if (y is ScriptableObject) {
- object test = ((ScriptableObject)y).EquivalentValues (x);
- if (test != UniqueTag.NotFound) {
- return ((bool)test);
- }
- }
- y = ScriptConvert.ToPrimitive (y);
- continue;
- }
- else {
- WarnAboutNonJSObject (y);
- return false;
- }
- }
- }
- public static bool shallowEq (object x, object y)
- {
- if (x == y) {
- if (!(CliHelper.IsNumber (x))) {
- return true;
- }
- // double.NaN check
- double d = Convert.ToDouble (x);
- return !double.IsNaN (d);
- }
- if (x == null || x == Undefined.Value) {
- return false;
- }
- else if (CliHelper.IsNumber (x)) {
- if (CliHelper.IsNumber (y)) {
- return Convert.ToDouble (x) == Convert.ToDouble (y);
- }
- }
- else if (x is string) {
- if (y is string) {
- return x.Equals (y);
- }
- }
- else if (x is bool) {
- if (y is bool) {
- return x.Equals (y);
- }
- }
- else if (x is IScriptable) {
- if (x is Wrapper && y is Wrapper) {
- return ((Wrapper)x).Unwrap () == ((Wrapper)y).Unwrap ();
- }
- }
- else {
- WarnAboutNonJSObject (x);
- return x == y;
- }
- return false;
- }
-
- /// The instanceof operator.
- ///
- ///
- /// a instanceof b
- ///
- public static bool InstanceOf (object a, object b, Context cx)
- {
- IScriptable sB = (b as IScriptable);
-
- // Check RHS is an object
- if (sB == null) {
- throw TypeErrorById ("msg.instanceof.not.object");
- }
-
- IScriptable sA = (a as IScriptable);
-
- // for primitive values on LHS, return false
- // TODO we may want to change this so that 5 instanceof Number == true
- if (sA == null) {
- return false;
- }
-
-
- return sB.HasInstance (sA);
- }
-
- /// Delegates to
- ///
- ///
- /// true iff rhs appears in lhs' proto chain
- ///
- protected internal static bool jsDelegatesTo (IScriptable lhs, IScriptable rhs)
- {
- IScriptable proto = lhs.GetPrototype ();
-
- while (proto != null) {
- if (proto.Equals (rhs))
- return true;
- proto = proto.GetPrototype ();
- }
-
- return false;
- }
-
- /// The in operator.
- ///
- /// This is a new JS 1.3 language feature. The in operator mirrors
- /// the operation of the for .. in construct, and tests whether the
- /// rhs has the property given by the lhs. It is different from the
- /// for .. in construct in that:
- ///
- it doesn't perform ToObject on the right hand side
- ///
- it returns true for DontEnum properties.
- ///
- /// the left hand operand
- ///
- /// the right hand operand
- ///
- ///
- /// true if property name or element number a is a property of b
- ///
- public static bool In (object a, object b, Context cx)
- {
- if (!(b is IScriptable)) {
- throw TypeErrorById ("msg.instanceof.not.object");
- }
-
- return hasObjectElem ((IScriptable)b, a, cx);
- }
-
- public static bool cmp_LT (object val1, object val2)
- {
- double d1, d2;
- if (CliHelper.IsNumber (val1) && CliHelper.IsNumber (val2)) {
- d1 = Convert.ToDouble (val1);
- d2 = Convert.ToDouble (val2);
- }
- else {
- if (val1 is IScriptable)
- val1 = ((IScriptable)val1).GetDefaultValue (typeof (long));
- if (val2 is IScriptable)
- val2 = ((IScriptable)val2).GetDefaultValue (typeof (long));
- if (val1 is string && val2 is string) {
- return String.CompareOrdinal (((string)val1), (string)val2) < 0;
- }
- d1 = ScriptConvert.ToNumber (val1);
- d2 = ScriptConvert.ToNumber (val2);
- }
- return d1 < d2;
- }
-
- public static bool cmp_LE (object val1, object val2)
- {
- double d1, d2;
- if (CliHelper.IsNumber (val1) && CliHelper.IsNumber (val2)) {
- d1 = Convert.ToDouble (val1);
- d2 = Convert.ToDouble (val2);
- }
- else {
- if (val1 is IScriptable)
- val1 = ((IScriptable)val1).GetDefaultValue (typeof (long));
- if (val2 is IScriptable)
- val2 = ((IScriptable)val2).GetDefaultValue (typeof (long));
- if (val1 is string && val2 is string) {
- return String.CompareOrdinal (((string)val1), (string)val2) <= 0;
- }
- d1 = ScriptConvert.ToNumber (val1);
- d2 = ScriptConvert.ToNumber (val2);
- }
- return d1 <= d2;
- }
-
-
- public static bool hasTopCall (Context cx)
- {
- return (cx.topCallScope != null);
- }
-
- public static IScriptable getTopCallScope (Context cx)
- {
- IScriptable scope = cx.topCallScope;
- if (scope == null) {
- throw new ApplicationException ();
- }
- return scope;
- }
-
- public static object DoTopCall (ICallable callable, Context cx, IScriptable scope, IScriptable thisObj, object [] args)
- {
- if (scope == null)
- throw new ArgumentException ();
- if (cx.topCallScope != null)
- throw new ApplicationException ();
-
- object result;
- cx.topCallScope = ScriptableObject.GetTopLevelScope (scope);
- cx.useDynamicScope = cx.HasFeature (Context.Features.DynamicScope);
- ContextFactory f = cx.Factory;
- try {
- result = f.DoTopCall (callable, cx, scope, thisObj, args);
- }
- finally {
- cx.topCallScope = null;
- // Cleanup cached references
- cx.cachedXMLLib = null;
-
- if (cx.currentActivationCall != null) {
- // Function should always call exitActivationFunction
- // if it creates activation record
- throw new ApplicationException (
- "ActivationCall without exitActivationFunction() invokation."
- );
- }
- }
- return result;
- }
-
- /// Return possibleDynamicScope if staticTopScope
- /// is present on its prototype chain and return staticTopScope
- /// otherwise.
- /// Should only be called when staticTopScope is top scope.
- ///
- internal static IScriptable checkDynamicScope (IScriptable possibleDynamicScope, IScriptable staticTopScope)
- {
- // Return cx.topCallScope if scope
- if (possibleDynamicScope == staticTopScope) {
- return possibleDynamicScope;
- }
- IScriptable proto = possibleDynamicScope;
- for (; ; ) {
- proto = proto.GetPrototype ();
- if (proto == staticTopScope) {
- return possibleDynamicScope;
- }
- if (proto == null) {
- return staticTopScope;
- }
- }
- }
-
- public static void initScript (BuiltinFunction funObj, IScriptable thisObj, Context cx, IScriptable scope, bool evalScript)
- {
- if (cx.topCallScope == null)
- throw new ApplicationException ();
-
- int varCount = funObj.ParamAndVarCount;
- if (varCount != 0) {
-
- IScriptable varScope = scope;
- // Never define any variables from var statements inside with
- // object. See bug 38590.
- while (varScope is BuiltinWith) {
- varScope = varScope.ParentScope;
- }
-
- for (int i = varCount; i-- != 0; ) {
- string name = funObj.getParamOrVarName (i);
- // Don't overwrite existing def if already defined in object
- // or prototypes of object.
- if (!ScriptableObject.HasProperty (scope, name)) {
- if (!evalScript) {
- // Global var definitions are supposed to be DONTDELETE
- ScriptableObject.DefineProperty (varScope, name, Undefined.Value, ScriptableObject.PERMANENT);
- }
- else {
- varScope.Put (name, varScope, Undefined.Value);
- }
- }
- }
- }
- }
-
- public static IScriptable createFunctionActivation (BuiltinFunction funObj, IScriptable scope, object [] args)
- {
- return new BuiltinCall (funObj, scope, args);
- }
-
-
- public static void enterActivationFunction (Context cx, IScriptable activation)
- {
- if (cx.topCallScope == null)
- throw new ApplicationException ();
-
- BuiltinCall call = (BuiltinCall)activation;
- call.parentActivationCall = cx.currentActivationCall;
- cx.currentActivationCall = call;
- }
-
- public static void exitActivationFunction (Context cx)
- {
- BuiltinCall call = cx.currentActivationCall;
- cx.currentActivationCall = call.parentActivationCall;
- call.parentActivationCall = null;
- }
-
- internal static BuiltinCall findFunctionActivation (Context cx, IFunction f)
- {
- BuiltinCall call = cx.currentActivationCall;
- while (call != null) {
- if (call.function == f)
- return call;
- call = call.parentActivationCall;
- }
- return null;
- }
-
- public static IScriptable NewCatchScope (Exception t, IScriptable lastCatchScope, string exceptionName, Context cx, IScriptable scope)
- {
- object obj;
- bool cacheObj;
-
- if (t is EcmaScriptThrow) {
- cacheObj = false;
- obj = ((EcmaScriptThrow)t).Value;
- }
- else {
- cacheObj = true;
-
- // Create wrapper object unless it was associated with
- // the previous scope object
-
- if (lastCatchScope != null) {
- BuiltinObject last = (BuiltinObject)lastCatchScope;
- obj = last.GetAssociatedValue (t);
- if (obj == null)
- Context.CodeBug ();
-
- goto getObj_brk;
- }
-
- EcmaScriptException re;
- string errorName;
- string errorMsg;
-
- Exception javaException = null;
-
- if (t is EcmaScriptError) {
- EcmaScriptError ee = (EcmaScriptError)t;
- re = ee;
- errorName = ee.Name;
- errorMsg = ee.ErrorMessage;
- }
- else if (t is EcmaScriptRuntimeException) {
- re = (EcmaScriptRuntimeException)t;
- if (t.InnerException != null) {
- javaException = t.InnerException;
- errorName = "JavaException";
- errorMsg = javaException.GetType ().FullName + ": " + javaException.Message;
- }
- else {
- errorName = "InternalError";
- errorMsg = re.Message;
- }
- }
- else {
- // Script can catch only instances of JavaScriptException,
- // EcmaError and EvaluatorException
- throw Context.CodeBug ();
- }
-
- string sourceUri = re.SourceName;
- if (sourceUri == null) {
- sourceUri = "";
- }
- int line = re.LineNumber;
- object [] args;
- if (line > 0) {
- args = new object [] { errorMsg, sourceUri, (int)line };
- }
- else {
- args = new object [] { errorMsg, sourceUri };
- }
-
- IScriptable errorObject = cx.NewObject (scope, errorName, args);
- ScriptableObject.PutProperty (errorObject, "name", errorName);
-
- if (javaException != null) {
- object wrap = cx.Wrap (scope, javaException, null);
- ScriptableObject.DefineProperty (errorObject, "javaException", wrap, ScriptableObject.PERMANENT | ScriptableObject.READONLY);
- }
- if (re != null) {
- object wrap = cx.Wrap (scope, re, null);
- ScriptableObject.DefineProperty (errorObject, "rhinoException", wrap, ScriptableObject.PERMANENT | ScriptableObject.READONLY);
- }
-
- obj = errorObject;
- }
-
- getObj_brk:
- ;
-
-
-
- BuiltinObject catchScopeObject = new BuiltinObject ();
- // See ECMA 12.4
- catchScopeObject.DefineProperty (exceptionName, obj, ScriptableObject.PERMANENT);
- if (cacheObj) {
- catchScopeObject.AssociateValue (t, obj);
- }
- return catchScopeObject;
- }
-
- public static IScriptable enterWith (object obj, Context cx, IScriptable scope)
- {
- IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj);
- if (sobj == null) {
- throw TypeErrorById ("msg.undef.with", ScriptConvert.ToString (obj));
- }
- if (sobj is XMLObject) {
- XMLObject xmlObject = (XMLObject)sobj;
- return xmlObject.EnterWith (scope);
- }
- return new BuiltinWith (scope, sobj);
- }
-
- public static IScriptable leaveWith (IScriptable scope)
- {
- BuiltinWith nw = (BuiltinWith)scope;
- return nw.ParentScope;
- }
-
- public static IScriptable enterDotQuery (object value, IScriptable scope)
- {
- if (!(value is XMLObject)) {
- throw NotXmlError (value);
- }
- XMLObject obj = (XMLObject)value;
- return obj.EnterDotQuery (scope);
- }
-
- public static object updateDotQuery (bool value, IScriptable scope)
- {
- // Return null to continue looping
- BuiltinWith nw = (BuiltinWith)scope;
- return nw.UpdateDotQuery (value);
- }
-
- public static IScriptable leaveDotQuery (IScriptable scope)
- {
- BuiltinWith nw = (BuiltinWith)scope;
- return nw.ParentScope;
- }
-
- public static void setFunctionProtoAndParent (BaseFunction fn, IScriptable scope)
- {
- fn.ParentScope = scope;
- fn.SetPrototype (ScriptableObject.GetFunctionPrototype (scope));
- }
-
- public static void setObjectProtoAndParent (ScriptableObject obj, IScriptable scope)
- {
- // Compared with function it always sets the scope to top scope
- scope = ScriptableObject.GetTopLevelScope (scope);
- obj.ParentScope = scope;
- IScriptable proto = ScriptableObject.getClassPrototype (scope, obj.ClassName);
- obj.SetPrototype (proto);
- }
-
- public static void initFunction (Context cx, IScriptable scope, BuiltinFunction function, int type, bool fromEvalCode)
- {
- if (type == FunctionNode.FUNCTION_STATEMENT) {
- string name = function.FunctionName;
- if (name != null && name.Length != 0) {
- if (!fromEvalCode) {
- // ECMA specifies that functions defined in global and
- // function scope outside eval should have DONTDELETE set.
- ScriptableObject.DefineProperty (scope, name, function, ScriptableObject.PERMANENT);
- }
- else {
- scope.Put (name, scope, function);
- }
- }
- }
- else if (type == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) {
- string name = function.FunctionName;
- if (name != null && name.Length != 0) {
- // Always put function expression statements into initial
- // activation object ignoring the with statement to follow
- // SpiderMonkey
- while (scope is BuiltinWith) {
- scope = scope.ParentScope;
- }
- scope.Put (name, scope, function);
- }
- }
- else {
- throw Context.CodeBug ();
- }
- }
-
- public static IScriptable newArrayLiteral (object [] objects, int [] skipIndexces, Context cx, IScriptable scope)
- {
- int count = objects.Length;
- int skipCount = 0;
- if (skipIndexces != null) {
- skipCount = skipIndexces.Length;
- }
- int length = count + skipCount;
- int lengthObj = (int)length;
- IScriptable arrayObj;
- /*
- * If the version is 120, then new Array(4) means create a new
- * array with 4 as the first element. In this case, we have to
- * set length property manually.
- */
- if (cx.Version == Context.Versions.JS1_2) {
- arrayObj = cx.NewObject (scope, "Array", ScriptRuntime.EmptyArgs);
- ScriptableObject.PutProperty (arrayObj, "length", (object)lengthObj);
- }
- else {
- arrayObj = cx.NewObject (scope, "Array", new object [] { lengthObj });
- }
- int skip = 0;
- for (int i = 0, j = 0; i != length; ++i) {
- if (skip != skipCount && skipIndexces [skip] == i) {
- ++skip;
- continue;
- }
- ScriptableObject.PutProperty (arrayObj, i, objects [j]);
- ++j;
- }
- return arrayObj;
- }
-
- public static IScriptable newObjectLiteral (object [] propertyIds, object [] propertyValues, Context cx, IScriptable scope)
- {
- IScriptable obj = cx.NewObject (scope);
- for (int i = 0, end = propertyIds.Length; i != end; ++i) {
- object id = propertyIds [i];
- object value = propertyValues [i];
-
- if (id is Node.GetterPropertyLiteral) {
- BuiltinObject nativeObj = (BuiltinObject)obj;
- InterpretedFunction fun = (InterpretedFunction)value;
- nativeObj.DefineGetter ((string)((Node.GetterPropertyLiteral)id).Property, fun);
- }
- else if (id is Node.SetterPropertyLiteral) {
- BuiltinObject nativeObj = (BuiltinObject)obj;
- InterpretedFunction fun = (InterpretedFunction)value;
- nativeObj.DefineSetter ((string)((Node.SetterPropertyLiteral)id).Property, fun);
- }
- else if (id is string) {
- ScriptableObject.PutProperty (obj, (string)id, value);
- }
- else {
- ScriptableObject.PutProperty (obj, (int)id, value);
- }
- }
- return obj;
- }
-
- public static bool isArrayObject (object obj)
- {
- return obj is BuiltinArray || obj is Arguments;
- }
-
- public static object [] getArrayElements (IScriptable obj)
- {
- Context cx = Context.CurrentContext;
- long longLen = BuiltinArray.getLengthProperty (cx, obj);
- if (longLen > int.MaxValue) {
- // arrays beyond MAX_INT is not in Java in any case
- throw new ArgumentException ();
- }
- int len = (int)longLen;
- if (len == 0) {
- return ScriptRuntime.EmptyArgs;
- }
- else {
- object [] result = new object [len];
- for (int i = 0; i < len; i++) {
- object elem = ScriptableObject.GetProperty (obj, i);
- result [i] = (elem == UniqueTag.NotFound) ? Undefined.Value : elem;
- }
- return result;
- }
- }
-
- internal static void checkDeprecated (Context cx, string name)
- {
- Context.Versions version = cx.Version;
- if (version >= Context.Versions.JS1_4 || version == Context.Versions.Default) {
- string msg = GetMessage ("msg.deprec.ctor", name);
- if (version == Context.Versions.Default)
- Context.ReportWarning (msg);
- else
- throw Context.ReportRuntimeError (msg);
- }
- }
-
-
- private static ResourceManager m_ResourceManager = null;
-
- public static string GetMessage (string messageId, params object [] arguments)
- {
- Context cx = Context.CurrentContext;
-
- // Get current culture
- CultureInfo culture = null;
- if (cx != null)
- culture = cx.CurrentCulture;
-
- if (m_ResourceManager == null) {
- m_ResourceManager = new ResourceManager (
- "EcmaScript.NET.Resources.Messages", typeof (ScriptRuntime).Assembly);
- }
-
- string formatString = m_ResourceManager.GetString (messageId, culture);
- if (formatString == null)
- throw new ApplicationException ("Missing no message resource found for message property " + messageId);
-
- if (arguments == null)
- arguments = new object [0];
- if (arguments.Length == 0)
- return formatString;
- return string.Format (formatString, arguments);
- }
-
- public static EcmaScriptError ConstructError (string error, string message)
- {
- int [] linep = new int [1];
- string filename = Context.GetSourcePositionFromStack (linep);
- return ConstructError (error, message, filename, linep [0], null, 0);
- }
-
- public static EcmaScriptError ConstructError (string error, string message, string sourceName, int lineNumber, string lineSource, int columnNumber)
- {
- return new EcmaScriptError (error, message, sourceName, lineNumber, lineSource, columnNumber);
- }
-
- public static EcmaScriptError TypeError (string message)
- {
- return ConstructError ("TypeError", message);
- }
-
- public static EcmaScriptError TypeErrorById (string messageId, params string [] args)
- {
- return TypeError (GetMessage (messageId, args));
- }
-
- public static ApplicationException UndefReadError (object obj, object id)
- {
- string idStr = (id == null) ? "null" : id.ToString ();
- return TypeErrorById ("msg.undef.prop.read", ScriptConvert.ToString (obj), idStr);
- }
-
- public static ApplicationException UndefCallError (object obj, object id)
- {
- string idStr = (id == null) ? "null" : id.ToString ();
- return TypeErrorById ("msg.undef.method.call", ScriptConvert.ToString (obj), idStr);
- }
-
- public static ApplicationException UndefWriteError (object obj, object id, object value)
- {
- string idStr = (id == null) ? "null" : id.ToString ();
- string valueStr = (value is IScriptable) ? value.ToString () : ScriptConvert.ToString (value);
- return TypeErrorById ("msg.undef.prop.write", ScriptConvert.ToString (obj), idStr, valueStr);
- }
-
- public static ApplicationException NotFoundError (IScriptable obj, string property)
- {
- // TODO: use object to improve the error message
- string msg = GetMessage ("msg.is.not.defined", property);
- throw ConstructError ("ReferenceError", msg);
- }
-
- public static ApplicationException NotFunctionError (object value)
- {
- return NotFunctionError (value, value);
- }
-
- public static ApplicationException NotFunctionError (object value, object messageHelper)
- {
- // TODO: Use value for better error reporting
- string msg = (messageHelper == null) ? "null" : messageHelper.ToString ();
- if (value == UniqueTag.NotFound) {
- return TypeErrorById ("msg.function.not.found", msg);
- }
- return TypeErrorById ("msg.isnt.function", msg, value == null ? "null" : value.GetType ().FullName);
- }
-
- private static ApplicationException NotXmlError (object value)
- {
- throw TypeErrorById ("msg.isnt.xml.object", ScriptConvert.ToString (value));
- }
-
- internal static void WarnAboutNonJSObject (object nonJSObject)
- {
- string message = "+++ USAGE WARNING: Missed Context.Wrap() conversion:\n"
- + "Runtime detected object " + nonJSObject + " of class " + nonJSObject.GetType ().FullName + " where it expected String, Number, Boolean or Scriptable instance. "
- + "Please check your code for missig Context.Wrap() call.";
-
- Context.ReportWarning (message);
- Console.Error.WriteLine (message);
- }
-
-
- private static XMLLib CurrentXMLLib (Context cx)
- {
- // Scripts should be running to access this
- if (cx.topCallScope == null)
- throw new ApplicationException ();
-
- XMLLib xmlLib = cx.cachedXMLLib;
- if (xmlLib == null) {
- xmlLib = XMLLib.ExtractFromScope (cx.topCallScope);
- if (xmlLib == null)
- throw new ApplicationException ();
- cx.cachedXMLLib = xmlLib;
- }
-
- return xmlLib;
- }
-
- /// Escapes the reserved characters in a value of an attribute
- ///
- ///
- /// Unescaped text
- ///
- /// The escaped text
- ///
- public static string escapeAttributeValue (object value, Context cx)
- {
- XMLLib xmlLib = CurrentXMLLib (cx);
- return xmlLib.EscapeAttributeValue (value);
- }
-
- /// Escapes the reserved characters in a value of a text node
- ///
- ///
- /// Unescaped text
- ///
- /// The escaped text
- ///
- public static string escapeTextValue (object value, Context cx)
- {
- XMLLib xmlLib = CurrentXMLLib (cx);
- return xmlLib.EscapeTextValue (value);
- }
-
- public static IRef memberRef (object obj, object elem, Context cx, int memberTypeFlags)
- {
- if (!(obj is XMLObject)) {
- throw NotXmlError (obj);
- }
- XMLObject xmlObject = (XMLObject)obj;
- return xmlObject.MemberRef (cx, elem, memberTypeFlags);
- }
-
- public static IRef memberRef (object obj, object ns, object elem, Context cx, int memberTypeFlags)
- {
- if (!(obj is XMLObject)) {
- throw NotXmlError (obj);
- }
- XMLObject xmlObject = (XMLObject)obj;
- return xmlObject.MemberRef (cx, ns, elem, memberTypeFlags);
- }
-
- public static IRef nameRef (object name, Context cx, IScriptable scope, int memberTypeFlags)
- {
- XMLLib xmlLib = CurrentXMLLib (cx);
- return xmlLib.NameRef (cx, name, scope, memberTypeFlags);
- }
-
- public static IRef nameRef (object ns, object name, Context cx, IScriptable scope, int memberTypeFlags)
- {
- XMLLib xmlLib = CurrentXMLLib (cx);
- return xmlLib.NameRef (cx, ns, name, scope, memberTypeFlags);
- }
-
- private static void storeIndexResult (Context cx, int index)
- {
- cx.scratchIndex = index;
- }
-
- internal static int lastIndexResult (Context cx)
- {
- return cx.scratchIndex;
- }
-
- public static void storeUint32Result (Context cx, long value)
- {
- if (((ulong)value >> 32) != 0)
- throw new ArgumentException ();
- cx.scratchUint32 = value;
- }
-
- public static long lastUint32Result (Context cx)
- {
- long value = cx.scratchUint32;
- if ((ulong)value >> 32 != 0)
- throw new ApplicationException ();
- return value;
- }
-
- private static void storeScriptable (Context cx, IScriptable value)
- {
- // The previosly stored scratchScriptable should be consumed
- if (cx.scratchScriptable != null)
- throw new ApplicationException ();
- cx.scratchScriptable = value;
- }
-
- public static IScriptable lastStoredScriptable (Context cx)
- {
- IScriptable result = cx.scratchScriptable;
- cx.scratchScriptable = null;
- return result;
- }
-
- internal static string makeUrlForGeneratedScript (bool isEval, string masterScriptUrl, int masterScriptLine)
- {
- if (isEval) {
- return masterScriptUrl + '#' + masterScriptLine + "(eval)";
- }
- else {
- return masterScriptUrl + '#' + masterScriptLine + "(Function)";
- }
- }
-
- internal static bool isGeneratedScript (string sourceUrl)
- {
- // ALERT: this may clash with a valid URL containing (eval) or
- // (Function)
- return sourceUrl.IndexOf ("(eval)") >= 0 || sourceUrl.IndexOf ("(Function)") >= 0;
- }
-
-
- public static readonly object [] EmptyArgs = new object [0];
- public static readonly string [] EmptyStrings = new string [0];
-
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+using System.Resources;
+using System.Globalization;
+using System.Text;
+using System.Threading;
+
+using EcmaScript.NET;
+using EcmaScript.NET.Types;
+using EcmaScript.NET.Types.RegExp;
+using EcmaScript.NET.Types.E4X;
+using EcmaScript.NET.Collections;
+
+namespace EcmaScript.NET
+{
+
+ /// This is the class that implements the runtime.
+ ///
+ ///
+ public class ScriptRuntime
+ {
+
+ /// No instances should be created.
+ protected internal ScriptRuntime ()
+ {
+ }
+
+ public const int MAXSTACKSIZE = 1000;
+
+ private const string XML_INIT_CLASS = "EcmaScript.NET.Xml.Impl.XMLLib";
+
+ private static readonly object LIBRARY_SCOPE_KEY = new object ();
+
+ public static bool IsNativeRuntimeType (Type cl)
+ {
+ if (cl.IsPrimitive) {
+ return (cl != typeof (char));
+ }
+ else {
+ return (cl == typeof (string) || cl == typeof (bool)
+ || CliHelper.IsNumberType (cl)
+ || typeof (IScriptable).IsAssignableFrom (cl));
+ }
+ }
+
+ public static ScriptableObject InitStandardObjects (Context cx, ScriptableObject scope, bool zealed)
+ {
+ if (scope == null) {
+ scope = new BuiltinObject ();
+ }
+ scope.AssociateValue (LIBRARY_SCOPE_KEY, scope);
+
+ BaseFunction.Init (scope, zealed);
+ BuiltinObject.Init (scope, zealed);
+
+ IScriptable objectProto = ScriptableObject.GetObjectPrototype (scope);
+
+ // Function.prototype.__proto__ should be Object.prototype
+ IScriptable functionProto = ScriptableObject.GetFunctionPrototype (scope);
+ functionProto.SetPrototype (objectProto);
+
+ // Set the prototype of the object passed in if need be
+ if (scope.GetPrototype () == null)
+ scope.SetPrototype (objectProto);
+
+ // must precede NativeGlobal since it's needed therein
+ BuiltinError.Init (scope, zealed);
+ BuiltinGlobal.Init (cx, scope, zealed);
+
+ if (scope is BuiltinGlobalObject) {
+ ((BuiltinGlobalObject)scope).Init (scope, zealed);
+ }
+
+ BuiltinArray.Init (scope, zealed);
+ BuiltinString.Init (scope, zealed);
+ BuiltinBoolean.Init (scope, zealed);
+ BuiltinNumber.Init (scope, zealed);
+ BuiltinDate.Init (scope, zealed);
+ BuiltinMath.Init (scope, zealed);
+
+ BuiltinWith.Init (scope, zealed);
+ BuiltinCall.Init (scope, zealed);
+ BuiltinScript.Init (scope, zealed);
+
+ BuiltinRegExp.Init (scope, zealed);
+
+ if (cx.HasFeature (Context.Features.E4x)) {
+ Types.E4X.XMLLib.Init (scope, zealed);
+ }
+
+ Continuation.Init (scope, zealed);
+
+ if (cx.HasFeature (Context.Features.NonEcmaItObject)) {
+ InitItObject (cx, scope);
+ }
+
+ return scope;
+ }
+
+ static void InitItObject (Context cx, ScriptableObject scope) {
+ BuiltinObject itObj = new BuiltinObject ();
+ itObj.SetPrototype (scope);
+ itObj.DefineProperty ("color", Undefined.Value, ScriptableObject.PERMANENT);
+ itObj.DefineProperty ("height", Undefined.Value, ScriptableObject.PERMANENT);
+ itObj.DefineProperty ("width", Undefined.Value, ScriptableObject.PERMANENT);
+ itObj.DefineProperty ("funny", Undefined.Value, ScriptableObject.PERMANENT);
+ itObj.DefineProperty ("array", Undefined.Value, ScriptableObject.PERMANENT);
+ itObj.DefineProperty ("rdonly", Undefined.Value, ScriptableObject.READONLY);
+ scope.DefineProperty ("it", itObj, ScriptableObject.PERMANENT);
+ }
+
+ public static ScriptableObject getLibraryScopeOrNull (IScriptable scope)
+ {
+ ScriptableObject libScope;
+ libScope = (ScriptableObject)ScriptableObject.GetTopScopeValue (scope, LIBRARY_SCOPE_KEY);
+ return libScope;
+ }
+
+ // It is public so NativeRegExp can access it .
+ public static bool isJSLineTerminator (int c)
+ {
+ // Optimization for faster check for eol character:
+ // they do not have 0xDFD0 bits set
+ if ((c & 0xDFD0) != 0) {
+ return false;
+ }
+ return c == '\n' || c == '\r' || c == 0x2028 || c == 0x2029;
+ }
+
+
+ /// Helper function for builtin objects that use the varargs form.
+ /// ECMA function formal arguments are undefined if not supplied;
+ /// this function pads the argument array out to the expected
+ /// length, if necessary.
+ ///
+ public static object [] padArguments (object [] args, int count)
+ {
+ if (count < args.Length)
+ return args;
+
+ int i;
+ object [] result = new object [count];
+ for (i = 0; i < args.Length; i++) {
+ result [i] = args [i];
+ }
+
+ for (; i < count; i++) {
+ result [i] = Undefined.Value;
+ }
+
+ return result;
+ }
+
+
+ public static string escapeString (string s)
+ {
+ return escapeString (s, '"');
+ }
+
+ /// For escaping strings printed by object and array literals; not quite
+ /// the same as 'escape.'
+ ///
+ public static string escapeString (string s, char escapeQuote)
+ {
+ if (!(escapeQuote == '"' || escapeQuote == '\''))
+ Context.CodeBug ();
+ System.Text.StringBuilder sb = null;
+
+ for (int i = 0, L = s.Length; i != L; ++i) {
+ int c = s [i];
+
+ if (' ' <= c && c <= '~' && c != escapeQuote && c != '\\') {
+ // an ordinary print character (like C isprint()) and not "
+ // or \ .
+ if (sb != null) {
+ sb.Append ((char)c);
+ }
+ continue;
+ }
+ if (sb == null) {
+ sb = new System.Text.StringBuilder (L + 3);
+ sb.Append (s);
+ sb.Length = i;
+ }
+
+ int escape = -1;
+ switch (c) {
+
+ case '\b':
+ escape = 'b';
+ break;
+
+ case '\f':
+ escape = 'f';
+ break;
+
+ case '\n':
+ escape = 'n';
+ break;
+
+ case '\r':
+ escape = 'r';
+ break;
+
+ case '\t':
+ escape = 't';
+ break;
+
+ case 0xb:
+ escape = 'v';
+ break; // Java lacks \v.
+
+ case ' ':
+ escape = ' ';
+ break;
+
+ case '\\':
+ escape = '\\';
+ break;
+ }
+ if (escape >= 0) {
+ // an \escaped sort of character
+ sb.Append ('\\');
+ sb.Append ((char)escape);
+ }
+ else if (c == escapeQuote) {
+ sb.Append ('\\');
+ sb.Append (escapeQuote);
+ }
+ else {
+ int hexSize;
+ if (c < 256) {
+ // 2-digit hex
+ sb.Append ("\\x");
+ hexSize = 2;
+ }
+ else {
+ // Unicode.
+ sb.Append ("\\u");
+ hexSize = 4;
+ }
+ // append hexadecimal form of c left-padded with 0
+ for (int shift = (hexSize - 1) * 4; shift >= 0; shift -= 4) {
+ int digit = 0xf & (c >> shift);
+ int hc = (digit < 10) ? '0' + digit : 'a' - 10 + digit;
+ sb.Append ((char)hc);
+ }
+ }
+ }
+ return (sb == null) ? s : sb.ToString ();
+ }
+
+ internal static bool isValidIdentifierName (string s)
+ {
+ int L = s.Length;
+ if (L == 0)
+ return false;
+ if (!(char.IsLetter (s [0]) || s [0].CompareTo ('$') == 0 || s [0].CompareTo ('_') == 0))
+ return false;
+ for (int i = 1; i != L; ++i) {
+ if (!TokenStream.IsJavaIdentifierPart (s [i]))
+ return false;
+ }
+ return !TokenStream.isKeyword (s);
+ }
+
+
+
+ internal static string DefaultObjectToString (IScriptable obj)
+ {
+ return "[object " + obj.ClassName + ']';
+ }
+
+ internal static string uneval (Context cx, IScriptable scope, object value)
+ {
+ if (value == null) {
+ return "null";
+ }
+ if (value == Undefined.Value) {
+ return "undefined";
+ }
+ if (value is string) {
+ string escaped = escapeString ((string)value);
+ System.Text.StringBuilder sb = new System.Text.StringBuilder (escaped.Length + 2);
+ sb.Append ('\"');
+ sb.Append (escaped);
+ sb.Append ('\"');
+ return sb.ToString ();
+ }
+ if (CliHelper.IsNumber (value)) {
+ double d = Convert.ToDouble (value);
+ if (d == 0 && 1 / d < 0) {
+ return "-0";
+ }
+ return ScriptConvert.ToString (d);
+ }
+ if (value is bool) {
+ return ScriptConvert.ToString (value);
+ }
+ if (value is IScriptable) {
+ IScriptable obj = (IScriptable)value;
+ object v = ScriptableObject.GetProperty (obj, "toSource");
+ if (v is IFunction) {
+ IFunction f = (IFunction)v;
+ return ScriptConvert.ToString (f.Call (cx, scope, obj, EmptyArgs));
+ }
+ return ScriptConvert.ToString (value);
+ }
+ WarnAboutNonJSObject (value);
+ return value.ToString ();
+ }
+
+ internal static string defaultObjectToSource (Context cx, IScriptable scope, IScriptable thisObj, object [] args)
+ {
+ using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier (1024)) {
+ bool toplevel, iterating;
+ if (cx.iterating == null) {
+ toplevel = true;
+ iterating = false;
+ cx.iterating = new ObjToIntMap (31);
+ }
+ else {
+ toplevel = false;
+ iterating = cx.iterating.has (thisObj);
+ }
+
+ System.Text.StringBuilder result = new System.Text.StringBuilder (128);
+ if (toplevel) {
+ result.Append ("(");
+ }
+ result.Append ('{');
+
+ // Make sure cx.iterating is set to null when done
+ // so we don't leak memory
+ try {
+ if (!iterating) {
+ cx.iterating.intern (thisObj); // stop recursion.
+ object [] ids = thisObj.GetIds ();
+ for (int i = 0; i < ids.Length; i++) {
+ if (i > 0)
+ result.Append (", ");
+ object id = ids [i];
+ object value;
+ if (id is int) {
+ int intId = ((int)id);
+ value = thisObj.Get (intId, thisObj);
+ result.Append (intId);
+ }
+ else {
+ string strId = (string)id;
+ value = thisObj.Get (strId, thisObj);
+ if (ScriptRuntime.isValidIdentifierName (strId)) {
+ result.Append (strId);
+ }
+ else {
+ result.Append ('\'');
+ result.Append (ScriptRuntime.escapeString (strId, '\''));
+ result.Append ('\'');
+ }
+ }
+ result.Append (':');
+ result.Append (ScriptRuntime.uneval (cx, scope, value));
+ }
+ }
+ }
+ finally {
+ if (toplevel) {
+ cx.iterating = null;
+ }
+ }
+
+ result.Append ('}');
+ if (toplevel) {
+ result.Append (')');
+ }
+ return result.ToString ();
+ }
+ }
+
+
+
+
+ public static IScriptable NewObject (Context cx, IScriptable scope, string constructorName, object [] args)
+ {
+ scope = ScriptableObject.GetTopLevelScope (scope);
+ IFunction ctor = getExistingCtor (cx, scope, constructorName);
+ if (args == null) {
+ args = ScriptRuntime.EmptyArgs;
+ }
+ return ctor.Construct (cx, scope, args);
+ }
+
+
+ // TODO: this is until setDefaultNamespace will learn how to store NS
+ // TODO: properly and separates namespace form Scriptable.get etc.
+ private const string DEFAULT_NS_TAG = "__default_namespace__";
+
+ public static object setDefaultNamespace (object ns, Context cx)
+ {
+ IScriptable scope = cx.currentActivationCall;
+ if (scope == null) {
+ scope = getTopCallScope (cx);
+ }
+
+ XMLLib xmlLib = CurrentXMLLib (cx);
+ object obj = xmlLib.ToDefaultXmlNamespace (cx, ns);
+
+ // TODO: this should be in separated namesapce from Scriptable.get/put
+ if (!scope.Has (DEFAULT_NS_TAG, scope)) {
+ // TODO: this is racy of cause
+ ScriptableObject.DefineProperty (scope, DEFAULT_NS_TAG, obj, ScriptableObject.PERMANENT | ScriptableObject.DONTENUM);
+ }
+ else {
+ scope.Put (DEFAULT_NS_TAG, scope, obj);
+ }
+
+ return Undefined.Value;
+ }
+
+ public static object searchDefaultNamespace (Context cx)
+ {
+ IScriptable scope = cx.currentActivationCall;
+ if (scope == null) {
+ scope = getTopCallScope (cx);
+ }
+ object nsObject;
+ for (; ; ) {
+ IScriptable parent = scope.ParentScope;
+ if (parent == null) {
+ nsObject = ScriptableObject.GetProperty (scope, DEFAULT_NS_TAG);
+ if (nsObject == UniqueTag.NotFound) {
+ return null;
+ }
+ break;
+ }
+ nsObject = scope.Get (DEFAULT_NS_TAG, scope);
+ if (nsObject != UniqueTag.NotFound) {
+ break;
+ }
+ scope = parent;
+ }
+ return nsObject;
+ }
+
+ public static object getTopLevelProp (IScriptable scope, string id)
+ {
+ scope = ScriptableObject.GetTopLevelScope (scope);
+ return ScriptableObject.GetProperty (scope, id);
+ }
+
+ internal static IFunction getExistingCtor (Context cx, IScriptable scope, string constructorName)
+ {
+ object ctorVal = ScriptableObject.GetProperty (scope, constructorName);
+ if (ctorVal is IFunction) {
+ return (IFunction)ctorVal;
+ }
+ if (ctorVal == UniqueTag.NotFound) {
+ throw Context.ReportRuntimeErrorById ("msg.ctor.not.found", constructorName);
+ }
+ else {
+ throw Context.ReportRuntimeErrorById ("msg.not.ctor", constructorName);
+ }
+ }
+
+ /// Return -1L if str is not an index or the index value as lower 32
+ /// bits of the result.
+ ///
+ private static long indexFromString (string str)
+ {
+ // The length of the decimal string representation of
+ // Integer.MAX_VALUE, 2147483647
+ const int MAX_VALUE_LENGTH = 10;
+
+ int len = str.Length;
+ if (len > 0) {
+ int i = 0;
+ bool negate = false;
+ int c = str [0];
+ if (c == '-') {
+ if (len > 1) {
+ c = str [1];
+ i = 1;
+ negate = true;
+ }
+ }
+ c -= '0';
+ if (0 <= c && c <= 9 && len <= (negate ? MAX_VALUE_LENGTH + 1 : MAX_VALUE_LENGTH)) {
+ // Use negative numbers to accumulate index to handle
+ // Integer.MIN_VALUE that is greater by 1 in absolute value
+ // then Integer.MAX_VALUE
+ int index = -c;
+ int oldIndex = 0;
+ i++;
+ if (index != 0) {
+ // Note that 00, 01, 000 etc. are not indexes
+ while (i != len && 0 <= (c = str [i] - '0') && c <= 9) {
+ oldIndex = index;
+ index = 10 * index - c;
+ i++;
+ }
+ }
+ // Make sure all characters were consumed and that it couldn't
+ // have overflowed.
+ if (i == len && (oldIndex > (int.MinValue / 10) || (oldIndex == (int.MinValue / 10) && c <= (negate ? -(int.MinValue % 10) : (int.MaxValue % 10))))) {
+ return unchecked ((int)0xFFFFFFFFL) & (negate ? index : -index);
+ }
+ }
+ }
+ return -1L;
+ }
+
+ /// If str is a decimal presentation of Uint32 value, return it as long.
+ /// Othewise return -1L;
+ ///
+ public static long testUint32String (string str)
+ {
+ // The length of the decimal string representation of
+ // UINT32_MAX_VALUE, 4294967296
+ const int MAX_VALUE_LENGTH = 10;
+
+ int len = str.Length;
+ if (1 <= len && len <= MAX_VALUE_LENGTH) {
+ int c = str [0];
+ c -= '0';
+ if (c == 0) {
+ // Note that 00,01 etc. are not valid Uint32 presentations
+ return (len == 1) ? 0L : -1L;
+ }
+ if (1 <= c && c <= 9) {
+ long v = c;
+ for (int i = 1; i != len; ++i) {
+ c = str [i] - '0';
+ if (!(0 <= c && c <= 9)) {
+ return -1;
+ }
+ v = 10 * v + c;
+ }
+ // Check for overflow
+ if ((ulong)v >> 32 == 0) {
+ return v;
+ }
+ }
+ }
+ return -1;
+ }
+
+ /// If s represents index, then return index value wrapped as Integer
+ /// and othewise return s.
+ ///
+ internal static object getIndexObject (string s)
+ {
+ long indexTest = indexFromString (s);
+ if (indexTest >= 0) {
+ return (int)indexTest;
+ }
+ return s;
+ }
+
+ /// If d is exact int value, return its value wrapped as Integer
+ /// and othewise return d converted to String.
+ ///
+ internal static object getIndexObject (double d)
+ {
+ int i = (int)d;
+ if ((double)i == d) {
+ return (int)i;
+ }
+ return ScriptConvert.ToString (d);
+ }
+
+ /// If ScriptConvert.ToString(id) is a decimal presentation of int32 value, then id
+ /// is index. In this case return null and make the index available
+ /// as ScriptRuntime.lastIndexResult(cx). Otherwise return ScriptConvert.ToString(id).
+ ///
+ internal static string ToStringIdOrIndex (Context cx, object id)
+ {
+ if (CliHelper.IsNumber (id)) {
+ double d = Convert.ToDouble (id);
+ int index = (int)d;
+ if (((double)index) == d) {
+ storeIndexResult (cx, index);
+ return null;
+ }
+ return ScriptConvert.ToString (id);
+ }
+ else {
+ string s;
+ if (id is string) {
+ s = ((string)id);
+ }
+ else {
+ s = ScriptConvert.ToString (id);
+ }
+ long indexTest = indexFromString (s);
+ if (indexTest >= 0) {
+ storeIndexResult (cx, (int)indexTest);
+ return null;
+ }
+ return s;
+ }
+ }
+
+ /// Call obj.[[Get]](id)
+ public static object getObjectElem (object obj, object elem, Context cx)
+ {
+ IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj);
+ if (sobj == null) {
+ throw UndefReadError (obj, elem);
+ }
+ return getObjectElem (sobj, elem, cx);
+ }
+
+ public static object getObjectElem (IScriptable obj, object elem, Context cx)
+ {
+ if (obj is XMLObject) {
+ XMLObject xmlObject = (XMLObject)obj;
+ return xmlObject.EcmaGet (cx, elem);
+ }
+
+ object result;
+
+ string s = ScriptRuntime.ToStringIdOrIndex (cx, elem);
+ if (s == null) {
+ int index = lastIndexResult (cx);
+ result = ScriptableObject.GetProperty (obj, index);
+ }
+ else {
+ result = ScriptableObject.GetProperty (obj, s);
+ }
+
+ if (result == UniqueTag.NotFound) {
+ result = Undefined.Value;
+ }
+
+ return result;
+ }
+
+ /// Version of getObjectElem when elem is a valid JS identifier name.
+ public static object getObjectProp (object obj, string property, Context cx)
+ {
+ IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj);
+ if (sobj == null) {
+ throw UndefReadError (obj, property);
+ }
+ return getObjectProp (sobj, property, cx);
+ }
+
+ public static object getObjectProp (IScriptable obj, string property, Context cx)
+ {
+ if (obj is XMLObject) {
+ XMLObject xmlObject = (XMLObject)obj;
+ return xmlObject.EcmaGet (cx, property);
+ }
+
+ object result = ScriptableObject.GetProperty (obj, property);
+ if (result == UniqueTag.NotFound) {
+ result = Undefined.Value;
+ }
+
+ return result;
+ }
+
+ /*
+ * A cheaper and less general version of the above for well-known argument
+ * types.
+ */
+ public static object getObjectIndex (object obj, double dblIndex, Context cx)
+ {
+ IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj);
+ if (sobj == null) {
+ throw UndefReadError (obj, ScriptConvert.ToString (dblIndex));
+ }
+ int index = (int)dblIndex;
+ if ((double)index == dblIndex) {
+ return getObjectIndex (sobj, index, cx);
+ }
+ else {
+ string s = ScriptConvert.ToString (dblIndex);
+ return getObjectProp (sobj, s, cx);
+ }
+ }
+
+ public static object getObjectIndex (IScriptable obj, int index, Context cx)
+ {
+ if (obj is XMLObject) {
+ XMLObject xmlObject = (XMLObject)obj;
+ return xmlObject.EcmaGet (cx, (object)index);
+ }
+
+ object result = ScriptableObject.GetProperty (obj, index);
+ if (result == UniqueTag.NotFound) {
+ result = Undefined.Value;
+ }
+
+ return result;
+ }
+
+ /*
+ * Call obj.[[Put]](id, value)
+ */
+ public static object setObjectElem (object obj, object elem, object value, Context cx)
+ {
+ IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj);
+ if (sobj == null) {
+ throw UndefWriteError (obj, elem, value);
+ }
+ return setObjectElem (sobj, elem, value, cx);
+ }
+
+ public static object setObjectElem (IScriptable obj, object elem, object value, Context cx)
+ {
+ if (obj is XMLObject) {
+ XMLObject xmlObject = (XMLObject)obj;
+ xmlObject.EcmaPut (cx, elem, value);
+ return value;
+ }
+
+ string s = ScriptRuntime.ToStringIdOrIndex (cx, elem);
+ if (s == null) {
+ int index = lastIndexResult (cx);
+ ScriptableObject.PutProperty (obj, index, value);
+ }
+ else {
+ ScriptableObject.PutProperty (obj, s, value);
+ }
+
+ return value;
+ }
+
+ /// Version of setObjectElem when elem is a valid JS identifier name.
+ public static object setObjectProp (object obj, string property, object value, Context cx)
+ {
+ IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj);
+ if (sobj == null) {
+ throw UndefWriteError (obj, property, value);
+ }
+ return setObjectProp (sobj, property, value, cx);
+ }
+
+ public static object setObjectProp (IScriptable obj, string property, object value, Context cx)
+ {
+ if (obj is XMLObject) {
+ XMLObject xmlObject = (XMLObject)obj;
+ xmlObject.EcmaPut (cx, property, value);
+ }
+ else {
+ return ScriptableObject.PutProperty (obj, property, value);
+ }
+ return value;
+ }
+
+ /*
+ * A cheaper and less general version of the above for well-known argument
+ * types.
+ */
+ public static object setObjectIndex (object obj, double dblIndex, object value, Context cx)
+ {
+ IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj);
+ if (sobj == null) {
+ throw UndefWriteError (obj, Convert.ToString (dblIndex), value);
+ }
+ int index = (int)dblIndex;
+ if ((double)index == dblIndex) {
+ return setObjectIndex (sobj, index, value, cx);
+ }
+ else {
+ string s = ScriptConvert.ToString (dblIndex);
+ return setObjectProp (sobj, s, value, cx);
+ }
+ }
+
+ public static object setObjectIndex (IScriptable obj, int index, object value, Context cx)
+ {
+ if (obj is XMLObject) {
+ XMLObject xmlObject = (XMLObject)obj;
+ xmlObject.EcmaPut (cx, (object)index, value);
+ }
+ else {
+ return ScriptableObject.PutProperty (obj, index, value);
+ }
+ return value;
+ }
+
+ public static bool deleteObjectElem (IScriptable target, object elem, Context cx)
+ {
+ bool result;
+ if (target is XMLObject) {
+ XMLObject xmlObject = (XMLObject)target;
+ result = xmlObject.EcmaDelete (cx, elem);
+ }
+ else {
+ string s = ScriptRuntime.ToStringIdOrIndex (cx, elem);
+ if (s == null) {
+ int index = lastIndexResult (cx);
+ result = ScriptableObject.DeleteProperty (target, index);
+ }
+ else {
+ result = ScriptableObject.DeleteProperty (target, s);
+ }
+ }
+ return result;
+ }
+
+ public static bool hasObjectElem (IScriptable target, object elem, Context cx)
+ {
+ bool result;
+
+ if (target is XMLObject) {
+ XMLObject xmlObject = (XMLObject)target;
+ result = xmlObject.EcmaHas (cx, elem);
+ }
+ else {
+ string s = ScriptRuntime.ToStringIdOrIndex (cx, elem);
+ if (s == null) {
+ int index = lastIndexResult (cx);
+ result = ScriptableObject.HasProperty (target, index);
+ }
+ else {
+ result = ScriptableObject.HasProperty (target, s);
+ }
+ }
+
+ return result;
+ }
+
+ public static object refGet (IRef rf, Context cx)
+ {
+ return rf.Get (cx);
+ }
+
+ public static object refSet (IRef rf, object value, Context cx)
+ {
+ return rf.Set (cx, value);
+ }
+
+ public static object refDel (IRef rf, Context cx)
+ {
+ return rf.Delete (cx);
+ }
+
+ internal static bool isSpecialProperty (string s)
+ {
+ return s.Equals ("__proto__") || s.Equals ("__parent__");
+ }
+
+ public static IRef specialRef (object obj, string specialProperty, Context cx)
+ {
+ return SpecialRef.createSpecial (cx, obj, specialProperty);
+ }
+
+ /// The delete operator
+ ///
+ /// See ECMA 11.4.1
+ ///
+ /// In ECMA 0.19, the description of the delete operator (11.4.1)
+ /// assumes that the [[Delete]] method returns a value. However,
+ /// the definition of the [[Delete]] operator (8.6.2.5) does not
+ /// define a return value. Here we assume that the [[Delete]]
+ /// method doesn't return a value.
+ ///
+ public static object delete (object obj, object id, Context cx)
+ {
+ IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj);
+ if (sobj == null) {
+ string idStr = (id == null) ? "null" : id.ToString ();
+ throw TypeErrorById ("msg.undef.prop.delete", ScriptConvert.ToString (obj), idStr);
+ }
+ bool result = deleteObjectElem (sobj, id, cx);
+ return result;
+ }
+
+ /// Looks up a name in the scope chain and returns its value.
+ public static object name (Context cx, IScriptable scope, string name)
+ {
+ IScriptable parent = scope.ParentScope;
+ if (parent == null) {
+ object result = topScopeName (cx, scope, name);
+ if (result == UniqueTag.NotFound) {
+ throw NotFoundError (scope, name);
+ }
+ return result;
+ }
+
+ return nameOrFunction (cx, scope, parent, name, false);
+ }
+
+ private static object nameOrFunction (Context cx, IScriptable scope, IScriptable parentScope, string name, bool asFunctionCall)
+ {
+ object result;
+ IScriptable thisObj = scope; // It is used only if asFunctionCall==true.
+
+ XMLObject firstXMLObject = null;
+ for (; ; ) {
+ if (scope is BuiltinWith) {
+ IScriptable withObj = scope.GetPrototype ();
+ if (withObj is XMLObject) {
+ XMLObject xmlObj = (XMLObject)withObj;
+ if (xmlObj.EcmaHas (cx, name)) {
+ // function this should be the target object of with
+ thisObj = xmlObj;
+ result = xmlObj.EcmaGet (cx, name);
+ break;
+ }
+ if (firstXMLObject == null) {
+ firstXMLObject = xmlObj;
+ }
+ }
+ else {
+ result = ScriptableObject.GetProperty (withObj, name);
+ if (result != UniqueTag.NotFound) {
+ // function this should be the target object of with
+ thisObj = withObj;
+ break;
+ }
+ }
+ }
+ else if (scope is BuiltinCall) {
+ // NativeCall does not prototype chain and Scriptable.get
+ // can be called directly.
+ result = scope.Get (name, scope);
+ if (result != UniqueTag.NotFound) {
+ if (asFunctionCall) {
+ // ECMA 262 requires that this for nested funtions
+ // should be top scope
+ thisObj = ScriptableObject.GetTopLevelScope (parentScope);
+ }
+ break;
+ }
+ }
+ else {
+ // Can happen if embedding decided that nested
+ // scopes are useful for what ever reasons.
+ result = ScriptableObject.GetProperty (scope, name);
+ if (result != UniqueTag.NotFound) {
+ thisObj = scope;
+ break;
+ }
+ }
+ scope = parentScope;
+ parentScope = parentScope.ParentScope;
+ if (parentScope == null) {
+ result = topScopeName (cx, scope, name);
+ if (result == UniqueTag.NotFound) {
+ if (firstXMLObject == null || asFunctionCall) {
+ throw NotFoundError (scope, name);
+ }
+ // The name was not found, but we did find an XML
+ // object in the scope chain and we are looking for name,
+ // not function. The result should be an empty XMLList
+ // in name context.
+ result = firstXMLObject.EcmaGet (cx, name);
+ }
+ // For top scope thisObj for functions is always scope itself.
+ thisObj = scope;
+ break;
+ }
+ }
+
+ if (asFunctionCall) {
+ if (!(result is ICallable)) {
+ throw NotFunctionError (result, name);
+ }
+ storeScriptable (cx, thisObj);
+ }
+
+ return result;
+ }
+
+ private static object topScopeName (Context cx, IScriptable scope, string name)
+ {
+ if (cx.useDynamicScope) {
+ scope = checkDynamicScope (cx.topCallScope, scope);
+ }
+ return ScriptableObject.GetProperty (scope, name);
+ }
+
+
+ /// Returns the object in the scope chain that has a given property.
+ ///
+ /// The order of evaluation of an assignment expression involves
+ /// evaluating the lhs to a reference, evaluating the rhs, and then
+ /// modifying the reference with the rhs value. This method is used
+ /// to 'bind' the given name to an object containing that property
+ /// so that the side effects of evaluating the rhs do not affect
+ /// which property is modified.
+ /// Typically used in conjunction with setName.
+ ///
+ /// See ECMA 10.1.4
+ ///
+ public static IScriptable bind (Context cx, IScriptable scope, string id)
+ {
+ IScriptable firstXMLObject = null;
+ IScriptable parent = scope.ParentScope;
+ if (parent != null) {
+ // Check for possibly nested "with" scopes first
+ while (scope is BuiltinWith) {
+ IScriptable withObj = scope.GetPrototype ();
+ if (withObj is XMLObject) {
+ XMLObject xmlObject = (XMLObject)withObj;
+ if (xmlObject.EcmaHas (cx, id)) {
+ return xmlObject;
+ }
+ if (firstXMLObject == null) {
+ firstXMLObject = xmlObject;
+ }
+ }
+ else {
+ if (ScriptableObject.HasProperty (withObj, id)) {
+ return withObj;
+ }
+ }
+ scope = parent;
+ parent = parent.ParentScope;
+ if (parent == null) {
+
+ goto childScopesChecks_brk;
+ }
+ }
+ for (; ; ) {
+ if (ScriptableObject.HasProperty (scope, id)) {
+ return scope;
+ }
+ scope = parent;
+ parent = parent.ParentScope;
+ if (parent == null) {
+
+ goto childScopesChecks_brk;
+ }
+ }
+ }
+
+ childScopesChecks_brk:
+ ;
+
+ // scope here is top scope
+ if (cx.useDynamicScope) {
+ scope = checkDynamicScope (cx.topCallScope, scope);
+ }
+ if (ScriptableObject.HasProperty (scope, id)) {
+ return scope;
+ }
+ // Nothing was found, but since XML objects always bind
+ // return one if found
+ return firstXMLObject;
+ }
+
+ public static object setName (IScriptable bound, object value, Context cx, IScriptable scope, string id)
+ {
+ if (bound != null) {
+ if (bound is XMLObject) {
+ XMLObject xmlObject = (XMLObject)bound;
+ xmlObject.EcmaPut (cx, id, value);
+ }
+ else {
+ ScriptableObject.PutProperty (bound, id, value);
+ }
+ }
+ else {
+ // "newname = 7;", where 'newname' has not yet
+ // been defined, creates a new property in the
+ // top scope unless strict mode is specified.
+ if (cx.HasFeature (Context.Features.StrictVars)) {
+ throw Context.ReportRuntimeErrorById ("msg.assn.create.strict", id);
+ }
+ // Find the top scope by walking up the scope chain.
+ bound = ScriptableObject.GetTopLevelScope (scope);
+ if (cx.useDynamicScope) {
+ bound = checkDynamicScope (cx.topCallScope, bound);
+ }
+ bound.Put (id, bound, value);
+ }
+ return value;
+ }
+
+
+
+
+
+
+ /// Prepare for calling name(...): return function corresponding to
+ /// name and make current top scope available
+ /// as ScriptRuntime.lastStoredScriptable() for consumption as thisObj.
+ /// The caller must call ScriptRuntime.lastStoredScriptable() immediately
+ /// after calling this method.
+ ///
+ public static ICallable getNameFunctionAndThis (string name, Context cx, IScriptable scope)
+ {
+ IScriptable parent = scope.ParentScope;
+ if (parent == null) {
+ object result = topScopeName (cx, scope, name);
+ if (!(result is ICallable)) {
+ if (result == UniqueTag.NotFound) {
+ throw NotFoundError (scope, name);
+ }
+ else {
+ throw NotFunctionError (result, name);
+ }
+ }
+ // Top scope is not NativeWith or NativeCall => thisObj == scope
+ IScriptable thisObj = scope;
+ storeScriptable (cx, thisObj);
+ return (ICallable)result;
+ }
+
+ // name will call storeScriptable(cx, thisObj);
+ return (ICallable)nameOrFunction (cx, scope, parent, name, true);
+ }
+
+ /// Prepare for calling obj[id](...): return function corresponding to
+ /// obj[id] and make obj properly converted to Scriptable available
+ /// as ScriptRuntime.lastStoredScriptable() for consumption as thisObj.
+ /// The caller must call ScriptRuntime.lastStoredScriptable() immediately
+ /// after calling this method.
+ ///
+ public static ICallable GetElemFunctionAndThis (object obj, object elem, Context cx)
+ {
+ string s = ScriptRuntime.ToStringIdOrIndex (cx, elem);
+ if (s != null) {
+ return getPropFunctionAndThis (obj, s, cx);
+ }
+ int index = lastIndexResult (cx);
+
+ IScriptable thisObj = ScriptConvert.ToObjectOrNull (cx, obj);
+ if (thisObj == null) {
+ throw UndefCallError (obj, Convert.ToString (index));
+ }
+
+ object value;
+ for (; ; ) {
+ // Ignore XML lookup as requred by ECMA 357, 11.2.2.1
+ value = ScriptableObject.GetProperty (thisObj, index);
+ if (value != UniqueTag.NotFound) {
+ break;
+ }
+ if (!(thisObj is XMLObject)) {
+ break;
+ }
+ XMLObject xmlObject = (XMLObject)thisObj;
+ IScriptable extra = xmlObject.GetExtraMethodSource (cx);
+ if (extra == null) {
+ break;
+ }
+ thisObj = extra;
+ }
+ if (!(value is ICallable)) {
+ throw NotFunctionError (value, elem);
+ }
+
+ storeScriptable (cx, thisObj);
+ return (ICallable)value;
+ }
+
+ /// Prepare for calling obj.property(...): return function corresponding to
+ /// obj.property and make obj properly converted to Scriptable available
+ /// as ScriptRuntime.lastStoredScriptable() for consumption as thisObj.
+ /// The caller must call ScriptRuntime.lastStoredScriptable() immediately
+ /// after calling this method.
+ ///
+ public static ICallable getPropFunctionAndThis (object obj, string property, Context cx)
+ {
+ IScriptable thisObj = ScriptConvert.ToObjectOrNull (cx, obj);
+ if (thisObj == null) {
+ throw UndefCallError (obj, property);
+ }
+
+ object value;
+ for (; ; ) {
+ // Ignore XML lookup as requred by ECMA 357, 11.2.2.1
+ value = ScriptableObject.GetProperty (thisObj, property);
+ if (value != UniqueTag.NotFound) {
+ break;
+ }
+ if (!(thisObj is XMLObject)) {
+ break;
+ }
+ XMLObject xmlObject = (XMLObject)thisObj;
+ IScriptable extra = xmlObject.GetExtraMethodSource (cx);
+ if (extra == null) {
+ break;
+ }
+ thisObj = extra;
+ }
+
+ if (value == UniqueTag.NotFound) {
+ //if (thisObj.Get ("__noSuchMethod__", thisObj) as ICallable != null) {
+ // return UniqueTag.NoSuchMethodMark;
+ //}
+ }
+
+ if (!(value is ICallable)) {
+ throw NotFunctionError (value, property);
+ }
+
+ storeScriptable (cx, thisObj);
+ return (ICallable)value;
+ }
+
+ /// Prepare for calling (...): return function corresponding to
+ /// and make parent scope of the function available
+ /// as ScriptRuntime.lastStoredScriptable() for consumption as thisObj.
+ /// The caller must call ScriptRuntime.lastStoredScriptable() immediately
+ /// after calling this method.
+ ///
+ public static ICallable getValueFunctionAndThis (object value, Context cx)
+ {
+ if (!(value is ICallable)) {
+ throw NotFunctionError (value);
+ }
+
+ ICallable f = (ICallable)value;
+ IScriptable thisObj;
+ if (f is IScriptable) {
+ thisObj = ((IScriptable)f).ParentScope;
+ }
+ else {
+ if (cx.topCallScope == null)
+ throw new Exception ();
+ thisObj = cx.topCallScope;
+ }
+ if (thisObj.ParentScope != null) {
+ if (thisObj is BuiltinWith) {
+ // functions defined inside with should have with target
+ // as their thisObj
+ }
+ else if (thisObj is BuiltinCall) {
+ // nested functions should have top scope as their thisObj
+ thisObj = ScriptableObject.GetTopLevelScope (thisObj);
+ }
+ }
+ storeScriptable (cx, thisObj);
+ return f;
+ }
+
+ /// Perform function call in reference context. Should always
+ /// return value that can be passed to
+ /// {@link #refGet(Object)} or @link #refSet(Object, Object)}
+ /// arbitrary number of times.
+ /// The args array reference should not be stored in any object that is
+ /// can be GC-reachable after this method returns. If this is necessary,
+ /// store args.clone(), not args array itself.
+ ///
+ public static IRef callRef (ICallable function, IScriptable thisObj, object [] args, Context cx)
+ {
+ if (function is IRefCallable) {
+ IRefCallable rfunction = (IRefCallable)function;
+ IRef rf = rfunction.RefCall (cx, thisObj, args);
+ if (rf == null) {
+ throw new Exception (rfunction.GetType ().FullName + ".refCall() returned null");
+ }
+ return rf;
+ }
+ // No runtime support for now
+ string msg = GetMessage ("msg.no.ref.from.function", ScriptConvert.ToString (function));
+ throw ConstructError ("ReferenceError", msg);
+ }
+
+ /// Operator new.
+ ///
+ /// See ECMA 11.2.2
+ ///
+ public static IScriptable NewObject (object fun, Context cx, IScriptable scope, object [] args)
+ {
+ if (!(fun is IFunction)) {
+ throw NotFunctionError (fun);
+ }
+ IFunction function = (IFunction)fun;
+ return function.Construct (cx, scope, args);
+ }
+
+ public static object callSpecial (Context cx, ICallable fun, IScriptable thisObj, object [] args, IScriptable scope, IScriptable callerThis, int callType, string filename, int lineNumber)
+ {
+ if (callType == Node.SPECIALCALL_EVAL) {
+ if (BuiltinGlobal.isEvalFunction (fun)) {
+ return evalSpecial (cx, scope, callerThis, args, filename, lineNumber);
+ }
+ }
+ else if (callType == Node.SPECIALCALL_WITH) {
+ if (BuiltinWith.IsWithFunction (fun)) {
+ throw Context.ReportRuntimeErrorById ("msg.only.from.new", "With");
+ }
+ }
+ else {
+ throw Context.CodeBug ();
+ }
+
+ return fun.Call (cx, scope, thisObj, args);
+ }
+
+ public static object newSpecial (Context cx, object fun, object [] args, IScriptable scope, int callType)
+ {
+ if (callType == Node.SPECIALCALL_EVAL) {
+ if (BuiltinGlobal.isEvalFunction (fun)) {
+ throw TypeErrorById ("msg.not.ctor", "eval");
+ }
+ }
+ else if (callType == Node.SPECIALCALL_WITH) {
+ if (BuiltinWith.IsWithFunction (fun)) {
+ return BuiltinWith.NewWithSpecial (cx, scope, args);
+ }
+ }
+ else {
+ throw Context.CodeBug ();
+ }
+
+ return NewObject (fun, cx, scope, args);
+ }
+
+ /// Function.prototype.apply and Function.prototype.call
+ ///
+ /// See Ecma 15.3.4.[34]
+ ///
+ public static object applyOrCall (bool isApply, Context cx, IScriptable scope, IScriptable thisObj, object [] args)
+ {
+ int L = args.Length;
+ ICallable function;
+ if (thisObj is ICallable) {
+ function = (ICallable)thisObj;
+ }
+ else {
+ object value = thisObj.GetDefaultValue (typeof (IFunction));
+ if (!(value is ICallable)) {
+ throw ScriptRuntime.NotFunctionError (value, thisObj);
+ }
+ function = (ICallable)value;
+ }
+
+ IScriptable callThis = null;
+ if (L != 0) {
+ callThis = ScriptConvert.ToObjectOrNull (cx, args [0]);
+ }
+ if (callThis == null) {
+ // This covers the case of args[0] == (null|undefined) as well.
+ callThis = getTopCallScope (cx);
+ }
+
+ object [] callArgs;
+ if (isApply) {
+ // Follow Ecma 15.3.4.3
+ if (L <= 1) {
+ callArgs = ScriptRuntime.EmptyArgs;
+ }
+ else {
+ object arg1 = args [1];
+ if (arg1 == null || arg1 == Undefined.Value) {
+ callArgs = ScriptRuntime.EmptyArgs;
+ }
+ else if (arg1 is BuiltinArray || arg1 is Arguments) {
+ callArgs = cx.GetElements ((IScriptable)arg1);
+ }
+ else {
+ throw ScriptRuntime.TypeErrorById ("msg.arg.isnt.array");
+ }
+ }
+ }
+ else {
+ // Follow Ecma 15.3.4.4
+ if (L <= 1) {
+ callArgs = ScriptRuntime.EmptyArgs;
+ }
+ else {
+ callArgs = new object [L - 1];
+ Array.Copy (args, 1, callArgs, 0, L - 1);
+ }
+ }
+
+ return function.Call (cx, scope, callThis, callArgs);
+ }
+
+ /// The eval function property of the global object.
+ ///
+ /// See ECMA 15.1.2.1
+ ///
+ public static object evalSpecial (Context cx, IScriptable scope, object thisArg, object [] args, string filename, int lineNumber)
+ {
+ if (args.Length < 1)
+ return Undefined.Value;
+ object x = args [0];
+ if (!(x is string)) {
+ if (cx.HasFeature (Context.Features.StrictEval)) {
+ throw Context.ReportRuntimeErrorById ("msg.eval.nonstring.strict");
+ }
+ string message = ScriptRuntime.GetMessage ("msg.eval.nonstring");
+ Context.ReportWarning (message);
+ return x;
+ }
+ if (filename == null) {
+ int [] linep = new int [1];
+ filename = Context.GetSourcePositionFromStack (linep);
+ if (filename != null) {
+ lineNumber = linep [0];
+ }
+ else {
+ filename = "";
+ }
+ }
+ string sourceName = ScriptRuntime.makeUrlForGeneratedScript (true, filename, lineNumber);
+
+ ErrorReporter reporter;
+ reporter = DefaultErrorReporter.ForEval (cx.ErrorReporter);
+
+ // Compile with explicit interpreter instance to force interpreter
+ // mode.
+ IScript script = cx.CompileString ((string)x, new Interpreter (), reporter, sourceName, 1, (object)null);
+ ((InterpretedFunction)script).idata.evalScriptFlag = true;
+ ICallable c = (ICallable)script;
+ return c.Call (cx, scope, (IScriptable)thisArg, ScriptRuntime.EmptyArgs);
+ }
+
+ /// The typeof operator
+ public static string Typeof (object value)
+ {
+ if (value == null)
+ return "object";
+ if (value == Undefined.Value)
+ return "undefined";
+ if (value is IScriptable) {
+ if (value is XMLObject)
+ return "xml";
+
+ return (value is ICallable && !(value is BuiltinRegExp)) ? "function" : "object";
+ }
+ if (value is string)
+ return "string";
+ if (value is char || CliHelper.IsNumber (value))
+ return "number";
+ if (value is bool)
+ return "boolean";
+ throw errorWithClassName ("msg.invalid.type", value);
+ }
+
+
+ internal static Exception errorWithClassName (string msg, object val)
+ {
+ return Context.ReportRuntimeErrorById (msg, val.GetType ().FullName);
+ }
+
+ /// The typeof operator that correctly handles the undefined case
+ public static string TypeofName (IScriptable scope, string id)
+ {
+ Context cx = Context.CurrentContext;
+ IScriptable val = bind (cx, scope, id);
+ if (val == null)
+ return "undefined";
+ return Typeof (getObjectProp (val, id, cx));
+ }
+
+ // neg:
+ // implement the '-' operator inline in the caller
+ // as "-ScriptConvert.ToNumber(val)"
+
+ // not:
+ // implement the '!' operator inline in the caller
+ // as "!toBoolean(val)"
+
+ // bitnot:
+ // implement the '~' operator inline in the caller
+ // as "~toInt32(val)"
+
+ public static object Add (object val1, object val2, Context cx)
+ {
+ if (CliHelper.IsNumber (val1) && CliHelper.IsNumber (val2)) {
+ return (double)val1 + (double)val2;
+ }
+ if (val1 is XMLObject) {
+ object test = ((XMLObject)val1).AddValues (cx, true, val2);
+ if (test != UniqueTag.NotFound) {
+ return test;
+ }
+ }
+ if (val2 is XMLObject) {
+ object test = ((XMLObject)val2).AddValues (cx, false, val1);
+ if (test != UniqueTag.NotFound) {
+ return test;
+ }
+ }
+ if (val1 is EcmaScript.NET.Types.Cli.CliEventInfo) {
+ return ((EcmaScript.NET.Types.Cli.CliEventInfo)val1).Add (val2, cx);
+ }
+ if (val1 is IScriptable)
+ val1 = ((IScriptable)val1).GetDefaultValue (null);
+ if (val2 is IScriptable)
+ val2 = ((IScriptable)val2).GetDefaultValue (null);
+ if (!(val1 is string) && !(val2 is string))
+ if ((CliHelper.IsNumber (val1)) && (CliHelper.IsNumber (val2)))
+ return (double)val1 + (double)val2;
+ else
+ return ScriptConvert.ToNumber (val1) + ScriptConvert.ToNumber (val2);
+ return string.Concat (ScriptConvert.ToString (val1), ScriptConvert.ToString (val2));
+ }
+
+ public static object nameIncrDecr (IScriptable scopeChain, string id, int incrDecrMask)
+ {
+ IScriptable target;
+ object value;
+ {
+ do {
+ target = scopeChain;
+ do {
+ value = target.Get (id, scopeChain);
+ if (value != UniqueTag.NotFound) {
+
+ goto search_brk;
+ }
+ target = target.GetPrototype ();
+ }
+ while (target != null);
+ scopeChain = scopeChain.ParentScope;
+ }
+ while (scopeChain != null);
+ throw NotFoundError (scopeChain, id);
+ }
+
+ search_brk:
+ ;
+
+ return doScriptableIncrDecr (target, id, scopeChain, value, incrDecrMask);
+ }
+
+ public static object propIncrDecr (object obj, string id, Context cx, int incrDecrMask)
+ {
+ IScriptable start = ScriptConvert.ToObjectOrNull (cx, obj);
+ if (start == null) {
+ throw UndefReadError (obj, id);
+ }
+
+ IScriptable target = start;
+ object value;
+ {
+ do {
+ value = target.Get (id, start);
+ if (value != UniqueTag.NotFound) {
+
+ goto search1_brk;
+ }
+ target = target.GetPrototype ();
+ }
+ while (target != null);
+ start.Put (id, start, double.NaN);
+ return double.NaN;
+ }
+
+ search1_brk:
+ ;
+
+ return doScriptableIncrDecr (target, id, start, value, incrDecrMask);
+ }
+
+ private static object doScriptableIncrDecr (IScriptable target, string id, IScriptable protoChainStart, object value, int incrDecrMask)
+ {
+ bool post = ((incrDecrMask & Node.POST_FLAG) != 0);
+ double number;
+ if (CliHelper.IsNumber (value)) {
+ number = Convert.ToDouble (value);
+ }
+ else {
+ number = ScriptConvert.ToNumber (value);
+ if (post) {
+ // convert result to number
+ value = number;
+ }
+ }
+ if ((incrDecrMask & Node.DECR_FLAG) == 0) {
+ ++number;
+ }
+ else {
+ --number;
+ }
+ object result = number;
+ target.Put (id, protoChainStart, result);
+ if (post) {
+ return value;
+ }
+ else {
+ return result;
+ }
+ }
+
+ public static object elemIncrDecr (object obj, object index, Context cx, int incrDecrMask)
+ {
+ object value = getObjectElem (obj, index, cx);
+ bool post = ((incrDecrMask & Node.POST_FLAG) != 0);
+ double number;
+ if (CliHelper.IsNumber (value)) {
+ number = Convert.ToDouble (value);
+ }
+ else {
+ number = ScriptConvert.ToNumber (value);
+ if (post) {
+ // convert result to number
+ value = number;
+ }
+ }
+ if ((incrDecrMask & Node.DECR_FLAG) == 0) {
+ ++number;
+ }
+ else {
+ --number;
+ }
+ object result = number;
+ setObjectElem (obj, index, result, cx);
+ if (post) {
+ return value;
+ }
+ else {
+ return result;
+ }
+ }
+
+ public static object refIncrDecr (IRef rf, Context cx, int incrDecrMask)
+ {
+ object value = rf.Get (cx);
+ bool post = ((incrDecrMask & Node.POST_FLAG) != 0);
+ double number;
+ if (CliHelper.IsNumber (value)) {
+ number = Convert.ToDouble (value);
+ }
+ else {
+ number = ScriptConvert.ToNumber (value);
+ if (post) {
+ // convert result to number
+ value = number;
+ }
+ }
+ if ((incrDecrMask & Node.DECR_FLAG) == 0) {
+ ++number;
+ }
+ else {
+ --number;
+ }
+ rf.Set (cx, number);
+ if (post) {
+ return value;
+ }
+ else {
+ return number;
+ }
+ }
+
+
+ /// Equality
+ ///
+ /// See ECMA 11.9
+ ///
+ public static bool eq (object x, object y)
+ {
+ if (x == null || x == Undefined.Value) {
+ if (y == null || y == Undefined.Value) {
+ return true;
+ }
+ if (y is ScriptableObject) {
+ object test = ((ScriptableObject)y).EquivalentValues (x);
+ if (test != UniqueTag.NotFound) {
+ return ((bool)test);
+ }
+ }
+ return false;
+ }
+ else if (CliHelper.IsNumber (x)) {
+ return eqNumber (Convert.ToDouble (x), y);
+ }
+ else if (x is string) {
+ return eqString ((string)x, y);
+ }
+ else if (x is bool) {
+ bool b = ((bool)x);
+ if (y is bool) {
+ return b == ((bool)y);
+ }
+ if (y is ScriptableObject) {
+ object test = ((ScriptableObject)y).EquivalentValues (x);
+ if (test != UniqueTag.NotFound) {
+ return ((bool)test);
+ }
+ }
+ return eqNumber (b ? 1.0 : 0.0, y);
+ }
+ else if (x is IScriptable) {
+ if (y is IScriptable) {
+ if (x == y) {
+ return true;
+ }
+ if (x is ScriptableObject) {
+ object test = ((ScriptableObject)x).EquivalentValues (y);
+ if (test != UniqueTag.NotFound) {
+ return ((bool)test);
+ }
+ }
+ if (y is ScriptableObject) {
+ object test = ((ScriptableObject)y).EquivalentValues (x);
+ if (test != UniqueTag.NotFound) {
+ return ((bool)test);
+ }
+ }
+ if (x is Wrapper && y is Wrapper) {
+ return ((Wrapper)x).Unwrap () == ((Wrapper)y).Unwrap ();
+ }
+ return false;
+ }
+ else if (y is bool) {
+ if (x is ScriptableObject) {
+ object test = ((ScriptableObject)x).EquivalentValues (y);
+ if (test != UniqueTag.NotFound) {
+ return ((bool)test);
+ }
+ }
+ double d = ((bool)y) ? 1.0 : 0.0;
+ return eqNumber (d, x);
+ }
+ else if (CliHelper.IsNumber (y)) {
+ return eqNumber (Convert.ToDouble (y), x);
+ }
+ else if (y is string) {
+ return eqString ((string)y, x);
+ }
+ // covers the case when y == Undefined.instance as well
+ return false;
+ }
+ else {
+ WarnAboutNonJSObject (x);
+ return x == y;
+ }
+ }
+
+ internal static bool eqNumber (double x, object y)
+ {
+ for (; ; ) {
+ if (y == null || y == Undefined.Value) {
+ return false;
+ }
+ else if (CliHelper.IsNumber (y)) {
+ return x == Convert.ToDouble (y);
+ }
+ else if (y is string) {
+ return x == ScriptConvert.ToNumber (y);
+ }
+ else if (y is bool) {
+ return x == (((bool)y) ? 1.0 : +0.0);
+ }
+ else if (y is IScriptable) {
+ if (y is ScriptableObject) {
+ object xval = x;
+ object test = ((ScriptableObject)y).EquivalentValues (xval);
+ if (test != UniqueTag.NotFound) {
+ return ((bool)test);
+ }
+ }
+ y = ScriptConvert.ToPrimitive (y);
+ }
+ else {
+ WarnAboutNonJSObject (y);
+ return false;
+ }
+ }
+ }
+
+ private static bool eqString (string x, object y)
+ {
+ for (; ; ) {
+ if (y == null || y == Undefined.Value) {
+ return false;
+ }
+ else if (y is string) {
+ return x.Equals (y);
+ }
+ else if (CliHelper.IsNumber (y)) {
+ return ScriptConvert.ToNumber (x) == Convert.ToDouble (y);
+ }
+ else if (y is bool) {
+ return ScriptConvert.ToNumber (x) == (((bool)y) ? 1.0 : 0.0);
+ }
+ else if (y is IScriptable) {
+ if (y is ScriptableObject) {
+ object test = ((ScriptableObject)y).EquivalentValues (x);
+ if (test != UniqueTag.NotFound) {
+ return ((bool)test);
+ }
+ }
+ y = ScriptConvert.ToPrimitive (y);
+ continue;
+ }
+ else {
+ WarnAboutNonJSObject (y);
+ return false;
+ }
+ }
+ }
+ public static bool shallowEq (object x, object y)
+ {
+ if (x == y) {
+ if (!(CliHelper.IsNumber (x))) {
+ return true;
+ }
+ // double.NaN check
+ double d = Convert.ToDouble (x);
+ return !double.IsNaN (d);
+ }
+ if (x == null || x == Undefined.Value) {
+ return false;
+ }
+ else if (CliHelper.IsNumber (x)) {
+ if (CliHelper.IsNumber (y)) {
+ return Convert.ToDouble (x) == Convert.ToDouble (y);
+ }
+ }
+ else if (x is string) {
+ if (y is string) {
+ return x.Equals (y);
+ }
+ }
+ else if (x is bool) {
+ if (y is bool) {
+ return x.Equals (y);
+ }
+ }
+ else if (x is IScriptable) {
+ if (x is Wrapper && y is Wrapper) {
+ return ((Wrapper)x).Unwrap () == ((Wrapper)y).Unwrap ();
+ }
+ }
+ else {
+ WarnAboutNonJSObject (x);
+ return x == y;
+ }
+ return false;
+ }
+
+ /// The instanceof operator.
+ ///
+ ///
+ /// a instanceof b
+ ///
+ public static bool InstanceOf (object a, object b, Context cx)
+ {
+ IScriptable sB = (b as IScriptable);
+
+ // Check RHS is an object
+ if (sB == null) {
+ throw TypeErrorById ("msg.instanceof.not.object");
+ }
+
+ IScriptable sA = (a as IScriptable);
+
+ // for primitive values on LHS, return false
+ // TODO we may want to change this so that 5 instanceof Number == true
+ if (sA == null) {
+ return false;
+ }
+
+
+ return sB.HasInstance (sA);
+ }
+
+ /// Delegates to
+ ///
+ ///
+ /// true iff rhs appears in lhs' proto chain
+ ///
+ protected internal static bool jsDelegatesTo (IScriptable lhs, IScriptable rhs)
+ {
+ IScriptable proto = lhs.GetPrototype ();
+
+ while (proto != null) {
+ if (proto.Equals (rhs))
+ return true;
+ proto = proto.GetPrototype ();
+ }
+
+ return false;
+ }
+
+ /// The in operator.
+ ///
+ /// This is a new JS 1.3 language feature. The in operator mirrors
+ /// the operation of the for .. in construct, and tests whether the
+ /// rhs has the property given by the lhs. It is different from the
+ /// for .. in construct in that:
+ ///
- it doesn't perform ToObject on the right hand side
+ ///
- it returns true for DontEnum properties.
+ ///
+ /// the left hand operand
+ ///
+ /// the right hand operand
+ ///
+ ///
+ /// true if property name or element number a is a property of b
+ ///
+ public static bool In (object a, object b, Context cx)
+ {
+ if (!(b is IScriptable)) {
+ throw TypeErrorById ("msg.instanceof.not.object");
+ }
+
+ return hasObjectElem ((IScriptable)b, a, cx);
+ }
+
+ public static bool cmp_LT (object val1, object val2)
+ {
+ double d1, d2;
+ if (CliHelper.IsNumber (val1) && CliHelper.IsNumber (val2)) {
+ d1 = Convert.ToDouble (val1);
+ d2 = Convert.ToDouble (val2);
+ }
+ else {
+ if (val1 is IScriptable)
+ val1 = ((IScriptable)val1).GetDefaultValue (typeof (long));
+ if (val2 is IScriptable)
+ val2 = ((IScriptable)val2).GetDefaultValue (typeof (long));
+ if (val1 is string && val2 is string) {
+ return String.CompareOrdinal (((string)val1), (string)val2) < 0;
+ }
+ d1 = ScriptConvert.ToNumber (val1);
+ d2 = ScriptConvert.ToNumber (val2);
+ }
+ return d1 < d2;
+ }
+
+ public static bool cmp_LE (object val1, object val2)
+ {
+ double d1, d2;
+ if (CliHelper.IsNumber (val1) && CliHelper.IsNumber (val2)) {
+ d1 = Convert.ToDouble (val1);
+ d2 = Convert.ToDouble (val2);
+ }
+ else {
+ if (val1 is IScriptable)
+ val1 = ((IScriptable)val1).GetDefaultValue (typeof (long));
+ if (val2 is IScriptable)
+ val2 = ((IScriptable)val2).GetDefaultValue (typeof (long));
+ if (val1 is string && val2 is string) {
+ return String.CompareOrdinal (((string)val1), (string)val2) <= 0;
+ }
+ d1 = ScriptConvert.ToNumber (val1);
+ d2 = ScriptConvert.ToNumber (val2);
+ }
+ return d1 <= d2;
+ }
+
+
+ public static bool hasTopCall (Context cx)
+ {
+ return (cx.topCallScope != null);
+ }
+
+ public static IScriptable getTopCallScope (Context cx)
+ {
+ IScriptable scope = cx.topCallScope;
+ if (scope == null) {
+ throw new Exception ();
+ }
+ return scope;
+ }
+
+ public static object DoTopCall (ICallable callable, Context cx, IScriptable scope, IScriptable thisObj, object [] args)
+ {
+ if (scope == null)
+ throw new ArgumentException ();
+ if (cx.topCallScope != null)
+ throw new Exception ();
+
+ object result;
+ cx.topCallScope = ScriptableObject.GetTopLevelScope (scope);
+ cx.useDynamicScope = cx.HasFeature (Context.Features.DynamicScope);
+ ContextFactory f = cx.Factory;
+ try {
+ result = f.DoTopCall (callable, cx, scope, thisObj, args);
+ }
+ finally {
+ cx.topCallScope = null;
+ // Cleanup cached references
+ cx.cachedXMLLib = null;
+
+ if (cx.currentActivationCall != null) {
+ // Function should always call exitActivationFunction
+ // if it creates activation record
+ throw new Exception (
+ "ActivationCall without exitActivationFunction() invokation."
+ );
+ }
+ }
+ return result;
+ }
+
+ /// Return possibleDynamicScope if staticTopScope
+ /// is present on its prototype chain and return staticTopScope
+ /// otherwise.
+ /// Should only be called when staticTopScope is top scope.
+ ///
+ internal static IScriptable checkDynamicScope (IScriptable possibleDynamicScope, IScriptable staticTopScope)
+ {
+ // Return cx.topCallScope if scope
+ if (possibleDynamicScope == staticTopScope) {
+ return possibleDynamicScope;
+ }
+ IScriptable proto = possibleDynamicScope;
+ for (; ; ) {
+ proto = proto.GetPrototype ();
+ if (proto == staticTopScope) {
+ return possibleDynamicScope;
+ }
+ if (proto == null) {
+ return staticTopScope;
+ }
+ }
+ }
+
+ public static void initScript (BuiltinFunction funObj, IScriptable thisObj, Context cx, IScriptable scope, bool evalScript)
+ {
+ if (cx.topCallScope == null)
+ throw new Exception ();
+
+ int varCount = funObj.ParamAndVarCount;
+ if (varCount != 0) {
+
+ IScriptable varScope = scope;
+ // Never define any variables from var statements inside with
+ // object. See bug 38590.
+ while (varScope is BuiltinWith) {
+ varScope = varScope.ParentScope;
+ }
+
+ for (int i = varCount; i-- != 0; ) {
+ string name = funObj.getParamOrVarName (i);
+ // Don't overwrite existing def if already defined in object
+ // or prototypes of object.
+ if (!ScriptableObject.HasProperty (scope, name)) {
+ if (!evalScript) {
+ // Global var definitions are supposed to be DONTDELETE
+ ScriptableObject.DefineProperty (varScope, name, Undefined.Value, ScriptableObject.PERMANENT);
+ }
+ else {
+ varScope.Put (name, varScope, Undefined.Value);
+ }
+ }
+ }
+ }
+ }
+
+ public static IScriptable createFunctionActivation (BuiltinFunction funObj, IScriptable scope, object [] args)
+ {
+ return new BuiltinCall (funObj, scope, args);
+ }
+
+
+ public static void enterActivationFunction (Context cx, IScriptable activation)
+ {
+ if (cx.topCallScope == null)
+ throw new Exception ();
+
+ BuiltinCall call = (BuiltinCall)activation;
+ call.parentActivationCall = cx.currentActivationCall;
+ cx.currentActivationCall = call;
+ }
+
+ public static void exitActivationFunction (Context cx)
+ {
+ BuiltinCall call = cx.currentActivationCall;
+ cx.currentActivationCall = call.parentActivationCall;
+ call.parentActivationCall = null;
+ }
+
+ internal static BuiltinCall findFunctionActivation (Context cx, IFunction f)
+ {
+ BuiltinCall call = cx.currentActivationCall;
+ while (call != null) {
+ if (call.function == f)
+ return call;
+ call = call.parentActivationCall;
+ }
+ return null;
+ }
+
+ public static IScriptable NewCatchScope (Exception t, IScriptable lastCatchScope, string exceptionName, Context cx, IScriptable scope)
+ {
+ object obj;
+ bool cacheObj;
+
+ if (t is EcmaScriptThrow) {
+ cacheObj = false;
+ obj = ((EcmaScriptThrow)t).Value;
+ }
+ else {
+ cacheObj = true;
+
+ // Create wrapper object unless it was associated with
+ // the previous scope object
+
+ if (lastCatchScope != null) {
+ BuiltinObject last = (BuiltinObject)lastCatchScope;
+ obj = last.GetAssociatedValue (t);
+ if (obj == null)
+ Context.CodeBug ();
+
+ goto getObj_brk;
+ }
+
+ EcmaScriptException re;
+ string errorName;
+ string errorMsg;
+
+ Exception javaException = null;
+
+ if (t is EcmaScriptError) {
+ EcmaScriptError ee = (EcmaScriptError)t;
+ re = ee;
+ errorName = ee.Name;
+ errorMsg = ee.ErrorMessage;
+ }
+ else if (t is EcmaScriptRuntimeException) {
+ re = (EcmaScriptRuntimeException)t;
+ if (t.InnerException != null) {
+ javaException = t.InnerException;
+ errorName = "JavaException";
+ errorMsg = javaException.GetType ().FullName + ": " + javaException.Message;
+ }
+ else {
+ errorName = "InternalError";
+ errorMsg = re.Message;
+ }
+ }
+ else {
+ // Script can catch only instances of JavaScriptException,
+ // EcmaError and EvaluatorException
+ throw Context.CodeBug ();
+ }
+
+ string sourceUri = re.SourceName;
+ if (sourceUri == null) {
+ sourceUri = "";
+ }
+ int line = re.LineNumber;
+ object [] args;
+ if (line > 0) {
+ args = new object [] { errorMsg, sourceUri, (int)line };
+ }
+ else {
+ args = new object [] { errorMsg, sourceUri };
+ }
+
+ IScriptable errorObject = cx.NewObject (scope, errorName, args);
+ ScriptableObject.PutProperty (errorObject, "name", errorName);
+
+ if (javaException != null) {
+ object wrap = cx.Wrap (scope, javaException, null);
+ ScriptableObject.DefineProperty (errorObject, "javaException", wrap, ScriptableObject.PERMANENT | ScriptableObject.READONLY);
+ }
+ if (re != null) {
+ object wrap = cx.Wrap (scope, re, null);
+ ScriptableObject.DefineProperty (errorObject, "rhinoException", wrap, ScriptableObject.PERMANENT | ScriptableObject.READONLY);
+ }
+
+ obj = errorObject;
+ }
+
+ getObj_brk:
+ ;
+
+
+
+ BuiltinObject catchScopeObject = new BuiltinObject ();
+ // See ECMA 12.4
+ catchScopeObject.DefineProperty (exceptionName, obj, ScriptableObject.PERMANENT);
+ if (cacheObj) {
+ catchScopeObject.AssociateValue (t, obj);
+ }
+ return catchScopeObject;
+ }
+
+ public static IScriptable enterWith (object obj, Context cx, IScriptable scope)
+ {
+ IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj);
+ if (sobj == null) {
+ throw TypeErrorById ("msg.undef.with", ScriptConvert.ToString (obj));
+ }
+ if (sobj is XMLObject) {
+ XMLObject xmlObject = (XMLObject)sobj;
+ return xmlObject.EnterWith (scope);
+ }
+ return new BuiltinWith (scope, sobj);
+ }
+
+ public static IScriptable leaveWith (IScriptable scope)
+ {
+ BuiltinWith nw = (BuiltinWith)scope;
+ return nw.ParentScope;
+ }
+
+ public static IScriptable enterDotQuery (object value, IScriptable scope)
+ {
+ if (!(value is XMLObject)) {
+ throw NotXmlError (value);
+ }
+ XMLObject obj = (XMLObject)value;
+ return obj.EnterDotQuery (scope);
+ }
+
+ public static object updateDotQuery (bool value, IScriptable scope)
+ {
+ // Return null to continue looping
+ BuiltinWith nw = (BuiltinWith)scope;
+ return nw.UpdateDotQuery (value);
+ }
+
+ public static IScriptable leaveDotQuery (IScriptable scope)
+ {
+ BuiltinWith nw = (BuiltinWith)scope;
+ return nw.ParentScope;
+ }
+
+ public static void setFunctionProtoAndParent (BaseFunction fn, IScriptable scope)
+ {
+ fn.ParentScope = scope;
+ fn.SetPrototype (ScriptableObject.GetFunctionPrototype (scope));
+ }
+
+ public static void setObjectProtoAndParent (ScriptableObject obj, IScriptable scope)
+ {
+ // Compared with function it always sets the scope to top scope
+ scope = ScriptableObject.GetTopLevelScope (scope);
+ obj.ParentScope = scope;
+ IScriptable proto = ScriptableObject.getClassPrototype (scope, obj.ClassName);
+ obj.SetPrototype (proto);
+ }
+
+ public static void initFunction (Context cx, IScriptable scope, BuiltinFunction function, int type, bool fromEvalCode)
+ {
+ if (type == FunctionNode.FUNCTION_STATEMENT) {
+ string name = function.FunctionName;
+ if (name != null && name.Length != 0) {
+ if (!fromEvalCode) {
+ // ECMA specifies that functions defined in global and
+ // function scope outside eval should have DONTDELETE set.
+ ScriptableObject.DefineProperty (scope, name, function, ScriptableObject.PERMANENT);
+ }
+ else {
+ scope.Put (name, scope, function);
+ }
+ }
+ }
+ else if (type == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) {
+ string name = function.FunctionName;
+ if (name != null && name.Length != 0) {
+ // Always put function expression statements into initial
+ // activation object ignoring the with statement to follow
+ // SpiderMonkey
+ while (scope is BuiltinWith) {
+ scope = scope.ParentScope;
+ }
+ scope.Put (name, scope, function);
+ }
+ }
+ else {
+ throw Context.CodeBug ();
+ }
+ }
+
+ public static IScriptable newArrayLiteral (object [] objects, int [] skipIndexces, Context cx, IScriptable scope)
+ {
+ int count = objects.Length;
+ int skipCount = 0;
+ if (skipIndexces != null) {
+ skipCount = skipIndexces.Length;
+ }
+ int length = count + skipCount;
+ int lengthObj = (int)length;
+ IScriptable arrayObj;
+ /*
+ * If the version is 120, then new Array(4) means create a new
+ * array with 4 as the first element. In this case, we have to
+ * set length property manually.
+ */
+ if (cx.Version == Context.Versions.JS1_2) {
+ arrayObj = cx.NewObject (scope, "Array", ScriptRuntime.EmptyArgs);
+ ScriptableObject.PutProperty (arrayObj, "length", (object)lengthObj);
+ }
+ else {
+ arrayObj = cx.NewObject (scope, "Array", new object [] { lengthObj });
+ }
+ int skip = 0;
+ for (int i = 0, j = 0; i != length; ++i) {
+ if (skip != skipCount && skipIndexces [skip] == i) {
+ ++skip;
+ continue;
+ }
+ ScriptableObject.PutProperty (arrayObj, i, objects [j]);
+ ++j;
+ }
+ return arrayObj;
+ }
+
+ public static IScriptable newObjectLiteral (object [] propertyIds, object [] propertyValues, Context cx, IScriptable scope)
+ {
+ IScriptable obj = cx.NewObject (scope);
+ for (int i = 0, end = propertyIds.Length; i != end; ++i) {
+ object id = propertyIds [i];
+ object value = propertyValues [i];
+
+ if (id is Node.GetterPropertyLiteral) {
+ BuiltinObject nativeObj = (BuiltinObject)obj;
+ InterpretedFunction fun = (InterpretedFunction)value;
+ nativeObj.DefineGetter ((string)((Node.GetterPropertyLiteral)id).Property, fun);
+ }
+ else if (id is Node.SetterPropertyLiteral) {
+ BuiltinObject nativeObj = (BuiltinObject)obj;
+ InterpretedFunction fun = (InterpretedFunction)value;
+ nativeObj.DefineSetter ((string)((Node.SetterPropertyLiteral)id).Property, fun);
+ }
+ else if (id is string) {
+ ScriptableObject.PutProperty (obj, (string)id, value);
+ }
+ else {
+ ScriptableObject.PutProperty (obj, (int)id, value);
+ }
+ }
+ return obj;
+ }
+
+ public static bool isArrayObject (object obj)
+ {
+ return obj is BuiltinArray || obj is Arguments;
+ }
+
+ public static object [] getArrayElements (IScriptable obj)
+ {
+ Context cx = Context.CurrentContext;
+ long longLen = BuiltinArray.getLengthProperty (cx, obj);
+ if (longLen > int.MaxValue) {
+ // arrays beyond MAX_INT is not in Java in any case
+ throw new ArgumentException ();
+ }
+ int len = (int)longLen;
+ if (len == 0) {
+ return ScriptRuntime.EmptyArgs;
+ }
+ else {
+ object [] result = new object [len];
+ for (int i = 0; i < len; i++) {
+ object elem = ScriptableObject.GetProperty (obj, i);
+ result [i] = (elem == UniqueTag.NotFound) ? Undefined.Value : elem;
+ }
+ return result;
+ }
+ }
+
+ internal static void checkDeprecated (Context cx, string name)
+ {
+ Context.Versions version = cx.Version;
+ if (version >= Context.Versions.JS1_4 || version == Context.Versions.Default) {
+ string msg = GetMessage ("msg.deprec.ctor", name);
+ if (version == Context.Versions.Default)
+ Context.ReportWarning (msg);
+ else
+ throw Context.ReportRuntimeError (msg);
+ }
+ }
+
+
+ private static ResourceManager m_ResourceManager = null;
+
+ public static string GetMessage (string messageId, params object [] arguments)
+ {
+ Context cx = Context.CurrentContext;
+
+ // Get current culture
+ CultureInfo culture = null;
+ if (cx != null)
+ culture = cx.CurrentCulture;
+
+ if (m_ResourceManager == null) {
+ m_ResourceManager = new ResourceManager (
+ "EcmaScript.NET.Resources.Messages", typeof (ScriptRuntime).Assembly);
+ }
+
+ string formatString = m_ResourceManager.GetString (messageId, culture);
+ if (formatString == null)
+ throw new Exception ("Missing no message resource found for message property " + messageId);
+
+ if (arguments == null)
+ arguments = new object [0];
+ if (arguments.Length == 0)
+ return formatString;
+ return string.Format (formatString, arguments);
+ }
+
+ public static EcmaScriptError ConstructError (string error, string message)
+ {
+ int [] linep = new int [1];
+ string filename = Context.GetSourcePositionFromStack (linep);
+ return ConstructError (error, message, filename, linep [0], null, 0);
+ }
+
+ public static EcmaScriptError ConstructError (string error, string message, string sourceName, int lineNumber, string lineSource, int columnNumber)
+ {
+ return new EcmaScriptError (error, message, sourceName, lineNumber, lineSource, columnNumber);
+ }
+
+ public static EcmaScriptError TypeError (string message)
+ {
+ return ConstructError ("TypeError", message);
+ }
+
+ public static EcmaScriptError TypeErrorById (string messageId, params string [] args)
+ {
+ return TypeError (GetMessage (messageId, args));
+ }
+
+ public static Exception UndefReadError (object obj, object id)
+ {
+ string idStr = (id == null) ? "null" : id.ToString ();
+ return TypeErrorById ("msg.undef.prop.read", ScriptConvert.ToString (obj), idStr);
+ }
+
+ public static Exception UndefCallError (object obj, object id)
+ {
+ string idStr = (id == null) ? "null" : id.ToString ();
+ return TypeErrorById ("msg.undef.method.call", ScriptConvert.ToString (obj), idStr);
+ }
+
+ public static Exception UndefWriteError (object obj, object id, object value)
+ {
+ string idStr = (id == null) ? "null" : id.ToString ();
+ string valueStr = (value is IScriptable) ? value.ToString () : ScriptConvert.ToString (value);
+ return TypeErrorById ("msg.undef.prop.write", ScriptConvert.ToString (obj), idStr, valueStr);
+ }
+
+ public static Exception NotFoundError (IScriptable obj, string property)
+ {
+ // TODO: use object to improve the error message
+ string msg = GetMessage ("msg.is.not.defined", property);
+ throw ConstructError ("ReferenceError", msg);
+ }
+
+ public static Exception NotFunctionError (object value)
+ {
+ return NotFunctionError (value, value);
+ }
+
+ public static Exception NotFunctionError (object value, object messageHelper)
+ {
+ // TODO: Use value for better error reporting
+ string msg = (messageHelper == null) ? "null" : messageHelper.ToString ();
+ if (value == UniqueTag.NotFound) {
+ return TypeErrorById ("msg.function.not.found", msg);
+ }
+ return TypeErrorById ("msg.isnt.function", msg, value == null ? "null" : value.GetType ().FullName);
+ }
+
+ private static Exception NotXmlError (object value)
+ {
+ throw TypeErrorById ("msg.isnt.xml.object", ScriptConvert.ToString (value));
+ }
+
+ internal static void WarnAboutNonJSObject (object nonJSObject)
+ {
+ string message = "+++ USAGE WARNING: Missed Context.Wrap() conversion:\n"
+ + "Runtime detected object " + nonJSObject + " of class " + nonJSObject.GetType ().FullName + " where it expected String, Number, Boolean or Scriptable instance. "
+ + "Please check your code for missig Context.Wrap() call.";
+
+ Context.ReportWarning (message);
+ Console.Error.WriteLine (message);
+ }
+
+
+ private static XMLLib CurrentXMLLib (Context cx)
+ {
+ // Scripts should be running to access this
+ if (cx.topCallScope == null)
+ throw new Exception ();
+
+ XMLLib xmlLib = cx.cachedXMLLib;
+ if (xmlLib == null) {
+ xmlLib = XMLLib.ExtractFromScope (cx.topCallScope);
+ if (xmlLib == null)
+ throw new Exception ();
+ cx.cachedXMLLib = xmlLib;
+ }
+
+ return xmlLib;
+ }
+
+ /// Escapes the reserved characters in a value of an attribute
+ ///
+ ///
+ /// Unescaped text
+ ///
+ /// The escaped text
+ ///
+ public static string escapeAttributeValue (object value, Context cx)
+ {
+ XMLLib xmlLib = CurrentXMLLib (cx);
+ return xmlLib.EscapeAttributeValue (value);
+ }
+
+ /// Escapes the reserved characters in a value of a text node
+ ///
+ ///
+ /// Unescaped text
+ ///
+ /// The escaped text
+ ///
+ public static string escapeTextValue (object value, Context cx)
+ {
+ XMLLib xmlLib = CurrentXMLLib (cx);
+ return xmlLib.EscapeTextValue (value);
+ }
+
+ public static IRef memberRef (object obj, object elem, Context cx, int memberTypeFlags)
+ {
+ if (!(obj is XMLObject)) {
+ throw NotXmlError (obj);
+ }
+ XMLObject xmlObject = (XMLObject)obj;
+ return xmlObject.MemberRef (cx, elem, memberTypeFlags);
+ }
+
+ public static IRef memberRef (object obj, object ns, object elem, Context cx, int memberTypeFlags)
+ {
+ if (!(obj is XMLObject)) {
+ throw NotXmlError (obj);
+ }
+ XMLObject xmlObject = (XMLObject)obj;
+ return xmlObject.MemberRef (cx, ns, elem, memberTypeFlags);
+ }
+
+ public static IRef nameRef (object name, Context cx, IScriptable scope, int memberTypeFlags)
+ {
+ XMLLib xmlLib = CurrentXMLLib (cx);
+ return xmlLib.NameRef (cx, name, scope, memberTypeFlags);
+ }
+
+ public static IRef nameRef (object ns, object name, Context cx, IScriptable scope, int memberTypeFlags)
+ {
+ XMLLib xmlLib = CurrentXMLLib (cx);
+ return xmlLib.NameRef (cx, ns, name, scope, memberTypeFlags);
+ }
+
+ private static void storeIndexResult (Context cx, int index)
+ {
+ cx.scratchIndex = index;
+ }
+
+ internal static int lastIndexResult (Context cx)
+ {
+ return cx.scratchIndex;
+ }
+
+ public static void storeUint32Result (Context cx, long value)
+ {
+ if (((ulong)value >> 32) != 0)
+ throw new ArgumentException ();
+ cx.scratchUint32 = value;
+ }
+
+ public static long lastUint32Result (Context cx)
+ {
+ long value = cx.scratchUint32;
+ if ((ulong)value >> 32 != 0)
+ throw new Exception ();
+ return value;
+ }
+
+ private static void storeScriptable (Context cx, IScriptable value)
+ {
+ // The previosly stored scratchScriptable should be consumed
+ if (cx.scratchScriptable != null)
+ throw new Exception ();
+ cx.scratchScriptable = value;
+ }
+
+ public static IScriptable lastStoredScriptable (Context cx)
+ {
+ IScriptable result = cx.scratchScriptable;
+ cx.scratchScriptable = null;
+ return result;
+ }
+
+ internal static string makeUrlForGeneratedScript (bool isEval, string masterScriptUrl, int masterScriptLine)
+ {
+ if (isEval) {
+ return masterScriptUrl + '#' + masterScriptLine + "(eval)";
+ }
+ else {
+ return masterScriptUrl + '#' + masterScriptLine + "(Function)";
+ }
+ }
+
+ internal static bool isGeneratedScript (string sourceUrl)
+ {
+ // ALERT: this may clash with a valid URL containing (eval) or
+ // (Function)
+ return sourceUrl.IndexOf ("(eval)") >= 0 || sourceUrl.IndexOf ("(Function)") >= 0;
+ }
+
+
+ public static readonly object [] EmptyArgs = new object [0];
+ public static readonly string [] EmptyStrings = new string [0];
+
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/ScriptableObject.cs b/src/EcmaScript.NET/ScriptableObject.cs
similarity index 97%
rename from Code/EcmaScript.NET/ScriptableObject.cs
rename to src/EcmaScript.NET/ScriptableObject.cs
index dda5f37..edd256b 100644
--- a/Code/EcmaScript.NET/ScriptableObject.cs
+++ b/src/EcmaScript.NET/ScriptableObject.cs
@@ -1,1410 +1,1410 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-// API class
-using System;
-using System.Reflection;
-using System.Runtime.InteropServices;
-using System.Collections;
-
-using EcmaScript.NET.Debugging;
-using EcmaScript.NET.Attributes;
-using EcmaScript.NET.Collections;
-
-namespace EcmaScript.NET
-{
-
- /// This is the default implementation of the Scriptable interface. This
- /// class provides convenient default behavior that makes it easier to
- /// define host objects.
- ///
- /// Various properties and methods of JavaScript objects can be conveniently
- /// defined using methods of ScriptableObject.
- ///
- /// Classes extending ScriptableObject must define the getClassName method.
- ///
- ///
- public abstract class ScriptableObject : IScriptable, DebuggableObject
- {
- /// Return the name of the class.
- ///
- /// This is typically the same name as the constructor.
- /// Classes extending ScriptableObject must implement this abstract
- /// method.
- ///
- public abstract string ClassName { get;}
-
-
- /// Returns the parent (enclosing) scope of the object.
- /// Sets the parent (enclosing) scope of the object.
- public IScriptable ParentScope
- {
- get
- {
- return parentScopeObject;
- }
-
- set
- {
- parentScopeObject = value;
- }
-
- }
- /// Returns an array of ids for the properties of the object.
- ///
- /// All properties, even those with attribute DONTENUM, are listed.
- ///
- ///
- /// an array of java.lang.Objects with an entry for every
- /// listed property. Properties accessed via an integer index will
- /// have a corresponding
- /// Integer entry in the returned array. Properties accessed by
- /// a String will have a String entry in the returned array.
- ///
- virtual public object [] AllIds
- {
- get
- {
- return GetIds (true);
- }
-
- }
- /// Return true if this object is sealed.
- ///
- /// It is an error to attempt to add or remove properties to
- /// a sealed object.
- ///
- ///
- /// true if sealed, false otherwise.
- ///
- public bool Sealed
- {
- get
- {
- return count < 0;
- }
-
- }
-
- /// The empty property attribute.
- ///
- /// Used by getAttributes() and setAttributes().
- ///
- ///
- public const int EMPTY = 0x00;
-
- /// Property attribute indicating assignment to this property is ignored.
- ///
- ///
- public const int READONLY = 0x01;
-
- /// Property attribute indicating property is not enumerated.
- ///
- /// Only enumerated properties will be returned by getIds().
- ///
- ///
- public const int DONTENUM = 0x02;
-
- /// Property attribute indicating property cannot be deleted.
- ///
- ///
- public const int PERMANENT = 0x04;
-
- internal static void CheckValidAttributes (int attributes)
- {
- const int mask = READONLY | DONTENUM | PERMANENT;
- if ((attributes & ~mask) != 0) {
- throw new ArgumentException (Convert.ToString (attributes));
- }
- }
-
- public ScriptableObject ()
- {
- }
-
- public ScriptableObject (IScriptable scope, IScriptable prototype)
- {
- if (scope == null)
- throw new ArgumentException ();
-
- parentScopeObject = scope;
- prototypeObject = prototype;
- }
-
- /// Returns true if the named property is defined.
- ///
- ///
- /// the name of the property
- ///
- /// the object in which the lookup began
- ///
- /// true if and only if the property was found in the object
- ///
- public virtual bool Has (string name, IScriptable start)
- {
- return null != GetNamedSlot (name);
- }
-
- /// Returns true if the property index is defined.
- ///
- ///
- /// the numeric index for the property
- ///
- /// the object in which the lookup began
- ///
- /// true if and only if the property was found in the object
- ///
- public virtual bool Has (int index, IScriptable start)
- {
- return null != GetSlot (null, index);
- }
-
- /// Returns the value of the named property or NOT_FOUND.
- ///
- /// If the property was created using defineProperty, the
- /// appropriate getter method is called.
- ///
- ///
- /// the name of the property
- ///
- /// the object in which the lookup began
- ///
- /// the value of the property (may be null), or NOT_FOUND
- ///
- public virtual object Get (string name, IScriptable start)
- {
- Slot slot = GetNamedSlot (name);
- if (slot == null) {
- return UniqueTag.NotFound;
- }
- return slot.GetValue (null, start, start);
- }
-
- /// Returns the value of the indexed property or NOT_FOUND.
- ///
- ///
- /// the numeric index for the property
- ///
- /// the object in which the lookup began
- ///
- /// the value of the property (may be null), or NOT_FOUND
- ///
- public virtual object Get (int index, IScriptable start)
- {
- Slot slot = GetSlot (null, index);
- if (slot == null) {
- return UniqueTag.NotFound;
- }
- return slot.GetValue (null, start, start);
- }
-
- /// Sets the value of the named property, creating it if need be.
- ///
- /// If the property was created using defineProperty, the
- /// appropriate setter method is called.
- ///
- /// If the property's attributes include READONLY, no action is
- /// taken.
- /// This method will actually set the property in the start
- /// object.
- ///
- ///
- /// the name of the property
- ///
- /// the object whose property is being set
- ///
- /// value to set the property to
- ///
- public virtual object Put (string name, IScriptable start, object value)
- {
- Slot slot = lastAccess; // Get local copy
- if ((object)name != (object)slot.stringKey || slot.wasDeleted != 0) {
- int hash = name.GetHashCode ();
- slot = GetSlot (name, hash);
- if (slot == null) {
- if (start != this) {
- start.Put (name, start, value);
- return value;
- }
- slot = AddSlot (name, hash, null);
- }
- // Note: cache is not updated in put
- }
- if (start == this && Sealed) {
- throw Context.ReportRuntimeErrorById ("msg.modify.sealed", name);
- }
- if ((slot.attributes & ScriptableObject.READONLY) != 0) {
- // FINDME
- Context cx = Context.CurrentContext;
- if (cx.Version == Context.Versions.JS1_2) {
- throw Context.ReportRuntimeErrorById ("msg.read-only", name);
- } else {
- if (cx.HasFeature (Context.Features.Strict)) {
- Context.ReportWarningById ("msg.read-only", name);
- }
- }
- return value;
- }
- if (this == start) {
- return slot.SetValue (null, start, start, value);
- }
- else {
- if (slot.setter != null) {
- Slot newSlot = (Slot)slot.Clone ();
- ((ScriptableObject)start).AddSlotImpl (newSlot.stringKey, newSlot.intKey, newSlot);
- return newSlot.SetValue (null, start, start, value);
- }
- else {
- return start.Put (name, start, value);
- }
- }
- return value;
- }
-
- /// Sets the value of the indexed property, creating it if need be.
- ///
- ///
- /// the numeric index for the property
- ///
- /// the object whose property is being set
- ///
- /// value to set the property to
- ///
- public virtual object Put (int index, IScriptable start, object value)
- {
- Slot slot = GetSlot (null, index);
- if (slot == null) {
- if (start != this) {
- return start.Put (index, start, value);
- }
- slot = AddSlot (null, index, null);
- }
- if (start == this && Sealed) {
- throw Context.ReportRuntimeErrorById ("msg.modify.sealed", Convert.ToString (index));
- }
- if ((slot.attributes & ScriptableObject.READONLY) != 0) {
- return slot.GetValue (null, start, start); // TODO: ???
- }
- if (this == start) {
- return slot.SetValue (null, start, start, value);
- }
- else {
- return start.Put (index, start, value);
- }
- }
-
- /// Removes a named property from the object.
- ///
- /// If the property is not found, or it has the PERMANENT attribute,
- /// no action is taken.
- ///
- ///
- /// the name of the property
- ///
- public virtual void Delete (string name)
- {
- RemoveSlot (name, name.GetHashCode ());
- }
-
- /// Removes the indexed property from the object.
- ///
- /// If the property is not found, or it has the PERMANENT attribute,
- /// no action is taken.
- ///
- ///
- /// the numeric index for the property
- ///
- public virtual void Delete (int index)
- {
- RemoveSlot (null, index);
- }
-
-
-
-
-
- /// Get the attributes of a named property.
- ///
- /// The property is specified by name
- /// as defined for has.
- ///
- ///
- /// the identifier for the property
- ///
- /// the bitset of attributes
- ///
- /// EvaluatorException if the named property is not found
- ///
- public virtual int GetAttributes (string name)
- {
- Slot slot = GetNamedSlot (name);
- if (slot == null) {
- throw Context.ReportRuntimeErrorById ("msg.prop.not.found", name);
- }
- return slot.attributes;
- }
-
- /// Get the attributes of an indexed property.
- ///
- ///
- /// the numeric index for the property
- ///
- /// EvaluatorException if the named property is not found
- /// is not found
- ///
- /// the bitset of attributes
- ///
- public virtual int GetAttributes (int index)
- {
- Slot slot = GetSlot (null, index);
- if (slot == null) {
- throw Context.ReportRuntimeErrorById ("msg.prop.not.found", Convert.ToString (index));
- }
- return slot.attributes;
- }
-
- /// Set the attributes of a named property.
- ///
- /// The property is specified by name
- /// as defined for has.
- ///
- /// The possible attributes are READONLY, DONTENUM,
- /// and PERMANENT. Combinations of attributes
- /// are expressed by the bitwise OR of attributes.
- /// EMPTY is the state of no attributes set. Any unused
- /// bits are reserved for future use.
- ///
- ///
- /// the name of the property
- ///
- /// the bitset of attributes
- ///
- /// EvaluatorException if the named property is not found
- ///
- public virtual void SetAttributes (string name, int attributes)
- {
- CheckValidAttributes (attributes);
- Slot slot = GetNamedSlot (name);
- if (slot == null) {
- throw Context.ReportRuntimeErrorById ("msg.prop.not.found", name);
- }
- slot.attributes = (short)attributes;
- }
-
- /// Set the attributes of an indexed property.
- ///
- ///
- /// the numeric index for the property
- ///
- /// the bitset of attributes
- ///
- /// EvaluatorException if the named property is not found
- ///
- public virtual void SetAttributes (int index, int attributes)
- {
- CheckValidAttributes (attributes);
- Slot slot = GetSlot (null, index);
- if (slot == null) {
- throw Context.ReportRuntimeErrorById ("msg.prop.not.found", Convert.ToString (index));
- }
- slot.attributes = (short)attributes;
- }
-
- /// Returns the prototype of the object.
- public virtual IScriptable GetPrototype ()
- {
- return prototypeObject;
- }
-
- /// Sets the prototype of the object.
- public virtual void SetPrototype (IScriptable m)
- {
- prototypeObject = m;
- }
-
- /// Returns an array of ids for the properties of the object.
- ///
- /// Any properties with the attribute DONTENUM are not listed.
- ///
- ///
- /// an array of java.lang.Objects with an entry for every
- /// listed property. Properties accessed via an integer index will
- /// have a corresponding
- /// Integer entry in the returned array. Properties accessed by
- /// a String will have a String entry in the returned array.
- ///
- public virtual object [] GetIds ()
- {
- return GetIds (false);
- }
-
- /// Implements the [[DefaultValue]] internal method.
- ///
- /// Note that the toPrimitive conversion is a no-op for
- /// every type other than Object, for which [[DefaultValue]]
- /// is called. See ECMA 9.1.
- ///
- /// A hint of null means "no hint".
- ///
- ///
- /// the type hint
- ///
- /// the default value for the object
- ///
- /// See ECMA 8.6.2.6.
- ///
- public virtual object GetDefaultValue (Type typeHint)
- {
- Context cx = null;
- for (int i = 0; i < 2; i++) {
- bool tryToString;
- if (typeHint == typeof (string)) {
- tryToString = (i == 0);
- }
- else {
- tryToString = (i == 1);
- }
-
- string methodName;
- object [] args;
- if (tryToString) {
- methodName = "toString";
- args = ScriptRuntime.EmptyArgs;
- }
- else {
- methodName = "valueOf";
- args = new object [1];
- string hint;
- if (typeHint == null) {
- hint = "undefined";
- }
- else if (typeHint == typeof (string)) {
- hint = "string";
- }
- else if (typeHint == typeof (IScriptable)) {
- hint = "object";
- }
- else if (typeHint == typeof (IFunction)) {
- hint = "function";
- }
- else if (typeHint == typeof (bool) || typeHint == typeof (bool)) {
- hint = "boolean";
- }
- else if (CliHelper.IsNumberType (typeHint) || typeHint == typeof (byte) || typeHint == typeof (sbyte)) {
- hint = "number";
- }
- else {
- throw Context.ReportRuntimeErrorById ("msg.invalid.type", typeHint.ToString ());
- }
- args [0] = hint;
- }
- object v = GetProperty (this, methodName);
- if (!(v is IFunction))
- continue;
- IFunction fun = (IFunction)v;
- if (cx == null)
- cx = Context.CurrentContext;
- v = fun.Call (cx, fun.ParentScope, this, args);
- if (v != null) {
- if (!(v is IScriptable)) {
- return v;
- }
- if (typeHint == typeof (IScriptable) || typeHint == typeof (IFunction)) {
- return v;
- }
- if (tryToString && v is Wrapper) {
- // Let a wrapped java.lang.String pass for a primitive
- // string.
- object u = ((Wrapper)v).Unwrap ();
- if (u is string)
- return u;
- }
- }
- }
- // fall through to error
- string arg = (typeHint == null) ? "undefined" : typeHint.FullName;
- throw ScriptRuntime.TypeErrorById ("msg.default.value", arg);
- }
-
- /// Implements the instanceof operator.
- ///
- /// This operator has been proposed to ECMA.
- ///
- ///
- /// The value that appeared on the LHS of the instanceof
- /// operator
- ///
- /// true if "this" appears in value's prototype chain
- ///
- ///
- public virtual bool HasInstance (IScriptable instance)
- {
-
- // According to specs -- section 11.8.6 of ECMA-262 -- instanceof operator
- // on objects NOT implementing [[HasInstance]] internal method should
- // throw a TypeError exception. Hence, in the following script the
- // catch block must get executed, (since Math object does not implement
- // [[HasInstance]] method).
- throw ScriptRuntime.TypeError ("msg.bad.instanceof.rhs");
-
-
- // Default for JS objects (other than Function) is to do prototype
- // chasing. This will be overridden in NativeFunction and non-JS
- // objects.
- //return ScriptRuntime.jsDelegatesTo(instance, this);
- }
-
- /// Custom == operator.
- /// Must return {@link Scriptable#NOT_FOUND} if this object does not
- /// have custom equality operator for the given value,
- /// Boolean.TRUE if this object is equivalent to value,
- /// Boolean.FALSE if this object is not equivalent to
- /// value.
- ///
- /// The default implementation returns Boolean.TRUE
- /// if this == value or {@link Scriptable#NOT_FOUND} otherwise.
- /// It indicates that by default custom equality is available only if
- /// value is this in which case true is returned.
- ///
- protected internal virtual object EquivalentValues (object value)
- {
- return (this == value) ? (object)true : UniqueTag.NotFound;
- }
-
- /// Define a JavaScript property.
- ///
- /// Creates the property with an initial value and sets its attributes.
- ///
- ///
- /// the name of the property to define.
- ///
- /// the initial value of the property
- ///
- /// the attributes of the JavaScript property
- ///
- public virtual void DefineProperty (string propertyName, object value, int attributes)
- {
- Put (propertyName, this, value);
- SetAttributes (propertyName, attributes);
- }
-
- /// Utility method to add properties to arbitrary Scriptable object.
- /// If destination is instance of ScriptableObject, calls
- /// defineProperty there, otherwise calls put in destination
- /// ignoring attributes
- ///
- public static void DefineProperty (IScriptable destination, string propertyName, object value, int attributes)
- {
- if (!(destination is ScriptableObject)) {
- destination.Put (propertyName, destination, value);
- return;
- }
- ScriptableObject so = (ScriptableObject)destination;
- so.DefineProperty (propertyName, value, attributes);
- }
-
-
-
- /// Get the Object.prototype property.
- /// See ECMA 15.2.4.
- ///
- public static IScriptable GetObjectPrototype (IScriptable scope)
- {
- return getClassPrototype (scope, "Object");
- }
-
- /// Get the Function.prototype property.
- /// See ECMA 15.3.4.
- ///
- public static IScriptable GetFunctionPrototype (IScriptable scope)
- {
- return getClassPrototype (scope, "Function");
- }
-
- /// Get the prototype for the named class.
- ///
- /// For example, getClassPrototype(s, "Date") will first
- /// walk up the parent chain to find the outermost scope, then will
- /// search that scope for the Date constructor, and then will
- /// return Date.prototype. If any of the lookups fail, or
- /// the prototype is not a JavaScript object, then null will
- /// be returned.
- ///
- ///
- /// an object in the scope chain
- ///
- /// the name of the constructor
- ///
- /// the prototype for the named class, or null if it
- /// cannot be found.
- ///
- public static IScriptable getClassPrototype (IScriptable scope, string className)
- {
- scope = GetTopLevelScope (scope);
- object ctor = GetProperty (scope, className);
- object proto;
- if (ctor is BaseFunction) {
- proto = ((BaseFunction)ctor).PrototypeProperty;
- }
- else if (ctor is IScriptable) {
- IScriptable ctorObj = (IScriptable)ctor;
- proto = ctorObj.Get ("prototype", ctorObj);
- }
- else {
- return null;
- }
- if (proto is IScriptable) {
- return (IScriptable)proto;
- }
- return null;
- }
-
- /// Get the global scope.
- ///
- /// Walks the parent scope chain to find an object with a null
- /// parent scope (the global object).
- ///
- ///
- /// a JavaScript object
- ///
- /// the corresponding global scope
- ///
- public static IScriptable GetTopLevelScope (IScriptable obj)
- {
- for (; ; ) {
- IScriptable parent = obj.ParentScope;
- if (parent == null) {
- return obj;
- }
- obj = parent;
- }
- }
-
- /// Seal this object.
- ///
- /// A sealed object may not have properties added or removed. Once
- /// an object is sealed it may not be unsealed.
- ///
- ///
- public virtual void SealObject ()
- {
- lock (this) {
- if (count >= 0) {
- count = -1 - count;
- }
- }
- }
-
- /// Gets a named property from an object or any object in its prototype chain.
- ///
- /// Searches the prototype chain for a property named name.
- ///
- ///
- /// a JavaScript object
- ///
- /// a property name
- ///
- /// the value of a property with name name found in
- /// obj or any object in its prototype chain, or
- /// Scriptable.NOT_FOUND if not found
- ///
- public static object GetProperty (IScriptable obj, string name)
- {
- IScriptable start = obj;
- object result;
- do {
- result = obj.Get (name, start);
- if (result != UniqueTag.NotFound)
- break;
- obj = obj.GetPrototype ();
- }
- while (obj != null);
- return result;
- }
-
- /// Gets an indexed property from an object or any object in its prototype chain.
- ///
- /// Searches the prototype chain for a property with integral index
- /// index. Note that if you wish to look for properties with numerical
- /// but non-integral indicies, you should use getProperty(Scriptable,String) with
- /// the string value of the index.
- ///
- ///
- /// a JavaScript object
- ///
- /// an integral index
- ///
- /// the value of a property with index index found in
- /// obj or any object in its prototype chain, or
- /// Scriptable.NOT_FOUND if not found
- ///
- public static object GetProperty (IScriptable obj, int index)
- {
- IScriptable start = obj;
- object result;
- do {
- result = obj.Get (index, start);
- if (result != UniqueTag.NotFound)
- break;
- obj = obj.GetPrototype ();
- }
- while (obj != null);
- return result;
- }
-
- /// Returns whether a named property is defined in an object or any object
- /// in its prototype chain.
- ///
- /// Searches the prototype chain for a property named name.
- ///
- ///
- /// a JavaScript object
- ///
- /// a property name
- ///
- /// the true if property was found
- ///
- public static bool HasProperty (IScriptable obj, string name)
- {
- return null != GetBase (obj, name);
- }
-
- /// Returns whether an indexed property is defined in an object or any object
- /// in its prototype chain.
- ///
- /// Searches the prototype chain for a property with index index.
- ///
- ///
- /// a JavaScript object
- ///
- /// a property index
- ///
- /// the true if property was found
- ///
- public static bool HasProperty (IScriptable obj, int index)
- {
- return null != GetBase (obj, index);
- }
-
- /// Puts a named property in an object or in an object in its prototype chain.
- ///
- /// Seaches for the named property in the prototype chain. If it is found,
- /// the value of the property is changed. If it is not found, a new
- /// property is added in obj.
- ///
- /// a JavaScript object
- ///
- /// a property name
- ///
- /// any JavaScript value accepted by Scriptable.put
- ///
- public static object PutProperty (IScriptable obj, string name, object value)
- {
- IScriptable toBase = GetBase (obj, name);
- if (toBase == null)
- toBase = obj;
- return toBase.Put (name, obj, value);
- }
-
- /// Puts an indexed property in an object or in an object in its prototype chain.
- ///
- /// Seaches for the indexed property in the prototype chain. If it is found,
- /// the value of the property is changed. If it is not found, a new
- /// property is added in obj.
- ///
- /// a JavaScript object
- ///
- /// a property index
- ///
- /// any JavaScript value accepted by Scriptable.put
- ///
- public static object PutProperty (IScriptable obj, int index, object value)
- {
- IScriptable toBase = GetBase (obj, index);
- if (toBase == null)
- toBase = obj;
- return toBase.Put (index, obj, value);
- }
-
- /// Removes the property from an object or its prototype chain.
- ///
- /// Searches for a property with name in obj or
- /// its prototype chain. If it is found, the object's delete
- /// method is called.
- ///
- /// a JavaScript object
- ///
- /// a property name
- ///
- /// true if the property doesn't exist or was successfully removed
- ///
- public static bool DeleteProperty (IScriptable obj, string name)
- {
- IScriptable toBase = GetBase (obj, name);
- if (toBase == null)
- return true;
- toBase.Delete (name);
- return !toBase.Has (name, obj);
- }
-
- /// Removes the property from an object or its prototype chain.
- ///
- /// Searches for a property with index in obj or
- /// its prototype chain. If it is found, the object's delete
- /// method is called.
- ///
- /// a JavaScript object
- ///
- /// a property index
- ///
- /// true if the property doesn't exist or was successfully removed
- ///
- public static bool DeleteProperty (IScriptable obj, int index)
- {
- IScriptable toBase = GetBase (obj, index);
- if (toBase == null)
- return true;
- toBase.Delete (index);
- return !toBase.Has (index, obj);
- }
-
- /// Returns an array of all ids from an object and its prototypes.
- ///
- ///
- /// a JavaScript object
- ///
- /// an array of all ids from all object in the prototype chain.
- /// If a given id occurs multiple times in the prototype chain,
- /// it will occur only once in this list.
- ///
- public static object [] GetPropertyIds (IScriptable obj)
- {
- if (obj == null) {
- return ScriptRuntime.EmptyArgs;
- }
- object [] result = obj.GetIds ();
- ObjToIntMap map = null;
- for (; ; ) {
- obj = obj.GetPrototype ();
- if (obj == null) {
- break;
- }
- object [] ids = obj.GetIds ();
- if (ids.Length == 0) {
- continue;
- }
- if (map == null) {
- if (result.Length == 0) {
- result = ids;
- continue;
- }
- map = new ObjToIntMap (result.Length + ids.Length);
- for (int i = 0; i != result.Length; ++i) {
- map.intern (result [i]);
- }
- result = null; // Allow to GC the result
- }
- for (int i = 0; i != ids.Length; ++i) {
- map.intern (ids [i]);
- }
- }
- if (map != null) {
- result = map.getKeys ();
- }
- return result;
- }
-
- /// Call a method of an object.
- /// the JavaScript object
- ///
- /// the name of the function property
- ///
- /// the arguments for the call
- ///
- ///
- public static object CallMethod (IScriptable obj, string methodName, object [] args)
- {
- return CallMethod (null, obj, methodName, args);
- }
-
- /// Call a method of an object.
- /// the Context object associated with the current thread.
- ///
- /// the JavaScript object
- ///
- /// the name of the function property
- ///
- /// the arguments for the call
- ///
- public static object CallMethod (Context cx, IScriptable obj, string methodName, object [] args)
- {
- object funObj = GetProperty (obj, methodName);
- if (!(funObj is IFunction)) {
- throw ScriptRuntime.NotFunctionError (obj, methodName);
- }
- IFunction fun = (IFunction)funObj;
- // TODO: What should be the scope when calling funObj?
- // The following favor scope stored in the object on the assumption
- // that is more useful especially under dynamic scope setup.
- // An alternative is to check for dynamic scope flag
- // and use ScriptableObject.getTopLevelScope(fun) if the flag is not
- // set. But that require access to Context and messy code
- // so for now it is not checked.
- IScriptable scope = ScriptableObject.GetTopLevelScope (obj);
- if (cx != null) {
- return fun.Call (cx, scope, obj, args);
- }
- else {
- return Context.Call (null, fun, scope, obj, args);
- }
- }
-
- private static IScriptable GetBase (IScriptable obj, string name)
- {
- do {
- if (obj.Has (name, obj))
- break;
- obj = obj.GetPrototype ();
- }
- while (obj != null);
- return obj;
- }
-
- private static IScriptable GetBase (IScriptable obj, int index)
- {
- do {
- if (obj.Has (index, obj))
- break;
- obj = obj.GetPrototype ();
- }
- while (obj != null);
- return obj;
- }
-
- /// Get arbitrary application-specific value associated with this object.
- /// key object to select particular value.
- ///
- public object GetAssociatedValue (object key)
- {
- Hashtable h = associatedValues;
- if (h == null)
- return null;
- return h [key];
- }
-
- /// Get arbitrary application-specific value associated with the top scope
- /// of the given scope.
- /// The method first calls {@link #getTopLevelScope(Scriptable scope)}
- /// and then searches the prototype chain of the top scope for the first
- /// object containing the associated value with the given key.
- ///
- ///
- /// the starting scope.
- ///
- /// key object to select particular value.
- ///
- public static object GetTopScopeValue (IScriptable scope, object key)
- {
- scope = ScriptableObject.GetTopLevelScope (scope);
- for (; ; ) {
- if (scope is ScriptableObject) {
- ScriptableObject so = (ScriptableObject)scope;
- object value = so.GetAssociatedValue (key);
- if (value != null) {
- return value;
- }
- }
- scope = scope.GetPrototype ();
- if (scope == null) {
- return null;
- }
- }
- }
-
- /// Associate arbitrary application-specific value with this object.
- /// Value can only be associated with the given object and key only once.
- /// The method ignores any subsequent attempts to change the already
- /// associated value.
- /// The associated values are not serilized.
- ///
- /// key object to select particular value.
- ///
- /// the value to associate
- ///
- /// the passed value if the method is called first time for the
- /// given key or old value for any subsequent calls.
- ///
- public object AssociateValue (object key, object value)
- {
- if (value == null)
- throw new ArgumentException ();
- Hashtable h = associatedValues;
- if (h == null) {
- lock (this) {
- h = associatedValues;
- if (h == null) {
- h = Hashtable.Synchronized (new Hashtable ());
- associatedValues = h;
- }
- }
- }
- return InitHash (h, key, value);
- }
-
- private object InitHash (Hashtable h, object key, object initialValue)
- {
- lock (h.SyncRoot) {
- object current = h [key];
- if (current == null) {
- h [key] = initialValue;
- }
- else {
- initialValue = current;
- }
- }
- return initialValue;
- }
-
- private Slot GetNamedSlot (string name)
- {
- // Query last access cache and check that it was not deleted
- Slot slot = lastAccess;
- if ((object)name == (object)slot.stringKey && slot.wasDeleted == 0) {
- return slot;
- }
- int hash = name.GetHashCode ();
- Slot [] slots = this.slots; // Get stable local reference
- int i = GetSlotPosition (slots, name, hash);
- if (i < 0) {
- return null;
- }
- slot = slots [i];
- // Update cache - here stringKey.equals(name) holds, but it can be
- // that slot.stringKey != name. To make last name cache work, need
- // to change the key
- slot.stringKey = name;
- lastAccess = slot;
- return slot;
- }
-
- private Slot GetSlot (string id, int index)
- {
- Slot [] slots = this.slots; // Get local copy
- int i = GetSlotPosition (slots, id, index);
- return (i < 0) ? null : slots [i];
- }
-
- private static int GetSlotPosition (Slot [] slots, string id, int index)
- {
- if (slots != null) {
- int start = (index & 0x7fffffff) % slots.Length;
- int i = start;
- do {
- Slot slot = slots [i];
- if (slot == null)
- break;
- if (slot != REMOVED && slot.intKey == index && ((object)slot.stringKey == (object)id || (id != null && id.Equals (slot.stringKey)))) {
- return i;
- }
- if (++i == slots.Length)
- i = 0;
- }
- while (i != start);
- }
- return -1;
- }
-
- /// Add a new slot to the hash table.
- ///
- /// This method must be synchronized since it is altering the hash
- /// table itself. Note that we search again for the slot to set
- /// since another thread could have added the given property or
- /// caused the table to grow while this thread was searching.
- ///
- private Slot AddSlot (string id, int index, Slot newSlot)
- {
- lock (this) {
- if (Sealed) {
- string str = (id != null) ? id : Convert.ToString (index);
- throw Context.ReportRuntimeErrorById ("msg.add.sealed", str);
- }
-
-
-
- return AddSlotImpl (id, index, newSlot);
- }
- }
-
- // Must be inside synchronized (this)
- private Slot AddSlotImpl (string id, int index, Slot newSlot)
- {
- if (slots == null) {
- slots = new Slot [5];
- }
- int start = (index & 0x7fffffff) % slots.Length;
- int i = start;
- for (; ; ) {
- Slot slot = slots [i];
- if (slot == null || slot == REMOVED) {
- if ((4 * (count + 1)) > (3 * slots.Length)) {
- Grow ();
- return AddSlotImpl (id, index, newSlot);
- }
- slot = (newSlot == null) ? new Slot () : newSlot;
- slot.stringKey = id;
- slot.intKey = index;
- slots [i] = slot;
- count++;
- return slot;
- }
- if (slot.intKey == index && ((object)slot.stringKey == (object)id || (id != null && id.Equals (slot.stringKey)))) {
- return slot;
- }
- if (++i == slots.Length)
- i = 0;
- if (i == start) {
- // slots should never be full or bug in grow code
- throw new ApplicationException ();
- }
- }
- }
-
- /// Remove a slot from the hash table.
- ///
- /// This method must be synchronized since it is altering the hash
- /// table itself. We might be able to optimize this more, but
- /// deletes are not common.
- ///
- private void RemoveSlot (string name, int index)
- {
- lock (this) {
- if (Sealed) {
- string str = (name != null) ? name : Convert.ToString (index);
- throw Context.ReportRuntimeErrorById ("msg.remove.sealed", str);
- }
-
- int i = GetSlotPosition (slots, name, index);
- if (i >= 0) {
- Slot slot = slots [i];
- if ((slot.attributes & PERMANENT) == 0) {
- // Mark the slot as removed to handle a case when
- // another thread manages to put just removed slot
- // into lastAccess cache.
- slot.wasDeleted = (sbyte)1;
- if (slot == lastAccess) {
- lastAccess = REMOVED;
- }
- count--;
- if (count != 0) {
- slots [i] = REMOVED;
- }
- else {
- // With no slots it is OK to mark with null.
- slots [i] = null;
- }
- }
- }
- }
- }
-
- // Grow the hash table to accommodate new entries.
- //
- // Note that by assigning the new array back at the end we
- // can continue reading the array from other threads.
- // Must be inside synchronized (this)
- private void Grow ()
- {
- Slot [] newSlots = new Slot [slots.Length * 2 + 1];
- for (int j = slots.Length - 1; j >= 0; j--) {
- Slot slot = slots [j];
- if (slot == null || slot == REMOVED)
- continue;
- int k = (slot.intKey & 0x7fffffff) % newSlots.Length;
- while (newSlots [k] != null)
- if (++k == newSlots.Length)
- k = 0;
- // The end of the "synchronized" statement will cause the memory
- // writes to be propagated on a multiprocessor machine. We want
- // to make sure that the new table is prepared to be read.
- // TODO: causes the 'this' pointer to be null in calling stack frames
- // on the MS JVM
- //synchronized (slot) { }
- newSlots [k] = slot;
- }
- slots = newSlots;
- }
-
- internal virtual object [] GetIds (bool getAll)
- {
- Slot [] s = slots;
- object [] a = ScriptRuntime.EmptyArgs;
- if (s == null)
- return a;
- int c = 0;
- for (int i = 0; i < s.Length; i++) {
- Slot slot = s [i];
- if (slot == null || slot == REMOVED)
- continue;
- if (getAll || (slot.attributes & DONTENUM) == 0) {
- if (c == 0)
- a = new object [s.Length - i];
- a [c++] = slot.stringKey != null ? (object)slot.stringKey : (int)slot.intKey;
- }
- }
- if (c == a.Length)
- return a;
- object [] result = new object [c];
- Array.Copy (a, 0, result, 0, c);
- return result;
- }
-
-
- /// The prototype of this object.
- private IScriptable prototypeObject;
-
- /// The parent scope of this object.
- private IScriptable parentScopeObject;
-
- private static readonly object HAS_STATIC_ACCESSORS = typeof (void);
- private static readonly Slot REMOVED = new Slot ();
-
-
- private Slot [] slots;
- // If count >= 0, it gives number of keys or if count < 0,
- // it indicates sealed object where -1 - count gives number of keys
- private int count;
-
- // cache; may be removed for smaller memory footprint
-
- private Slot lastAccess = REMOVED;
-
- // associated values are not serialized
-
- private volatile Hashtable associatedValues;
-
- public virtual void DefineSetter (string name, ICallable setter)
- {
- Slot slot = GetSlot (name, name.GetHashCode ());
- if (slot == null) {
- slot = new Slot ();
- AddSlot (name, name.GetHashCode (), slot);
- }
- slot.setter = setter;
- }
-
- public virtual void DefineSetter (int index, ICallable setter)
- {
- Slot slot = GetSlot (null, index);
- if (slot == null) {
- slot = new Slot ();
- AddSlot (null, index, slot);
- }
- slot.setter = setter;
- }
-
- public virtual void DefineGetter (int index, ICallable getter)
- {
- Slot slot = GetSlot (null, index);
- if (slot == null) {
- slot = new Slot ();
- AddSlot (null, index, slot);
- }
- slot.getter = getter;
- }
-
- public virtual void DefineGetter (string name, ICallable getter)
- {
- Slot slot = GetSlot (name, name.GetHashCode ());
- if (slot == null) {
- slot = new Slot ();
- AddSlot (name, name.GetHashCode (), slot);
- }
- slot.getter = getter;
- }
-
- public virtual object LookupGetter (string name)
- {
- Slot slot = GetSlot (name, name.GetHashCode ());
- if (slot == null || slot.getter == null)
- return Undefined.Value;
- return slot.getter;
- }
-
- public virtual object LookupSetter (string name)
- {
- Slot slot = GetSlot (name, name.GetHashCode ());
- if (slot == null || slot.setter == null)
- return Undefined.Value;
- return slot.setter;
- }
-
- private class Slot : ICloneable
- {
-
- internal int intKey;
- internal string stringKey;
- internal object value;
- internal short attributes;
-
- internal sbyte wasDeleted;
-
- internal ICallable getter;
- internal ICallable setter;
-
- public object Clone ()
- {
- Slot clone = new Slot ();
- clone.intKey = intKey;
- clone.stringKey = stringKey;
- clone.value = value;
- clone.attributes = attributes;
- clone.wasDeleted = wasDeleted;
- clone.getter = getter;
- clone.setter = setter;
- return clone;
- }
-
- internal object GetValue (Context cx, IScriptable scope, IScriptable thisObj)
- {
- if (getter == null) {
- return value;
- }
- else {
- if (cx == null)
- cx = Context.CurrentContext;
- return getter.Call (cx, scope, thisObj,
- ScriptRuntime.EmptyArgs);
- }
- }
-
- internal object SetValue (Context cx, IScriptable scope, IScriptable thisObj, object value)
- {
- if (setter == null) {
- if (getter == null) {
- return (this.value = value);
- }
- else {
- throw ScriptRuntime.TypeError ("setting a property that has only a getter");
- }
- }
- else {
- if (cx == null)
- cx = Context.CurrentContext;
- return setter.Call (cx, scope, thisObj, new object [] { value });
- }
- }
-
- }
-
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+// API class
+using System;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Collections;
+
+using EcmaScript.NET.Debugging;
+using EcmaScript.NET.Attributes;
+using EcmaScript.NET.Collections;
+
+namespace EcmaScript.NET
+{
+
+ /// This is the default implementation of the Scriptable interface. This
+ /// class provides convenient default behavior that makes it easier to
+ /// define host objects.
+ ///
+ /// Various properties and methods of JavaScript objects can be conveniently
+ /// defined using methods of ScriptableObject.
+ ///
+ /// Classes extending ScriptableObject must define the getClassName method.
+ ///
+ ///
+ public abstract class ScriptableObject : IScriptable, DebuggableObject
+ {
+ /// Return the name of the class.
+ ///
+ /// This is typically the same name as the constructor.
+ /// Classes extending ScriptableObject must implement this abstract
+ /// method.
+ ///
+ public abstract string ClassName { get;}
+
+
+ /// Returns the parent (enclosing) scope of the object.
+ /// Sets the parent (enclosing) scope of the object.
+ public IScriptable ParentScope
+ {
+ get
+ {
+ return parentScopeObject;
+ }
+
+ set
+ {
+ parentScopeObject = value;
+ }
+
+ }
+ /// Returns an array of ids for the properties of the object.
+ ///
+ /// All properties, even those with attribute DONTENUM, are listed.
+ ///
+ ///
+ /// an array of java.lang.Objects with an entry for every
+ /// listed property. Properties accessed via an integer index will
+ /// have a corresponding
+ /// Integer entry in the returned array. Properties accessed by
+ /// a String will have a String entry in the returned array.
+ ///
+ virtual public object [] AllIds
+ {
+ get
+ {
+ return GetIds (true);
+ }
+
+ }
+ /// Return true if this object is sealed.
+ ///
+ /// It is an error to attempt to add or remove properties to
+ /// a sealed object.
+ ///
+ ///
+ /// true if sealed, false otherwise.
+ ///
+ public bool Sealed
+ {
+ get
+ {
+ return count < 0;
+ }
+
+ }
+
+ /// The empty property attribute.
+ ///
+ /// Used by getAttributes() and setAttributes().
+ ///
+ ///
+ public const int EMPTY = 0x00;
+
+ /// Property attribute indicating assignment to this property is ignored.
+ ///
+ ///
+ public const int READONLY = 0x01;
+
+ /// Property attribute indicating property is not enumerated.
+ ///
+ /// Only enumerated properties will be returned by getIds().
+ ///
+ ///
+ public const int DONTENUM = 0x02;
+
+ /// Property attribute indicating property cannot be deleted.
+ ///
+ ///
+ public const int PERMANENT = 0x04;
+
+ internal static void CheckValidAttributes (int attributes)
+ {
+ const int mask = READONLY | DONTENUM | PERMANENT;
+ if ((attributes & ~mask) != 0) {
+ throw new ArgumentException (Convert.ToString (attributes));
+ }
+ }
+
+ public ScriptableObject ()
+ {
+ }
+
+ public ScriptableObject (IScriptable scope, IScriptable prototype)
+ {
+ if (scope == null)
+ throw new ArgumentException ();
+
+ parentScopeObject = scope;
+ prototypeObject = prototype;
+ }
+
+ /// Returns true if the named property is defined.
+ ///
+ ///
+ /// the name of the property
+ ///
+ /// the object in which the lookup began
+ ///
+ /// true if and only if the property was found in the object
+ ///
+ public virtual bool Has (string name, IScriptable start)
+ {
+ return null != GetNamedSlot (name);
+ }
+
+ /// Returns true if the property index is defined.
+ ///
+ ///
+ /// the numeric index for the property
+ ///
+ /// the object in which the lookup began
+ ///
+ /// true if and only if the property was found in the object
+ ///
+ public virtual bool Has (int index, IScriptable start)
+ {
+ return null != GetSlot (null, index);
+ }
+
+ /// Returns the value of the named property or NOT_FOUND.
+ ///
+ /// If the property was created using defineProperty, the
+ /// appropriate getter method is called.
+ ///
+ ///
+ /// the name of the property
+ ///
+ /// the object in which the lookup began
+ ///
+ /// the value of the property (may be null), or NOT_FOUND
+ ///
+ public virtual object Get (string name, IScriptable start)
+ {
+ Slot slot = GetNamedSlot (name);
+ if (slot == null) {
+ return UniqueTag.NotFound;
+ }
+ return slot.GetValue (null, start, start);
+ }
+
+ /// Returns the value of the indexed property or NOT_FOUND.
+ ///
+ ///
+ /// the numeric index for the property
+ ///
+ /// the object in which the lookup began
+ ///
+ /// the value of the property (may be null), or NOT_FOUND
+ ///
+ public virtual object Get (int index, IScriptable start)
+ {
+ Slot slot = GetSlot (null, index);
+ if (slot == null) {
+ return UniqueTag.NotFound;
+ }
+ return slot.GetValue (null, start, start);
+ }
+
+ /// Sets the value of the named property, creating it if need be.
+ ///
+ /// If the property was created using defineProperty, the
+ /// appropriate setter method is called.
+ ///
+ /// If the property's attributes include READONLY, no action is
+ /// taken.
+ /// This method will actually set the property in the start
+ /// object.
+ ///
+ ///
+ /// the name of the property
+ ///
+ /// the object whose property is being set
+ ///
+ /// value to set the property to
+ ///
+ public virtual object Put (string name, IScriptable start, object value)
+ {
+ Slot slot = lastAccess; // Get local copy
+ if ((object)name != (object)slot.stringKey || slot.wasDeleted != 0) {
+ int hash = name.GetHashCode ();
+ slot = GetSlot (name, hash);
+ if (slot == null) {
+ if (start != this) {
+ start.Put (name, start, value);
+ return value;
+ }
+ slot = AddSlot (name, hash, null);
+ }
+ // Note: cache is not updated in put
+ }
+ if (start == this && Sealed) {
+ throw Context.ReportRuntimeErrorById ("msg.modify.sealed", name);
+ }
+ if ((slot.attributes & ScriptableObject.READONLY) != 0) {
+ // FINDME
+ Context cx = Context.CurrentContext;
+ if (cx.Version == Context.Versions.JS1_2) {
+ throw Context.ReportRuntimeErrorById ("msg.read-only", name);
+ } else {
+ if (cx.HasFeature (Context.Features.Strict)) {
+ Context.ReportWarningById ("msg.read-only", name);
+ }
+ }
+ return value;
+ }
+ if (this == start) {
+ return slot.SetValue (null, start, start, value);
+ }
+ else {
+ if (slot.setter != null) {
+ Slot newSlot = (Slot)slot.Clone ();
+ ((ScriptableObject)start).AddSlotImpl (newSlot.stringKey, newSlot.intKey, newSlot);
+ return newSlot.SetValue (null, start, start, value);
+ }
+ else {
+ return start.Put (name, start, value);
+ }
+ }
+ return value;
+ }
+
+ /// Sets the value of the indexed property, creating it if need be.
+ ///
+ ///
+ /// the numeric index for the property
+ ///
+ /// the object whose property is being set
+ ///
+ /// value to set the property to
+ ///
+ public virtual object Put (int index, IScriptable start, object value)
+ {
+ Slot slot = GetSlot (null, index);
+ if (slot == null) {
+ if (start != this) {
+ return start.Put (index, start, value);
+ }
+ slot = AddSlot (null, index, null);
+ }
+ if (start == this && Sealed) {
+ throw Context.ReportRuntimeErrorById ("msg.modify.sealed", Convert.ToString (index));
+ }
+ if ((slot.attributes & ScriptableObject.READONLY) != 0) {
+ return slot.GetValue (null, start, start); // TODO: ???
+ }
+ if (this == start) {
+ return slot.SetValue (null, start, start, value);
+ }
+ else {
+ return start.Put (index, start, value);
+ }
+ }
+
+ /// Removes a named property from the object.
+ ///
+ /// If the property is not found, or it has the PERMANENT attribute,
+ /// no action is taken.
+ ///
+ ///
+ /// the name of the property
+ ///
+ public virtual void Delete (string name)
+ {
+ RemoveSlot (name, name.GetHashCode ());
+ }
+
+ /// Removes the indexed property from the object.
+ ///
+ /// If the property is not found, or it has the PERMANENT attribute,
+ /// no action is taken.
+ ///
+ ///
+ /// the numeric index for the property
+ ///
+ public virtual void Delete (int index)
+ {
+ RemoveSlot (null, index);
+ }
+
+
+
+
+
+ /// Get the attributes of a named property.
+ ///
+ /// The property is specified by name
+ /// as defined for has.
+ ///
+ ///
+ /// the identifier for the property
+ ///
+ /// the bitset of attributes
+ ///
+ /// EvaluatorException if the named property is not found
+ ///
+ public virtual int GetAttributes (string name)
+ {
+ Slot slot = GetNamedSlot (name);
+ if (slot == null) {
+ throw Context.ReportRuntimeErrorById ("msg.prop.not.found", name);
+ }
+ return slot.attributes;
+ }
+
+ /// Get the attributes of an indexed property.
+ ///
+ ///
+ /// the numeric index for the property
+ ///
+ /// EvaluatorException if the named property is not found
+ /// is not found
+ ///
+ /// the bitset of attributes
+ ///
+ public virtual int GetAttributes (int index)
+ {
+ Slot slot = GetSlot (null, index);
+ if (slot == null) {
+ throw Context.ReportRuntimeErrorById ("msg.prop.not.found", Convert.ToString (index));
+ }
+ return slot.attributes;
+ }
+
+ /// Set the attributes of a named property.
+ ///
+ /// The property is specified by name
+ /// as defined for has.
+ ///
+ /// The possible attributes are READONLY, DONTENUM,
+ /// and PERMANENT. Combinations of attributes
+ /// are expressed by the bitwise OR of attributes.
+ /// EMPTY is the state of no attributes set. Any unused
+ /// bits are reserved for future use.
+ ///
+ ///
+ /// the name of the property
+ ///
+ /// the bitset of attributes
+ ///
+ /// EvaluatorException if the named property is not found
+ ///
+ public virtual void SetAttributes (string name, int attributes)
+ {
+ CheckValidAttributes (attributes);
+ Slot slot = GetNamedSlot (name);
+ if (slot == null) {
+ throw Context.ReportRuntimeErrorById ("msg.prop.not.found", name);
+ }
+ slot.attributes = (short)attributes;
+ }
+
+ /// Set the attributes of an indexed property.
+ ///
+ ///
+ /// the numeric index for the property
+ ///
+ /// the bitset of attributes
+ ///
+ /// EvaluatorException if the named property is not found
+ ///
+ public virtual void SetAttributes (int index, int attributes)
+ {
+ CheckValidAttributes (attributes);
+ Slot slot = GetSlot (null, index);
+ if (slot == null) {
+ throw Context.ReportRuntimeErrorById ("msg.prop.not.found", Convert.ToString (index));
+ }
+ slot.attributes = (short)attributes;
+ }
+
+ /// Returns the prototype of the object.
+ public virtual IScriptable GetPrototype ()
+ {
+ return prototypeObject;
+ }
+
+ /// Sets the prototype of the object.
+ public virtual void SetPrototype (IScriptable m)
+ {
+ prototypeObject = m;
+ }
+
+ /// Returns an array of ids for the properties of the object.
+ ///
+ /// Any properties with the attribute DONTENUM are not listed.
+ ///
+ ///
+ /// an array of java.lang.Objects with an entry for every
+ /// listed property. Properties accessed via an integer index will
+ /// have a corresponding
+ /// Integer entry in the returned array. Properties accessed by
+ /// a String will have a String entry in the returned array.
+ ///
+ public virtual object [] GetIds ()
+ {
+ return GetIds (false);
+ }
+
+ /// Implements the [[DefaultValue]] internal method.
+ ///
+ /// Note that the toPrimitive conversion is a no-op for
+ /// every type other than Object, for which [[DefaultValue]]
+ /// is called. See ECMA 9.1.
+ ///
+ /// A hint of null means "no hint".
+ ///
+ ///
+ /// the type hint
+ ///
+ /// the default value for the object
+ ///
+ /// See ECMA 8.6.2.6.
+ ///
+ public virtual object GetDefaultValue (Type typeHint)
+ {
+ Context cx = null;
+ for (int i = 0; i < 2; i++) {
+ bool tryToString;
+ if (typeHint == typeof (string)) {
+ tryToString = (i == 0);
+ }
+ else {
+ tryToString = (i == 1);
+ }
+
+ string methodName;
+ object [] args;
+ if (tryToString) {
+ methodName = "toString";
+ args = ScriptRuntime.EmptyArgs;
+ }
+ else {
+ methodName = "valueOf";
+ args = new object [1];
+ string hint;
+ if (typeHint == null) {
+ hint = "undefined";
+ }
+ else if (typeHint == typeof (string)) {
+ hint = "string";
+ }
+ else if (typeHint == typeof (IScriptable)) {
+ hint = "object";
+ }
+ else if (typeHint == typeof (IFunction)) {
+ hint = "function";
+ }
+ else if (typeHint == typeof (bool) || typeHint == typeof (bool)) {
+ hint = "boolean";
+ }
+ else if (CliHelper.IsNumberType (typeHint) || typeHint == typeof (byte) || typeHint == typeof (sbyte)) {
+ hint = "number";
+ }
+ else {
+ throw Context.ReportRuntimeErrorById ("msg.invalid.type", typeHint.ToString ());
+ }
+ args [0] = hint;
+ }
+ object v = GetProperty (this, methodName);
+ if (!(v is IFunction))
+ continue;
+ IFunction fun = (IFunction)v;
+ if (cx == null)
+ cx = Context.CurrentContext;
+ v = fun.Call (cx, fun.ParentScope, this, args);
+ if (v != null) {
+ if (!(v is IScriptable)) {
+ return v;
+ }
+ if (typeHint == typeof (IScriptable) || typeHint == typeof (IFunction)) {
+ return v;
+ }
+ if (tryToString && v is Wrapper) {
+ // Let a wrapped java.lang.String pass for a primitive
+ // string.
+ object u = ((Wrapper)v).Unwrap ();
+ if (u is string)
+ return u;
+ }
+ }
+ }
+ // fall through to error
+ string arg = (typeHint == null) ? "undefined" : typeHint.FullName;
+ throw ScriptRuntime.TypeErrorById ("msg.default.value", arg);
+ }
+
+ /// Implements the instanceof operator.
+ ///
+ /// This operator has been proposed to ECMA.
+ ///
+ ///
+ /// The value that appeared on the LHS of the instanceof
+ /// operator
+ ///
+ /// true if "this" appears in value's prototype chain
+ ///
+ ///
+ public virtual bool HasInstance (IScriptable instance)
+ {
+
+ // According to specs -- section 11.8.6 of ECMA-262 -- instanceof operator
+ // on objects NOT implementing [[HasInstance]] internal method should
+ // throw a TypeError exception. Hence, in the following script the
+ // catch block must get executed, (since Math object does not implement
+ // [[HasInstance]] method).
+ throw ScriptRuntime.TypeError ("msg.bad.instanceof.rhs");
+
+
+ // Default for JS objects (other than Function) is to do prototype
+ // chasing. This will be overridden in NativeFunction and non-JS
+ // objects.
+ //return ScriptRuntime.jsDelegatesTo(instance, this);
+ }
+
+ /// Custom == operator.
+ /// Must return {@link Scriptable#NOT_FOUND} if this object does not
+ /// have custom equality operator for the given value,
+ /// Boolean.TRUE if this object is equivalent to value,
+ /// Boolean.FALSE if this object is not equivalent to
+ /// value.
+ ///
+ /// The default implementation returns Boolean.TRUE
+ /// if this == value or {@link Scriptable#NOT_FOUND} otherwise.
+ /// It indicates that by default custom equality is available only if
+ /// value is this in which case true is returned.
+ ///
+ protected internal virtual object EquivalentValues (object value)
+ {
+ return (this == value) ? (object)true : UniqueTag.NotFound;
+ }
+
+ /// Define a JavaScript property.
+ ///
+ /// Creates the property with an initial value and sets its attributes.
+ ///
+ ///
+ /// the name of the property to define.
+ ///
+ /// the initial value of the property
+ ///
+ /// the attributes of the JavaScript property
+ ///
+ public virtual void DefineProperty (string propertyName, object value, int attributes)
+ {
+ Put (propertyName, this, value);
+ SetAttributes (propertyName, attributes);
+ }
+
+ /// Utility method to add properties to arbitrary Scriptable object.
+ /// If destination is instance of ScriptableObject, calls
+ /// defineProperty there, otherwise calls put in destination
+ /// ignoring attributes
+ ///
+ public static void DefineProperty (IScriptable destination, string propertyName, object value, int attributes)
+ {
+ if (!(destination is ScriptableObject)) {
+ destination.Put (propertyName, destination, value);
+ return;
+ }
+ ScriptableObject so = (ScriptableObject)destination;
+ so.DefineProperty (propertyName, value, attributes);
+ }
+
+
+
+ /// Get the Object.prototype property.
+ /// See ECMA 15.2.4.
+ ///
+ public static IScriptable GetObjectPrototype (IScriptable scope)
+ {
+ return getClassPrototype (scope, "Object");
+ }
+
+ /// Get the Function.prototype property.
+ /// See ECMA 15.3.4.
+ ///
+ public static IScriptable GetFunctionPrototype (IScriptable scope)
+ {
+ return getClassPrototype (scope, "Function");
+ }
+
+ /// Get the prototype for the named class.
+ ///
+ /// For example, getClassPrototype(s, "Date") will first
+ /// walk up the parent chain to find the outermost scope, then will
+ /// search that scope for the Date constructor, and then will
+ /// return Date.prototype. If any of the lookups fail, or
+ /// the prototype is not a JavaScript object, then null will
+ /// be returned.
+ ///
+ ///
+ /// an object in the scope chain
+ ///
+ /// the name of the constructor
+ ///
+ /// the prototype for the named class, or null if it
+ /// cannot be found.
+ ///
+ public static IScriptable getClassPrototype (IScriptable scope, string className)
+ {
+ scope = GetTopLevelScope (scope);
+ object ctor = GetProperty (scope, className);
+ object proto;
+ if (ctor is BaseFunction) {
+ proto = ((BaseFunction)ctor).PrototypeProperty;
+ }
+ else if (ctor is IScriptable) {
+ IScriptable ctorObj = (IScriptable)ctor;
+ proto = ctorObj.Get ("prototype", ctorObj);
+ }
+ else {
+ return null;
+ }
+ if (proto is IScriptable) {
+ return (IScriptable)proto;
+ }
+ return null;
+ }
+
+ /// Get the global scope.
+ ///
+ /// Walks the parent scope chain to find an object with a null
+ /// parent scope (the global object).
+ ///
+ ///
+ /// a JavaScript object
+ ///
+ /// the corresponding global scope
+ ///
+ public static IScriptable GetTopLevelScope (IScriptable obj)
+ {
+ for (; ; ) {
+ IScriptable parent = obj.ParentScope;
+ if (parent == null) {
+ return obj;
+ }
+ obj = parent;
+ }
+ }
+
+ /// Seal this object.
+ ///
+ /// A sealed object may not have properties added or removed. Once
+ /// an object is sealed it may not be unsealed.
+ ///
+ ///
+ public virtual void SealObject ()
+ {
+ lock (this) {
+ if (count >= 0) {
+ count = -1 - count;
+ }
+ }
+ }
+
+ /// Gets a named property from an object or any object in its prototype chain.
+ ///
+ /// Searches the prototype chain for a property named name.
+ ///
+ ///
+ /// a JavaScript object
+ ///
+ /// a property name
+ ///
+ /// the value of a property with name name found in
+ /// obj or any object in its prototype chain, or
+ /// Scriptable.NOT_FOUND if not found
+ ///
+ public static object GetProperty (IScriptable obj, string name)
+ {
+ IScriptable start = obj;
+ object result;
+ do {
+ result = obj.Get (name, start);
+ if (result != UniqueTag.NotFound)
+ break;
+ obj = obj.GetPrototype ();
+ }
+ while (obj != null);
+ return result;
+ }
+
+ /// Gets an indexed property from an object or any object in its prototype chain.
+ ///
+ /// Searches the prototype chain for a property with integral index
+ /// index. Note that if you wish to look for properties with numerical
+ /// but non-integral indicies, you should use getProperty(Scriptable,String) with
+ /// the string value of the index.
+ ///
+ ///
+ /// a JavaScript object
+ ///
+ /// an integral index
+ ///
+ /// the value of a property with index index found in
+ /// obj or any object in its prototype chain, or
+ /// Scriptable.NOT_FOUND if not found
+ ///
+ public static object GetProperty (IScriptable obj, int index)
+ {
+ IScriptable start = obj;
+ object result;
+ do {
+ result = obj.Get (index, start);
+ if (result != UniqueTag.NotFound)
+ break;
+ obj = obj.GetPrototype ();
+ }
+ while (obj != null);
+ return result;
+ }
+
+ /// Returns whether a named property is defined in an object or any object
+ /// in its prototype chain.
+ ///
+ /// Searches the prototype chain for a property named name.
+ ///
+ ///
+ /// a JavaScript object
+ ///
+ /// a property name
+ ///
+ /// the true if property was found
+ ///
+ public static bool HasProperty (IScriptable obj, string name)
+ {
+ return null != GetBase (obj, name);
+ }
+
+ /// Returns whether an indexed property is defined in an object or any object
+ /// in its prototype chain.
+ ///
+ /// Searches the prototype chain for a property with index index.
+ ///
+ ///
+ /// a JavaScript object
+ ///
+ /// a property index
+ ///
+ /// the true if property was found
+ ///
+ public static bool HasProperty (IScriptable obj, int index)
+ {
+ return null != GetBase (obj, index);
+ }
+
+ /// Puts a named property in an object or in an object in its prototype chain.
+ ///
+ /// Seaches for the named property in the prototype chain. If it is found,
+ /// the value of the property is changed. If it is not found, a new
+ /// property is added in obj.
+ ///
+ /// a JavaScript object
+ ///
+ /// a property name
+ ///
+ /// any JavaScript value accepted by Scriptable.put
+ ///
+ public static object PutProperty (IScriptable obj, string name, object value)
+ {
+ IScriptable toBase = GetBase (obj, name);
+ if (toBase == null)
+ toBase = obj;
+ return toBase.Put (name, obj, value);
+ }
+
+ /// Puts an indexed property in an object or in an object in its prototype chain.
+ ///
+ /// Seaches for the indexed property in the prototype chain. If it is found,
+ /// the value of the property is changed. If it is not found, a new
+ /// property is added in obj.
+ ///
+ /// a JavaScript object
+ ///
+ /// a property index
+ ///
+ /// any JavaScript value accepted by Scriptable.put
+ ///
+ public static object PutProperty (IScriptable obj, int index, object value)
+ {
+ IScriptable toBase = GetBase (obj, index);
+ if (toBase == null)
+ toBase = obj;
+ return toBase.Put (index, obj, value);
+ }
+
+ /// Removes the property from an object or its prototype chain.
+ ///
+ /// Searches for a property with name in obj or
+ /// its prototype chain. If it is found, the object's delete
+ /// method is called.
+ ///
+ /// a JavaScript object
+ ///
+ /// a property name
+ ///
+ /// true if the property doesn't exist or was successfully removed
+ ///
+ public static bool DeleteProperty (IScriptable obj, string name)
+ {
+ IScriptable toBase = GetBase (obj, name);
+ if (toBase == null)
+ return true;
+ toBase.Delete (name);
+ return !toBase.Has (name, obj);
+ }
+
+ /// Removes the property from an object or its prototype chain.
+ ///
+ /// Searches for a property with index in obj or
+ /// its prototype chain. If it is found, the object's delete
+ /// method is called.
+ ///
+ /// a JavaScript object
+ ///
+ /// a property index
+ ///
+ /// true if the property doesn't exist or was successfully removed
+ ///
+ public static bool DeleteProperty (IScriptable obj, int index)
+ {
+ IScriptable toBase = GetBase (obj, index);
+ if (toBase == null)
+ return true;
+ toBase.Delete (index);
+ return !toBase.Has (index, obj);
+ }
+
+ /// Returns an array of all ids from an object and its prototypes.
+ ///
+ ///
+ /// a JavaScript object
+ ///
+ /// an array of all ids from all object in the prototype chain.
+ /// If a given id occurs multiple times in the prototype chain,
+ /// it will occur only once in this list.
+ ///
+ public static object [] GetPropertyIds (IScriptable obj)
+ {
+ if (obj == null) {
+ return ScriptRuntime.EmptyArgs;
+ }
+ object [] result = obj.GetIds ();
+ ObjToIntMap map = null;
+ for (; ; ) {
+ obj = obj.GetPrototype ();
+ if (obj == null) {
+ break;
+ }
+ object [] ids = obj.GetIds ();
+ if (ids.Length == 0) {
+ continue;
+ }
+ if (map == null) {
+ if (result.Length == 0) {
+ result = ids;
+ continue;
+ }
+ map = new ObjToIntMap (result.Length + ids.Length);
+ for (int i = 0; i != result.Length; ++i) {
+ map.intern (result [i]);
+ }
+ result = null; // Allow to GC the result
+ }
+ for (int i = 0; i != ids.Length; ++i) {
+ map.intern (ids [i]);
+ }
+ }
+ if (map != null) {
+ result = map.getKeys ();
+ }
+ return result;
+ }
+
+ /// Call a method of an object.
+ /// the JavaScript object
+ ///
+ /// the name of the function property
+ ///
+ /// the arguments for the call
+ ///
+ ///
+ public static object CallMethod (IScriptable obj, string methodName, object [] args)
+ {
+ return CallMethod (null, obj, methodName, args);
+ }
+
+ /// Call a method of an object.
+ /// the Context object associated with the current thread.
+ ///
+ /// the JavaScript object
+ ///
+ /// the name of the function property
+ ///
+ /// the arguments for the call
+ ///
+ public static object CallMethod (Context cx, IScriptable obj, string methodName, object [] args)
+ {
+ object funObj = GetProperty (obj, methodName);
+ if (!(funObj is IFunction)) {
+ throw ScriptRuntime.NotFunctionError (obj, methodName);
+ }
+ IFunction fun = (IFunction)funObj;
+ // TODO: What should be the scope when calling funObj?
+ // The following favor scope stored in the object on the assumption
+ // that is more useful especially under dynamic scope setup.
+ // An alternative is to check for dynamic scope flag
+ // and use ScriptableObject.getTopLevelScope(fun) if the flag is not
+ // set. But that require access to Context and messy code
+ // so for now it is not checked.
+ IScriptable scope = ScriptableObject.GetTopLevelScope (obj);
+ if (cx != null) {
+ return fun.Call (cx, scope, obj, args);
+ }
+ else {
+ return Context.Call (null, fun, scope, obj, args);
+ }
+ }
+
+ private static IScriptable GetBase (IScriptable obj, string name)
+ {
+ do {
+ if (obj.Has (name, obj))
+ break;
+ obj = obj.GetPrototype ();
+ }
+ while (obj != null);
+ return obj;
+ }
+
+ private static IScriptable GetBase (IScriptable obj, int index)
+ {
+ do {
+ if (obj.Has (index, obj))
+ break;
+ obj = obj.GetPrototype ();
+ }
+ while (obj != null);
+ return obj;
+ }
+
+ /// Get arbitrary application-specific value associated with this object.
+ /// key object to select particular value.
+ ///
+ public object GetAssociatedValue (object key)
+ {
+ Hashtable h = associatedValues;
+ if (h == null)
+ return null;
+ return h [key];
+ }
+
+ /// Get arbitrary application-specific value associated with the top scope
+ /// of the given scope.
+ /// The method first calls {@link #getTopLevelScope(Scriptable scope)}
+ /// and then searches the prototype chain of the top scope for the first
+ /// object containing the associated value with the given key.
+ ///
+ ///
+ /// the starting scope.
+ ///
+ /// key object to select particular value.
+ ///
+ public static object GetTopScopeValue (IScriptable scope, object key)
+ {
+ scope = ScriptableObject.GetTopLevelScope (scope);
+ for (; ; ) {
+ if (scope is ScriptableObject) {
+ ScriptableObject so = (ScriptableObject)scope;
+ object value = so.GetAssociatedValue (key);
+ if (value != null) {
+ return value;
+ }
+ }
+ scope = scope.GetPrototype ();
+ if (scope == null) {
+ return null;
+ }
+ }
+ }
+
+ /// Associate arbitrary application-specific value with this object.
+ /// Value can only be associated with the given object and key only once.
+ /// The method ignores any subsequent attempts to change the already
+ /// associated value.
+ /// The associated values are not serilized.
+ ///
+ /// key object to select particular value.
+ ///
+ /// the value to associate
+ ///
+ /// the passed value if the method is called first time for the
+ /// given key or old value for any subsequent calls.
+ ///
+ public object AssociateValue (object key, object value)
+ {
+ if (value == null)
+ throw new ArgumentException ();
+ Hashtable h = associatedValues;
+ if (h == null) {
+ lock (this) {
+ h = associatedValues;
+ if (h == null) {
+ h = Hashtable.Synchronized (new Hashtable ());
+ associatedValues = h;
+ }
+ }
+ }
+ return InitHash (h, key, value);
+ }
+
+ private object InitHash (Hashtable h, object key, object initialValue)
+ {
+ lock (h.SyncRoot) {
+ object current = h [key];
+ if (current == null) {
+ h [key] = initialValue;
+ }
+ else {
+ initialValue = current;
+ }
+ }
+ return initialValue;
+ }
+
+ private Slot GetNamedSlot (string name)
+ {
+ // Query last access cache and check that it was not deleted
+ Slot slot = lastAccess;
+ if ((object)name == (object)slot.stringKey && slot.wasDeleted == 0) {
+ return slot;
+ }
+ int hash = name.GetHashCode ();
+ Slot [] slots = this.slots; // Get stable local reference
+ int i = GetSlotPosition (slots, name, hash);
+ if (i < 0) {
+ return null;
+ }
+ slot = slots [i];
+ // Update cache - here stringKey.equals(name) holds, but it can be
+ // that slot.stringKey != name. To make last name cache work, need
+ // to change the key
+ slot.stringKey = name;
+ lastAccess = slot;
+ return slot;
+ }
+
+ private Slot GetSlot (string id, int index)
+ {
+ Slot [] slots = this.slots; // Get local copy
+ int i = GetSlotPosition (slots, id, index);
+ return (i < 0) ? null : slots [i];
+ }
+
+ private static int GetSlotPosition (Slot [] slots, string id, int index)
+ {
+ if (slots != null) {
+ int start = (index & 0x7fffffff) % slots.Length;
+ int i = start;
+ do {
+ Slot slot = slots [i];
+ if (slot == null)
+ break;
+ if (slot != REMOVED && slot.intKey == index && ((object)slot.stringKey == (object)id || (id != null && id.Equals (slot.stringKey)))) {
+ return i;
+ }
+ if (++i == slots.Length)
+ i = 0;
+ }
+ while (i != start);
+ }
+ return -1;
+ }
+
+ /// Add a new slot to the hash table.
+ ///
+ /// This method must be synchronized since it is altering the hash
+ /// table itself. Note that we search again for the slot to set
+ /// since another thread could have added the given property or
+ /// caused the table to grow while this thread was searching.
+ ///
+ private Slot AddSlot (string id, int index, Slot newSlot)
+ {
+ lock (this) {
+ if (Sealed) {
+ string str = (id != null) ? id : Convert.ToString (index);
+ throw Context.ReportRuntimeErrorById ("msg.add.sealed", str);
+ }
+
+
+
+ return AddSlotImpl (id, index, newSlot);
+ }
+ }
+
+ // Must be inside synchronized (this)
+ private Slot AddSlotImpl (string id, int index, Slot newSlot)
+ {
+ if (slots == null) {
+ slots = new Slot [5];
+ }
+ int start = (index & 0x7fffffff) % slots.Length;
+ int i = start;
+ for (; ; ) {
+ Slot slot = slots [i];
+ if (slot == null || slot == REMOVED) {
+ if ((4 * (count + 1)) > (3 * slots.Length)) {
+ Grow ();
+ return AddSlotImpl (id, index, newSlot);
+ }
+ slot = (newSlot == null) ? new Slot () : newSlot;
+ slot.stringKey = id;
+ slot.intKey = index;
+ slots [i] = slot;
+ count++;
+ return slot;
+ }
+ if (slot.intKey == index && ((object)slot.stringKey == (object)id || (id != null && id.Equals (slot.stringKey)))) {
+ return slot;
+ }
+ if (++i == slots.Length)
+ i = 0;
+ if (i == start) {
+ // slots should never be full or bug in grow code
+ throw new Exception ();
+ }
+ }
+ }
+
+ /// Remove a slot from the hash table.
+ ///
+ /// This method must be synchronized since it is altering the hash
+ /// table itself. We might be able to optimize this more, but
+ /// deletes are not common.
+ ///
+ private void RemoveSlot (string name, int index)
+ {
+ lock (this) {
+ if (Sealed) {
+ string str = (name != null) ? name : Convert.ToString (index);
+ throw Context.ReportRuntimeErrorById ("msg.remove.sealed", str);
+ }
+
+ int i = GetSlotPosition (slots, name, index);
+ if (i >= 0) {
+ Slot slot = slots [i];
+ if ((slot.attributes & PERMANENT) == 0) {
+ // Mark the slot as removed to handle a case when
+ // another thread manages to put just removed slot
+ // into lastAccess cache.
+ slot.wasDeleted = (sbyte)1;
+ if (slot == lastAccess) {
+ lastAccess = REMOVED;
+ }
+ count--;
+ if (count != 0) {
+ slots [i] = REMOVED;
+ }
+ else {
+ // With no slots it is OK to mark with null.
+ slots [i] = null;
+ }
+ }
+ }
+ }
+ }
+
+ // Grow the hash table to accommodate new entries.
+ //
+ // Note that by assigning the new array back at the end we
+ // can continue reading the array from other threads.
+ // Must be inside synchronized (this)
+ private void Grow ()
+ {
+ Slot [] newSlots = new Slot [slots.Length * 2 + 1];
+ for (int j = slots.Length - 1; j >= 0; j--) {
+ Slot slot = slots [j];
+ if (slot == null || slot == REMOVED)
+ continue;
+ int k = (slot.intKey & 0x7fffffff) % newSlots.Length;
+ while (newSlots [k] != null)
+ if (++k == newSlots.Length)
+ k = 0;
+ // The end of the "synchronized" statement will cause the memory
+ // writes to be propagated on a multiprocessor machine. We want
+ // to make sure that the new table is prepared to be read.
+ // TODO: causes the 'this' pointer to be null in calling stack frames
+ // on the MS JVM
+ //synchronized (slot) { }
+ newSlots [k] = slot;
+ }
+ slots = newSlots;
+ }
+
+ internal virtual object [] GetIds (bool getAll)
+ {
+ Slot [] s = slots;
+ object [] a = ScriptRuntime.EmptyArgs;
+ if (s == null)
+ return a;
+ int c = 0;
+ for (int i = 0; i < s.Length; i++) {
+ Slot slot = s [i];
+ if (slot == null || slot == REMOVED)
+ continue;
+ if (getAll || (slot.attributes & DONTENUM) == 0) {
+ if (c == 0)
+ a = new object [s.Length - i];
+ a [c++] = slot.stringKey != null ? (object)slot.stringKey : (int)slot.intKey;
+ }
+ }
+ if (c == a.Length)
+ return a;
+ object [] result = new object [c];
+ Array.Copy (a, 0, result, 0, c);
+ return result;
+ }
+
+
+ /// The prototype of this object.
+ private IScriptable prototypeObject;
+
+ /// The parent scope of this object.
+ private IScriptable parentScopeObject;
+
+ private static readonly object HAS_STATIC_ACCESSORS = typeof (void);
+ private static readonly Slot REMOVED = new Slot ();
+
+
+ private Slot [] slots;
+ // If count >= 0, it gives number of keys or if count < 0,
+ // it indicates sealed object where -1 - count gives number of keys
+ private int count;
+
+ // cache; may be removed for smaller memory footprint
+
+ private Slot lastAccess = REMOVED;
+
+ // associated values are not serialized
+
+ private volatile Hashtable associatedValues;
+
+ public virtual void DefineSetter (string name, ICallable setter)
+ {
+ Slot slot = GetSlot (name, name.GetHashCode ());
+ if (slot == null) {
+ slot = new Slot ();
+ AddSlot (name, name.GetHashCode (), slot);
+ }
+ slot.setter = setter;
+ }
+
+ public virtual void DefineSetter (int index, ICallable setter)
+ {
+ Slot slot = GetSlot (null, index);
+ if (slot == null) {
+ slot = new Slot ();
+ AddSlot (null, index, slot);
+ }
+ slot.setter = setter;
+ }
+
+ public virtual void DefineGetter (int index, ICallable getter)
+ {
+ Slot slot = GetSlot (null, index);
+ if (slot == null) {
+ slot = new Slot ();
+ AddSlot (null, index, slot);
+ }
+ slot.getter = getter;
+ }
+
+ public virtual void DefineGetter (string name, ICallable getter)
+ {
+ Slot slot = GetSlot (name, name.GetHashCode ());
+ if (slot == null) {
+ slot = new Slot ();
+ AddSlot (name, name.GetHashCode (), slot);
+ }
+ slot.getter = getter;
+ }
+
+ public virtual object LookupGetter (string name)
+ {
+ Slot slot = GetSlot (name, name.GetHashCode ());
+ if (slot == null || slot.getter == null)
+ return Undefined.Value;
+ return slot.getter;
+ }
+
+ public virtual object LookupSetter (string name)
+ {
+ Slot slot = GetSlot (name, name.GetHashCode ());
+ if (slot == null || slot.setter == null)
+ return Undefined.Value;
+ return slot.setter;
+ }
+
+ private class Slot : ICloneable
+ {
+
+ internal int intKey;
+ internal string stringKey;
+ internal object value;
+ internal short attributes;
+
+ internal sbyte wasDeleted;
+
+ internal ICallable getter;
+ internal ICallable setter;
+
+ public object Clone ()
+ {
+ Slot clone = new Slot ();
+ clone.intKey = intKey;
+ clone.stringKey = stringKey;
+ clone.value = value;
+ clone.attributes = attributes;
+ clone.wasDeleted = wasDeleted;
+ clone.getter = getter;
+ clone.setter = setter;
+ return clone;
+ }
+
+ internal object GetValue (Context cx, IScriptable scope, IScriptable thisObj)
+ {
+ if (getter == null) {
+ return value;
+ }
+ else {
+ if (cx == null)
+ cx = Context.CurrentContext;
+ return getter.Call (cx, scope, thisObj,
+ ScriptRuntime.EmptyArgs);
+ }
+ }
+
+ internal object SetValue (Context cx, IScriptable scope, IScriptable thisObj, object value)
+ {
+ if (setter == null) {
+ if (getter == null) {
+ return (this.value = value);
+ }
+ else {
+ throw ScriptRuntime.TypeError ("setting a property that has only a getter");
+ }
+ }
+ else {
+ if (cx == null)
+ cx = Context.CurrentContext;
+ return setter.Call (cx, scope, thisObj, new object [] { value });
+ }
+ }
+
+ }
+
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/SecurityController.cs b/src/EcmaScript.NET/SecurityController.cs
similarity index 97%
rename from Code/EcmaScript.NET/SecurityController.cs
rename to src/EcmaScript.NET/SecurityController.cs
index ad30598..0653587 100644
--- a/Code/EcmaScript.NET/SecurityController.cs
+++ b/src/EcmaScript.NET/SecurityController.cs
@@ -1,137 +1,137 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-namespace EcmaScript.NET
-{
-
- /// This class describes the support needed to implement security.
- ///
- /// Three main pieces of functionality are required to implement
- /// security for JavaScript. First, it must be possible to define
- /// classes with an associated security domain. (This security
- /// domain may be any object incorporating notion of access
- /// restrictions that has meaning to an embedding; for a client-side
- /// JavaScript embedding this would typically be
- /// java.security.ProtectionDomain or similar object depending on an
- /// origin URL and/or a digital certificate.)
- /// Next it must be possible to get a security domain object that
- /// allows a particular action only if all security domains
- /// associated with code on the current Java stack allows it. And
- /// finally, it must be possible to execute script code with
- /// associated security domain injected into Java stack.
- ///
- /// These three pieces of functionality are encapsulated in the
- /// SecurityController class.
- ///
- ///
- public abstract class SecurityController
- {
-
- private class AnonymousClassScript : IScript
- {
- public AnonymousClassScript (EcmaScript.NET.ICallable callable, EcmaScript.NET.IScriptable thisObj, object [] args, SecurityController enclosingInstance)
- {
- InitBlock (callable, thisObj, args, enclosingInstance);
- }
- private void InitBlock (EcmaScript.NET.ICallable callable, EcmaScript.NET.IScriptable thisObj, object [] args, SecurityController enclosingInstance)
- {
- this.callable = callable;
- this.thisObj = thisObj;
- this.args = args;
- this.enclosingInstance = enclosingInstance;
- }
-
- private EcmaScript.NET.ICallable callable;
-
- private EcmaScript.NET.IScriptable thisObj;
-
- private object [] args;
- private SecurityController enclosingInstance;
- public SecurityController Enclosing_Instance
- {
- get
- {
- return enclosingInstance;
- }
-
- }
- public virtual object Exec (Context cx, IScriptable scope)
- {
- return callable.Call (cx, scope, thisObj, args);
- }
- }
- private static SecurityController m_Global;
-
- // The method must NOT be public or protected
- internal static SecurityController Global
- {
- get
- {
- return m_Global;
- }
- }
-
- /// Check if global {@link SecurityController} was already installed.
- public static bool HasGlobal ()
- {
- return m_Global != null;
- }
-
- /// Initialize global controller that will be used for all
- /// security-related operations. The global controller takes precedence
- /// over already installed {@link Context}-specific controllers and cause
- /// any subsequent call to
- /// {@link Context#setSecurityController(SecurityController)}
- /// to throw an exception.
- ///
- /// The method can only be called once.
- ///
- ///
- public static void initGlobal (SecurityController controller)
- {
- if (controller == null)
- throw new ArgumentException ();
- if (m_Global != null) {
- throw new System.Security.SecurityException ("Cannot overwrite already installed global SecurityController");
- }
- m_Global = controller;
- }
-
-
- /// Get dynamic security domain that allows an action only if it is allowed
- /// by the current Java stack and securityDomain. If
- /// securityDomain is null, return domain representing permissions
- /// allowed by the current stack.
- ///
- public abstract object getDynamicSecurityDomain (object securityDomain);
-
- /// Call {@link
- /// Callable#call(Context cx, Scriptable scope, Scriptable thisObj,
- /// Object[] args)}
- /// of callable under restricted security domain where an action is
- /// allowed only if it is allowed according to the Java stack on the
- /// moment of the execWithDomain call and securityDomain.
- /// Any call to {@link #getDynamicSecurityDomain(Object)} during
- /// execution of callable.call(cx, scope, thisObj, args)
- /// should return a domain incorporate restrictions imposed by
- /// securityDomain and Java stack on the moment of callWithDomain
- /// invocation.
- ///
- ///
- public abstract object callWithDomain (object securityDomain, Context cx, ICallable callable, IScriptable scope, IScriptable thisObj, object [] args);
-
-
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+namespace EcmaScript.NET
+{
+
+ /// This class describes the support needed to implement security.
+ ///
+ /// Three main pieces of functionality are required to implement
+ /// security for JavaScript. First, it must be possible to define
+ /// classes with an associated security domain. (This security
+ /// domain may be any object incorporating notion of access
+ /// restrictions that has meaning to an embedding; for a client-side
+ /// JavaScript embedding this would typically be
+ /// java.security.ProtectionDomain or similar object depending on an
+ /// origin URL and/or a digital certificate.)
+ /// Next it must be possible to get a security domain object that
+ /// allows a particular action only if all security domains
+ /// associated with code on the current Java stack allows it. And
+ /// finally, it must be possible to execute script code with
+ /// associated security domain injected into Java stack.
+ ///
+ /// These three pieces of functionality are encapsulated in the
+ /// SecurityController class.
+ ///
+ ///
+ public abstract class SecurityController
+ {
+
+ private class AnonymousClassScript : IScript
+ {
+ public AnonymousClassScript (EcmaScript.NET.ICallable callable, EcmaScript.NET.IScriptable thisObj, object [] args, SecurityController enclosingInstance)
+ {
+ InitBlock (callable, thisObj, args, enclosingInstance);
+ }
+ private void InitBlock (EcmaScript.NET.ICallable callable, EcmaScript.NET.IScriptable thisObj, object [] args, SecurityController enclosingInstance)
+ {
+ this.callable = callable;
+ this.thisObj = thisObj;
+ this.args = args;
+ this.enclosingInstance = enclosingInstance;
+ }
+
+ private EcmaScript.NET.ICallable callable;
+
+ private EcmaScript.NET.IScriptable thisObj;
+
+ private object [] args;
+ private SecurityController enclosingInstance;
+ public SecurityController Enclosing_Instance
+ {
+ get
+ {
+ return enclosingInstance;
+ }
+
+ }
+ public virtual object Exec (Context cx, IScriptable scope)
+ {
+ return callable.Call (cx, scope, thisObj, args);
+ }
+ }
+ private static SecurityController m_Global;
+
+ // The method must NOT be public or protected
+ internal static SecurityController Global
+ {
+ get
+ {
+ return m_Global;
+ }
+ }
+
+ /// Check if global {@link SecurityController} was already installed.
+ public static bool HasGlobal ()
+ {
+ return m_Global != null;
+ }
+
+ /// Initialize global controller that will be used for all
+ /// security-related operations. The global controller takes precedence
+ /// over already installed {@link Context}-specific controllers and cause
+ /// any subsequent call to
+ /// {@link Context#setSecurityController(SecurityController)}
+ /// to throw an exception.
+ ///
+ /// The method can only be called once.
+ ///
+ ///
+ public static void initGlobal (SecurityController controller)
+ {
+ if (controller == null)
+ throw new ArgumentException ();
+ if (m_Global != null) {
+ throw new System.Security.SecurityException ("Cannot overwrite already installed global SecurityController");
+ }
+ m_Global = controller;
+ }
+
+
+ /// Get dynamic security domain that allows an action only if it is allowed
+ /// by the current Java stack and securityDomain. If
+ /// securityDomain is null, return domain representing permissions
+ /// allowed by the current stack.
+ ///
+ public abstract object getDynamicSecurityDomain (object securityDomain);
+
+ /// Call {@link
+ /// Callable#call(Context cx, Scriptable scope, Scriptable thisObj,
+ /// Object[] args)}
+ /// of callable under restricted security domain where an action is
+ /// allowed only if it is allowed according to the Java stack on the
+ /// moment of the execWithDomain call and securityDomain.
+ /// Any call to {@link #getDynamicSecurityDomain(Object)} during
+ /// execution of callable.call(cx, scope, thisObj, args)
+ /// should return a domain incorporate restrictions imposed by
+ /// securityDomain and Java stack on the moment of callWithDomain
+ /// invocation.
+ ///
+ ///
+ public abstract object callWithDomain (object securityDomain, Context cx, ICallable callable, IScriptable scope, IScriptable thisObj, object [] args);
+
+
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/SpecialRef.cs b/src/EcmaScript.NET/SpecialRef.cs
similarity index 96%
rename from Code/EcmaScript.NET/SpecialRef.cs
rename to src/EcmaScript.NET/SpecialRef.cs
index e75be75..5809841 100644
--- a/Code/EcmaScript.NET/SpecialRef.cs
+++ b/src/EcmaScript.NET/SpecialRef.cs
@@ -1,145 +1,145 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-namespace EcmaScript.NET
-{
-
- class SpecialRef : IRef
- {
-
- public enum Types
- {
- None = 0,
- Proto = 1,
- Parent = 2
- }
-
- private IScriptable target;
- private Types type;
- private string name;
-
- private SpecialRef (IScriptable target, Types type, string name)
- {
- this.target = target;
- this.type = type;
- this.name = name;
- }
-
- internal static IRef createSpecial (Context cx, object obj, string name)
- {
- IScriptable target = ScriptConvert.ToObjectOrNull (cx, obj);
- if (target == null) {
- throw ScriptRuntime.UndefReadError (obj, name);
- }
-
- Types type;
- if (name.Equals ("__proto__")) {
- type = Types.Proto;
- }
- else if (name.Equals ("__parent__")) {
- type = Types.Parent;
- }
- else {
- throw new ArgumentException (name);
- }
-
- if (!cx.HasFeature (Context.Features.ParentProtoProperties)) {
- // Clear special after checking for valid name!
- type = Types.None;
- }
-
- return new SpecialRef (target, type, name);
- }
-
- public object Get (Context cx)
- {
- switch (type) {
-
- case Types.None:
- return ScriptRuntime.getObjectProp (target, name, cx);
-
- case Types.Proto:
- return target.GetPrototype ();
-
- case Types.Parent:
- return target.ParentScope;
-
- default:
- throw Context.CodeBug ();
-
- }
- }
-
- public object Set (Context cx, object value)
- {
- switch (type) {
-
- case Types.None:
- return ScriptRuntime.setObjectProp (target, name, value, cx);
-
- case Types.Proto:
- case Types.Parent: {
- IScriptable obj = ScriptConvert.ToObjectOrNull (cx, value);
- if (obj != null) {
- // Check that obj does not contain on its prototype/scope
- // chain to prevent cycles
- IScriptable search = obj;
- do {
- if (search == target) {
- throw Context.ReportRuntimeErrorById ("msg.cyclic.value", name);
- }
- if (type == Types.Proto) {
- search = search.GetPrototype ();
- }
- else {
- search = search.ParentScope;
- }
- }
- while (search != null);
- }
- if (type == Types.Proto) {
- target.SetPrototype (obj);
- }
- else {
- target.ParentScope = obj;
- }
- return obj;
- }
-
- default:
- throw Context.CodeBug ();
-
- }
- }
-
- public bool Has (Context cx)
- {
- if (type == Types.None) {
- return ScriptRuntime.hasObjectElem (target, name, cx);
- }
- return true;
- }
-
- public bool Delete (Context cx)
- {
- if (type == Types.None) {
- return ScriptRuntime.deleteObjectElem (target, name, cx);
- }
- return false;
- }
-
- }
-
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+namespace EcmaScript.NET
+{
+
+ class SpecialRef : IRef
+ {
+
+ public enum Types
+ {
+ None = 0,
+ Proto = 1,
+ Parent = 2
+ }
+
+ private IScriptable target;
+ private Types type;
+ private string name;
+
+ private SpecialRef (IScriptable target, Types type, string name)
+ {
+ this.target = target;
+ this.type = type;
+ this.name = name;
+ }
+
+ internal static IRef createSpecial (Context cx, object obj, string name)
+ {
+ IScriptable target = ScriptConvert.ToObjectOrNull (cx, obj);
+ if (target == null) {
+ throw ScriptRuntime.UndefReadError (obj, name);
+ }
+
+ Types type;
+ if (name.Equals ("__proto__")) {
+ type = Types.Proto;
+ }
+ else if (name.Equals ("__parent__")) {
+ type = Types.Parent;
+ }
+ else {
+ throw new ArgumentException (name);
+ }
+
+ if (!cx.HasFeature (Context.Features.ParentProtoProperties)) {
+ // Clear special after checking for valid name!
+ type = Types.None;
+ }
+
+ return new SpecialRef (target, type, name);
+ }
+
+ public object Get (Context cx)
+ {
+ switch (type) {
+
+ case Types.None:
+ return ScriptRuntime.getObjectProp (target, name, cx);
+
+ case Types.Proto:
+ return target.GetPrototype ();
+
+ case Types.Parent:
+ return target.ParentScope;
+
+ default:
+ throw Context.CodeBug ();
+
+ }
+ }
+
+ public object Set (Context cx, object value)
+ {
+ switch (type) {
+
+ case Types.None:
+ return ScriptRuntime.setObjectProp (target, name, value, cx);
+
+ case Types.Proto:
+ case Types.Parent: {
+ IScriptable obj = ScriptConvert.ToObjectOrNull (cx, value);
+ if (obj != null) {
+ // Check that obj does not contain on its prototype/scope
+ // chain to prevent cycles
+ IScriptable search = obj;
+ do {
+ if (search == target) {
+ throw Context.ReportRuntimeErrorById ("msg.cyclic.value", name);
+ }
+ if (type == Types.Proto) {
+ search = search.GetPrototype ();
+ }
+ else {
+ search = search.ParentScope;
+ }
+ }
+ while (search != null);
+ }
+ if (type == Types.Proto) {
+ target.SetPrototype (obj);
+ }
+ else {
+ target.ParentScope = obj;
+ }
+ return obj;
+ }
+
+ default:
+ throw Context.CodeBug ();
+
+ }
+ }
+
+ public bool Has (Context cx)
+ {
+ if (type == Types.None) {
+ return ScriptRuntime.hasObjectElem (target, name, cx);
+ }
+ return true;
+ }
+
+ public bool Delete (Context cx)
+ {
+ if (type == Types.None) {
+ return ScriptRuntime.deleteObjectElem (target, name, cx);
+ }
+ return false;
+ }
+
+ }
+
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/Token.cs b/src/EcmaScript.NET/Token.cs
similarity index 96%
rename from Code/EcmaScript.NET/Token.cs
rename to src/EcmaScript.NET/Token.cs
index 2c6732e..0a4b5b2 100644
--- a/Code/EcmaScript.NET/Token.cs
+++ b/src/EcmaScript.NET/Token.cs
@@ -1,669 +1,669 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-
-namespace EcmaScript.NET
-{
-
- /// This class implements the JavaScript scanner.
- ///
- /// It is based on the C source files jsscan.c and jsscan.h
- /// in the jsref package.
- ///
- ///
- public class Token
- {
-
- // debug flags
- internal static readonly bool printTrees = false; // TODO: make me a preprocessor directive
-
- internal static readonly bool printICode = false; // TODO: make me a preprocessor directive
-
- internal static readonly bool printNames = printTrees || printICode;
-
- ///
- /// Token types.
- ///
- /// These values correspond to JSTokenType values in
- /// jsscan.c.
- ///
- public const int ERROR = -1; /* well-known as the only code < EOF */
- public const int EOF = 0; /* end of file */
- public const int EOL = 1; /* end of line */
- public const int FIRST_BYTECODE_TOKEN = 2;
- public const int ENTERWITH = 2;
- public const int LEAVEWITH = 3;
- public const int RETURN = 4;
- public const int GOTO = 5;
- public const int IFEQ = 6;
- public const int IFNE = 7;
- public const int SETNAME = 8;
- public const int BITOR = 9;
- public const int BITXOR = 10;
- public const int BITAND = 11;
- public const int EQ = 12;
- public const int NE = 13;
- public const int LT = 14;
- public const int LE = 15;
- public const int GT = 16;
- public const int GE = 17;
- public const int LSH = 18;
- public const int RSH = 19;
- public const int URSH = 20;
- public const int ADD = 21;
- public const int SUB = 22;
- public const int MUL = 23;
- public const int DIV = 24;
- public const int MOD = 25;
- public const int NOT = 26;
- public const int BITNOT = 27;
- public const int POS = 28;
- public const int NEG = 29;
- public const int NEW = 30;
- public const int DELPROP = 31;
- public const int TYPEOF = 32;
- public const int GETPROP = 33;
- public const int SETPROP = 34;
- public const int GETELEM = 35;
- public const int SETELEM = 36;
- public const int CALL = 37;
- public const int NAME = 38;
- public const int NUMBER = 39;
- public const int STRING = 40;
- public const int NULL = 41;
- public const int THIS = 42;
- public const int FALSE = 43;
- public const int TRUE = 44;
- public const int SHEQ = 45;
- public const int SHNE = 46;
- public const int REGEXP = 47;
- public const int BINDNAME = 48;
- public const int THROW = 49;
- public const int RETHROW = 50;
- public const int IN = 51;
- public const int INSTANCEOF = 52;
- public const int LOCAL_LOAD = 53;
- public const int GETVAR = 54;
- public const int SETVAR = 55;
- public const int CATCH_SCOPE = 56;
- public const int ENUM_INIT_KEYS = 57;
- public const int ENUM_INIT_VALUES = 58;
- public const int ENUM_NEXT = 59;
- public const int ENUM_ID = 60;
- public const int THISFN = 61;
- public const int RETURN_RESULT = 62;
- public const int ARRAYLIT = 63;
- public const int OBJECTLIT = 64;
- public const int GET_REF = 65;
- public const int SET_REF = 66;
- public const int DEL_REF = 67;
- public const int REF_CALL = 68;
- public const int REF_SPECIAL = 69;
- public const int DEFAULTNAMESPACE = 70;
- public const int ESCXMLATTR = 71;
- public const int ESCXMLTEXT = 72;
- public const int REF_MEMBER = 73;
- public const int REF_NS_MEMBER = 74;
- public const int REF_NAME = 75;
- public const int REF_NS_NAME = 76; // Reference for ns::y, @ns::y@[y] etc.
- public const int SETPROP_GETTER = 77;
- public const int SETPROP_SETTER = 78;
-
- // End of interpreter bytecodes
- public const int LAST_BYTECODE_TOKEN = SETPROP_SETTER;
-
- public const int TRY = LAST_BYTECODE_TOKEN + 1;
- public const int SEMI = LAST_BYTECODE_TOKEN + 2;
- public const int LB = LAST_BYTECODE_TOKEN + 3;
- public const int RB = LAST_BYTECODE_TOKEN + 4;
- public const int LC = LAST_BYTECODE_TOKEN + 5;
- public const int RC = LAST_BYTECODE_TOKEN + 6;
- public const int LP = LAST_BYTECODE_TOKEN + 7;
- public const int RP = LAST_BYTECODE_TOKEN + 8;
- public const int COMMA = LAST_BYTECODE_TOKEN + 9;
- public const int ASSIGN = LAST_BYTECODE_TOKEN + 10;
- public const int ASSIGN_BITOR = LAST_BYTECODE_TOKEN + 11;
- public const int ASSIGN_BITXOR = LAST_BYTECODE_TOKEN + 12;
- public const int ASSIGN_BITAND = LAST_BYTECODE_TOKEN + 13;
- public const int ASSIGN_LSH = LAST_BYTECODE_TOKEN + 14;
- public const int ASSIGN_RSH = LAST_BYTECODE_TOKEN + 15;
- public const int ASSIGN_URSH = LAST_BYTECODE_TOKEN + 16;
- public const int ASSIGN_ADD = LAST_BYTECODE_TOKEN + 17;
- public const int ASSIGN_SUB = LAST_BYTECODE_TOKEN + 18;
- public const int ASSIGN_MUL = LAST_BYTECODE_TOKEN + 19;
- public const int ASSIGN_DIV = LAST_BYTECODE_TOKEN + 20;
- public const int ASSIGN_MOD = LAST_BYTECODE_TOKEN + 21; // %=
-
- public const int FIRST_ASSIGN = ASSIGN;
- public const int LAST_ASSIGN = ASSIGN_MOD;
-
- public const int HOOK = LAST_BYTECODE_TOKEN + 22;
- public const int COLON = LAST_BYTECODE_TOKEN + 23;
- public const int OR = LAST_BYTECODE_TOKEN + 24;
- public const int AND = LAST_BYTECODE_TOKEN + 25;
- public const int INC = LAST_BYTECODE_TOKEN + 26;
- public const int DEC = LAST_BYTECODE_TOKEN + 27;
- public const int DOT = LAST_BYTECODE_TOKEN + 28;
- public const int FUNCTION = LAST_BYTECODE_TOKEN + 29;
- public const int EXPORT = LAST_BYTECODE_TOKEN + 30;
- public const int IMPORT = LAST_BYTECODE_TOKEN + 31;
- public const int IF = LAST_BYTECODE_TOKEN + 32;
- public const int ELSE = LAST_BYTECODE_TOKEN + 33;
- public const int SWITCH = LAST_BYTECODE_TOKEN + 34;
- public const int CASE = LAST_BYTECODE_TOKEN + 35;
- public const int DEFAULT = LAST_BYTECODE_TOKEN + 36;
- public const int WHILE = LAST_BYTECODE_TOKEN + 37;
- public const int DO = LAST_BYTECODE_TOKEN + 38;
- public const int FOR = LAST_BYTECODE_TOKEN + 39;
- public const int BREAK = LAST_BYTECODE_TOKEN + 40;
- public const int CONTINUE = LAST_BYTECODE_TOKEN + 41;
- public const int VAR = LAST_BYTECODE_TOKEN + 42;
- public const int WITH = LAST_BYTECODE_TOKEN + 43;
- public const int CATCH = LAST_BYTECODE_TOKEN + 44;
- public const int FINALLY = LAST_BYTECODE_TOKEN + 45;
- public const int VOID = LAST_BYTECODE_TOKEN + 46;
- public const int RESERVED = LAST_BYTECODE_TOKEN + 47;
- public const int EMPTY = LAST_BYTECODE_TOKEN + 48;
- public const int BLOCK = LAST_BYTECODE_TOKEN + 49;
- public const int LABEL = LAST_BYTECODE_TOKEN + 50;
- public const int TARGET = LAST_BYTECODE_TOKEN + 51;
- public const int LOOP = LAST_BYTECODE_TOKEN + 52;
- public const int EXPR_VOID = LAST_BYTECODE_TOKEN + 53;
- public const int EXPR_RESULT = LAST_BYTECODE_TOKEN + 54;
- public const int JSR = LAST_BYTECODE_TOKEN + 55;
- public const int SCRIPT = LAST_BYTECODE_TOKEN + 56;
- public const int TYPEOFNAME = LAST_BYTECODE_TOKEN + 57;
- public const int USE_STACK = LAST_BYTECODE_TOKEN + 58;
- public const int SETPROP_OP = LAST_BYTECODE_TOKEN + 59;
- public const int SETELEM_OP = LAST_BYTECODE_TOKEN + 60;
- public const int LOCAL_BLOCK = LAST_BYTECODE_TOKEN + 61;
- public const int SET_REF_OP = LAST_BYTECODE_TOKEN + 62;
- public const int DOTDOT = LAST_BYTECODE_TOKEN + 63;
- public const int COLONCOLON = LAST_BYTECODE_TOKEN + 64;
- public const int XML = LAST_BYTECODE_TOKEN + 65;
- public const int DOTQUERY = LAST_BYTECODE_TOKEN + 66;
- public const int XMLATTR = LAST_BYTECODE_TOKEN + 67;
- public const int XMLEND = LAST_BYTECODE_TOKEN + 68;
- public const int TO_OBJECT = LAST_BYTECODE_TOKEN + 69;
- public const int TO_DOUBLE = LAST_BYTECODE_TOKEN + 70;
-
- public const int GET = LAST_BYTECODE_TOKEN + 71; // JS 1.5 get pseudo keyword
- public const int SET = LAST_BYTECODE_TOKEN + 72; // JS 1.5 set pseudo keyword
- public const int CONST = LAST_BYTECODE_TOKEN + 73;
- public const int SETCONST = LAST_BYTECODE_TOKEN + 74;
- public const int SETCONSTVAR = LAST_BYTECODE_TOKEN + 75;
- public const int CONDCOMMENT = LAST_BYTECODE_TOKEN + 76; // JScript conditional comment
- public const int KEEPCOMMENT = LAST_BYTECODE_TOKEN + 77; // /*! ... */ comment
- public const int DEBUGGER = LAST_BYTECODE_TOKEN + 78;
-
- public const int LAST_TOKEN = LAST_BYTECODE_TOKEN + 79;
-
- public static string name (int token)
- {
- //if (!printNames) {
- // return Convert.ToString (token);
- //}
- switch (token) {
-
- case ERROR:
- return "ERROR";
- case EOF:
- return "EOF";
- case EOL:
- return "EOL";
-
- case ENTERWITH:
- return "ENTERWITH";
-
- case LEAVEWITH:
- return "LEAVEWITH";
-
- case RETURN:
- return "RETURN";
-
- case GOTO:
- return "GOTO";
-
- case IFEQ:
- return "IFEQ";
-
- case IFNE:
- return "IFNE";
-
- case SETNAME:
- return "SETNAME";
-
- case BITOR:
- return "BITOR";
-
- case BITXOR:
- return "BITXOR";
-
- case BITAND:
- return "BITAND";
-
- case EQ:
- return "EQ";
-
- case NE:
- return "NE";
-
- case LT:
- return "LT";
-
- case LE:
- return "LE";
-
- case GT:
- return "GT";
-
- case GE:
- return "GE";
-
- case LSH:
- return "LSH";
-
- case RSH:
- return "RSH";
-
- case URSH:
- return "URSH";
-
- case ADD:
- return "ADD";
-
- case SUB:
- return "SUB";
-
- case MUL:
- return "MUL";
-
- case DIV:
- return "DIV";
-
- case MOD:
- return "MOD";
-
- case NOT:
- return "NOT";
-
- case BITNOT:
- return "BITNOT";
-
- case POS:
- return "POS";
-
- case NEG:
- return "NEG";
-
- case NEW:
- return "NEW";
-
- case DELPROP:
- return "DELPROP";
-
- case TYPEOF:
- return "TYPEOF";
-
- case GETPROP:
- return "GETPROP";
-
- case SETPROP:
- return "SETPROP";
-
- case GETELEM:
- return "GETELEM";
-
- case SETELEM:
- return "SETELEM";
-
- case CALL:
- return "CALL";
-
- case NAME:
- return "NAME";
-
- case NUMBER:
- return "NUMBER";
-
- case STRING:
- return "STRING";
-
- case NULL:
- return "NULL";
-
- case THIS:
- return "THIS";
-
- case FALSE:
- return "FALSE";
-
- case TRUE:
- return "TRUE";
-
- case SHEQ:
- return "SHEQ";
-
- case SHNE:
- return "SHNE";
-
- case REGEXP:
- return "OBJECT";
-
- case BINDNAME:
- return "BINDNAME";
-
- case THROW:
- return "THROW";
-
- case RETHROW:
- return "RETHROW";
-
- case IN:
- return "IN";
-
- case INSTANCEOF:
- return "INSTANCEOF";
-
- case LOCAL_LOAD:
- return "LOCAL_LOAD";
-
- case GETVAR:
- return "GETVAR";
-
- case SETVAR:
- return "SETVAR";
-
- case CATCH_SCOPE:
- return "CATCH_SCOPE";
-
- case ENUM_INIT_KEYS:
- return "ENUM_INIT_KEYS";
-
- case ENUM_INIT_VALUES:
- return "ENUM_INIT_VALUES";
-
- case ENUM_NEXT:
- return "ENUM_NEXT";
-
- case ENUM_ID:
- return "ENUM_ID";
-
- case THISFN:
- return "THISFN";
-
- case RETURN_RESULT:
- return "RETURN_RESULT";
-
- case ARRAYLIT:
- return "ARRAYLIT";
-
- case OBJECTLIT:
- return "OBJECTLIT";
-
- case GET_REF:
- return "GET_REF";
-
- case SET_REF:
- return "SET_REF";
-
- case DEL_REF:
- return "DEL_REF";
-
- case REF_CALL:
- return "REF_CALL";
-
- case REF_SPECIAL:
- return "REF_SPECIAL";
-
- case DEFAULTNAMESPACE:
- return "DEFAULTNAMESPACE";
-
- case ESCXMLTEXT:
- return "ESCXMLTEXT";
-
- case ESCXMLATTR:
- return "ESCXMLATTR";
-
- case REF_MEMBER:
- return "REF_MEMBER";
-
- case REF_NS_MEMBER:
- return "REF_NS_MEMBER";
-
- case REF_NAME:
- return "REF_NAME";
-
- case REF_NS_NAME:
- return "REF_NS_NAME";
-
- case TRY:
- return "TRY";
-
- case SEMI:
- return "SEMI";
-
- case LB:
- return "LB";
-
- case RB:
- return "RB";
-
- case LC:
- return "LC";
-
- case RC:
- return "RC";
-
- case LP:
- return "LP";
-
- case RP:
- return "RP";
-
- case COMMA:
- return "COMMA";
-
- case ASSIGN:
- return "ASSIGN";
-
- case ASSIGN_BITOR:
- return "ASSIGN_BITOR";
-
- case ASSIGN_BITXOR:
- return "ASSIGN_BITXOR";
-
- case ASSIGN_BITAND:
- return "ASSIGN_BITAND";
-
- case ASSIGN_LSH:
- return "ASSIGN_LSH";
-
- case ASSIGN_RSH:
- return "ASSIGN_RSH";
-
- case ASSIGN_URSH:
- return "ASSIGN_URSH";
-
- case ASSIGN_ADD:
- return "ASSIGN_ADD";
-
- case ASSIGN_SUB:
- return "ASSIGN_SUB";
-
- case ASSIGN_MUL:
- return "ASSIGN_MUL";
-
- case ASSIGN_DIV:
- return "ASSIGN_DIV";
-
- case ASSIGN_MOD:
- return "ASSIGN_MOD";
-
- case HOOK:
- return "HOOK";
-
- case COLON:
- return "COLON";
-
- case OR:
- return "OR";
-
- case AND:
- return "AND";
-
- case INC:
- return "INC";
-
- case DEC:
- return "DEC";
-
- case DOT:
- return "DOT";
-
- case FUNCTION:
- return "FUNCTION";
-
- case EXPORT:
- return "EXPORT";
-
- case IMPORT:
- return "IMPORT";
-
- case IF:
- return "IF";
-
- case ELSE:
- return "ELSE";
-
- case SWITCH:
- return "SWITCH";
-
- case CASE:
- return "CASE";
-
- case DEFAULT:
- return "DEFAULT";
-
- case WHILE:
- return "WHILE";
-
- case DO:
- return "DO";
-
- case FOR:
- return "FOR";
-
- case BREAK:
- return "BREAK";
-
- case CONTINUE:
- return "CONTINUE";
-
- case VAR:
- return "VAR";
-
- case WITH:
- return "WITH";
-
- case CATCH:
- return "CATCH";
-
- case FINALLY:
- return "FINALLY";
-
- case RESERVED:
- return "RESERVED";
-
- case EMPTY:
- return "EMPTY";
-
- case BLOCK:
- return "BLOCK";
-
- case LABEL:
- return "LABEL";
-
- case TARGET:
- return "TARGET";
-
- case LOOP:
- return "LOOP";
-
- case EXPR_VOID:
- return "EXPR_VOID";
-
- case EXPR_RESULT:
- return "EXPR_RESULT";
-
- case JSR:
- return "JSR";
-
- case SCRIPT:
- return "SCRIPT";
-
- case TYPEOFNAME:
- return "TYPEOFNAME";
-
- case USE_STACK:
- return "USE_STACK";
-
- case SETPROP_OP:
- return "SETPROP_OP";
-
- case SETELEM_OP:
- return "SETELEM_OP";
-
- case LOCAL_BLOCK:
- return "LOCAL_BLOCK";
-
- case SET_REF_OP:
- return "SET_REF_OP";
-
- case DOTDOT:
- return "DOTDOT";
-
- case COLONCOLON:
- return "COLONCOLON";
-
- case XML:
- return "XML";
-
- case DOTQUERY:
- return "DOTQUERY";
-
- case XMLATTR:
- return "XMLATTR";
-
- case XMLEND:
- return "XMLEND";
-
- case TO_OBJECT: return "TO_OBJECT";
- case TO_DOUBLE: return "TO_DOUBLE";
- case GET: return "GET";
- case SET: return "SET";
- case CONST: return "CONST";
- case SETCONST: return "SETCONST";
- case SETCONSTVAR: return "SETCONSTVAR";
- case CONDCOMMENT: return "CONDCOMMENT";
- case KEEPCOMMENT: return "KEEPCOMMENT";
- case DEBUGGER: return "DEBUGGER";
- default: return "UNKNOWN Token Type";
- }
-
- // Token without name
- throw new ApplicationException ("Unknown token: " + Convert.ToString (token));
- }
- }
+//------------------------------------------------------------------------------
+//
+//
+// The use and distribution terms for this software are contained in the file
+// named 'LICENSE', which can be found in the resources directory of this
+// distribution.
+//
+// By using this software in any fashion, you are agreeing to be bound by the
+// terms of this license.
+//
+//
+//------------------------------------------------------------------------------
+
+using System;
+
+namespace EcmaScript.NET
+{
+
+ /// This class implements the JavaScript scanner.
+ ///
+ /// It is based on the C source files jsscan.c and jsscan.h
+ /// in the jsref package.
+ ///
+ ///
+ public class Token
+ {
+
+ // debug flags
+ internal static readonly bool printTrees = false; // TODO: make me a preprocessor directive
+
+ internal static readonly bool printICode = false; // TODO: make me a preprocessor directive
+
+ internal static readonly bool printNames = printTrees || printICode;
+
+ ///
+ /// Token types.
+ ///
+ /// These values correspond to JSTokenType values in
+ /// jsscan.c.
+ ///
+ public const int ERROR = -1; /* well-known as the only code < EOF */
+ public const int EOF = 0; /* end of file */
+ public const int EOL = 1; /* end of line */
+ public const int FIRST_BYTECODE_TOKEN = 2;
+ public const int ENTERWITH = 2;
+ public const int LEAVEWITH = 3;
+ public const int RETURN = 4;
+ public const int GOTO = 5;
+ public const int IFEQ = 6;
+ public const int IFNE = 7;
+ public const int SETNAME = 8;
+ public const int BITOR = 9;
+ public const int BITXOR = 10;
+ public const int BITAND = 11;
+ public const int EQ = 12;
+ public const int NE = 13;
+ public const int LT = 14;
+ public const int LE = 15;
+ public const int GT = 16;
+ public const int GE = 17;
+ public const int LSH = 18;
+ public const int RSH = 19;
+ public const int URSH = 20;
+ public const int ADD = 21;
+ public const int SUB = 22;
+ public const int MUL = 23;
+ public const int DIV = 24;
+ public const int MOD = 25;
+ public const int NOT = 26;
+ public const int BITNOT = 27;
+ public const int POS = 28;
+ public const int NEG = 29;
+ public const int NEW = 30;
+ public const int DELPROP = 31;
+ public const int TYPEOF = 32;
+ public const int GETPROP = 33;
+ public const int SETPROP = 34;
+ public const int GETELEM = 35;
+ public const int SETELEM = 36;
+ public const int CALL = 37;
+ public const int NAME = 38;
+ public const int NUMBER = 39;
+ public const int STRING = 40;
+ public const int NULL = 41;
+ public const int THIS = 42;
+ public const int FALSE = 43;
+ public const int TRUE = 44;
+ public const int SHEQ = 45;
+ public const int SHNE = 46;
+ public const int REGEXP = 47;
+ public const int BINDNAME = 48;
+ public const int THROW = 49;
+ public const int RETHROW = 50;
+ public const int IN = 51;
+ public const int INSTANCEOF = 52;
+ public const int LOCAL_LOAD = 53;
+ public const int GETVAR = 54;
+ public const int SETVAR = 55;
+ public const int CATCH_SCOPE = 56;
+ public const int ENUM_INIT_KEYS = 57;
+ public const int ENUM_INIT_VALUES = 58;
+ public const int ENUM_NEXT = 59;
+ public const int ENUM_ID = 60;
+ public const int THISFN = 61;
+ public const int RETURN_RESULT = 62;
+ public const int ARRAYLIT = 63;
+ public const int OBJECTLIT = 64;
+ public const int GET_REF = 65;
+ public const int SET_REF = 66;
+ public const int DEL_REF = 67;
+ public const int REF_CALL = 68;
+ public const int REF_SPECIAL = 69;
+ public const int DEFAULTNAMESPACE = 70;
+ public const int ESCXMLATTR = 71;
+ public const int ESCXMLTEXT = 72;
+ public const int REF_MEMBER = 73;
+ public const int REF_NS_MEMBER = 74;
+ public const int REF_NAME = 75;
+ public const int REF_NS_NAME = 76; // Reference for ns::y, @ns::y@[y] etc.
+ public const int SETPROP_GETTER = 77;
+ public const int SETPROP_SETTER = 78;
+
+ // End of interpreter bytecodes
+ public const int LAST_BYTECODE_TOKEN = SETPROP_SETTER;
+
+ public const int TRY = LAST_BYTECODE_TOKEN + 1;
+ public const int SEMI = LAST_BYTECODE_TOKEN + 2;
+ public const int LB = LAST_BYTECODE_TOKEN + 3;
+ public const int RB = LAST_BYTECODE_TOKEN + 4;
+ public const int LC = LAST_BYTECODE_TOKEN + 5;
+ public const int RC = LAST_BYTECODE_TOKEN + 6;
+ public const int LP = LAST_BYTECODE_TOKEN + 7;
+ public const int RP = LAST_BYTECODE_TOKEN + 8;
+ public const int COMMA = LAST_BYTECODE_TOKEN + 9;
+ public const int ASSIGN = LAST_BYTECODE_TOKEN + 10;
+ public const int ASSIGN_BITOR = LAST_BYTECODE_TOKEN + 11;
+ public const int ASSIGN_BITXOR = LAST_BYTECODE_TOKEN + 12;
+ public const int ASSIGN_BITAND = LAST_BYTECODE_TOKEN + 13;
+ public const int ASSIGN_LSH = LAST_BYTECODE_TOKEN + 14;
+ public const int ASSIGN_RSH = LAST_BYTECODE_TOKEN + 15;
+ public const int ASSIGN_URSH = LAST_BYTECODE_TOKEN + 16;
+ public const int ASSIGN_ADD = LAST_BYTECODE_TOKEN + 17;
+ public const int ASSIGN_SUB = LAST_BYTECODE_TOKEN + 18;
+ public const int ASSIGN_MUL = LAST_BYTECODE_TOKEN + 19;
+ public const int ASSIGN_DIV = LAST_BYTECODE_TOKEN + 20;
+ public const int ASSIGN_MOD = LAST_BYTECODE_TOKEN + 21; // %=
+
+ public const int FIRST_ASSIGN = ASSIGN;
+ public const int LAST_ASSIGN = ASSIGN_MOD;
+
+ public const int HOOK = LAST_BYTECODE_TOKEN + 22;
+ public const int COLON = LAST_BYTECODE_TOKEN + 23;
+ public const int OR = LAST_BYTECODE_TOKEN + 24;
+ public const int AND = LAST_BYTECODE_TOKEN + 25;
+ public const int INC = LAST_BYTECODE_TOKEN + 26;
+ public const int DEC = LAST_BYTECODE_TOKEN + 27;
+ public const int DOT = LAST_BYTECODE_TOKEN + 28;
+ public const int FUNCTION = LAST_BYTECODE_TOKEN + 29;
+ public const int EXPORT = LAST_BYTECODE_TOKEN + 30;
+ public const int IMPORT = LAST_BYTECODE_TOKEN + 31;
+ public const int IF = LAST_BYTECODE_TOKEN + 32;
+ public const int ELSE = LAST_BYTECODE_TOKEN + 33;
+ public const int SWITCH = LAST_BYTECODE_TOKEN + 34;
+ public const int CASE = LAST_BYTECODE_TOKEN + 35;
+ public const int DEFAULT = LAST_BYTECODE_TOKEN + 36;
+ public const int WHILE = LAST_BYTECODE_TOKEN + 37;
+ public const int DO = LAST_BYTECODE_TOKEN + 38;
+ public const int FOR = LAST_BYTECODE_TOKEN + 39;
+ public const int BREAK = LAST_BYTECODE_TOKEN + 40;
+ public const int CONTINUE = LAST_BYTECODE_TOKEN + 41;
+ public const int VAR = LAST_BYTECODE_TOKEN + 42;
+ public const int WITH = LAST_BYTECODE_TOKEN + 43;
+ public const int CATCH = LAST_BYTECODE_TOKEN + 44;
+ public const int FINALLY = LAST_BYTECODE_TOKEN + 45;
+ public const int VOID = LAST_BYTECODE_TOKEN + 46;
+ public const int RESERVED = LAST_BYTECODE_TOKEN + 47;
+ public const int EMPTY = LAST_BYTECODE_TOKEN + 48;
+ public const int BLOCK = LAST_BYTECODE_TOKEN + 49;
+ public const int LABEL = LAST_BYTECODE_TOKEN + 50;
+ public const int TARGET = LAST_BYTECODE_TOKEN + 51;
+ public const int LOOP = LAST_BYTECODE_TOKEN + 52;
+ public const int EXPR_VOID = LAST_BYTECODE_TOKEN + 53;
+ public const int EXPR_RESULT = LAST_BYTECODE_TOKEN + 54;
+ public const int JSR = LAST_BYTECODE_TOKEN + 55;
+ public const int SCRIPT = LAST_BYTECODE_TOKEN + 56;
+ public const int TYPEOFNAME = LAST_BYTECODE_TOKEN + 57;
+ public const int USE_STACK = LAST_BYTECODE_TOKEN + 58;
+ public const int SETPROP_OP = LAST_BYTECODE_TOKEN + 59;
+ public const int SETELEM_OP = LAST_BYTECODE_TOKEN + 60;
+ public const int LOCAL_BLOCK = LAST_BYTECODE_TOKEN + 61;
+ public const int SET_REF_OP = LAST_BYTECODE_TOKEN + 62;
+ public const int DOTDOT = LAST_BYTECODE_TOKEN + 63;
+ public const int COLONCOLON = LAST_BYTECODE_TOKEN + 64;
+ public const int XML = LAST_BYTECODE_TOKEN + 65;
+ public const int DOTQUERY = LAST_BYTECODE_TOKEN + 66;
+ public const int XMLATTR = LAST_BYTECODE_TOKEN + 67;
+ public const int XMLEND = LAST_BYTECODE_TOKEN + 68;
+ public const int TO_OBJECT = LAST_BYTECODE_TOKEN + 69;
+ public const int TO_DOUBLE = LAST_BYTECODE_TOKEN + 70;
+
+ public const int GET = LAST_BYTECODE_TOKEN + 71; // JS 1.5 get pseudo keyword
+ public const int SET = LAST_BYTECODE_TOKEN + 72; // JS 1.5 set pseudo keyword
+ public const int CONST = LAST_BYTECODE_TOKEN + 73;
+ public const int SETCONST = LAST_BYTECODE_TOKEN + 74;
+ public const int SETCONSTVAR = LAST_BYTECODE_TOKEN + 75;
+ public const int CONDCOMMENT = LAST_BYTECODE_TOKEN + 76; // JScript conditional comment
+ public const int KEEPCOMMENT = LAST_BYTECODE_TOKEN + 77; // /*! ... */ comment
+ public const int DEBUGGER = LAST_BYTECODE_TOKEN + 78;
+
+ public const int LAST_TOKEN = LAST_BYTECODE_TOKEN + 79;
+
+ public static string name (int token)
+ {
+ //if (!printNames) {
+ // return Convert.ToString (token);
+ //}
+ switch (token) {
+
+ case ERROR:
+ return "ERROR";
+ case EOF:
+ return "EOF";
+ case EOL:
+ return "EOL";
+
+ case ENTERWITH:
+ return "ENTERWITH";
+
+ case LEAVEWITH:
+ return "LEAVEWITH";
+
+ case RETURN:
+ return "RETURN";
+
+ case GOTO:
+ return "GOTO";
+
+ case IFEQ:
+ return "IFEQ";
+
+ case IFNE:
+ return "IFNE";
+
+ case SETNAME:
+ return "SETNAME";
+
+ case BITOR:
+ return "BITOR";
+
+ case BITXOR:
+ return "BITXOR";
+
+ case BITAND:
+ return "BITAND";
+
+ case EQ:
+ return "EQ";
+
+ case NE:
+ return "NE";
+
+ case LT:
+ return "LT";
+
+ case LE:
+ return "LE";
+
+ case GT:
+ return "GT";
+
+ case GE:
+ return "GE";
+
+ case LSH:
+ return "LSH";
+
+ case RSH:
+ return "RSH";
+
+ case URSH:
+ return "URSH";
+
+ case ADD:
+ return "ADD";
+
+ case SUB:
+ return "SUB";
+
+ case MUL:
+ return "MUL";
+
+ case DIV:
+ return "DIV";
+
+ case MOD:
+ return "MOD";
+
+ case NOT:
+ return "NOT";
+
+ case BITNOT:
+ return "BITNOT";
+
+ case POS:
+ return "POS";
+
+ case NEG:
+ return "NEG";
+
+ case NEW:
+ return "NEW";
+
+ case DELPROP:
+ return "DELPROP";
+
+ case TYPEOF:
+ return "TYPEOF";
+
+ case GETPROP:
+ return "GETPROP";
+
+ case SETPROP:
+ return "SETPROP";
+
+ case GETELEM:
+ return "GETELEM";
+
+ case SETELEM:
+ return "SETELEM";
+
+ case CALL:
+ return "CALL";
+
+ case NAME:
+ return "NAME";
+
+ case NUMBER:
+ return "NUMBER";
+
+ case STRING:
+ return "STRING";
+
+ case NULL:
+ return "NULL";
+
+ case THIS:
+ return "THIS";
+
+ case FALSE:
+ return "FALSE";
+
+ case TRUE:
+ return "TRUE";
+
+ case SHEQ:
+ return "SHEQ";
+
+ case SHNE:
+ return "SHNE";
+
+ case REGEXP:
+ return "OBJECT";
+
+ case BINDNAME:
+ return "BINDNAME";
+
+ case THROW:
+ return "THROW";
+
+ case RETHROW:
+ return "RETHROW";
+
+ case IN:
+ return "IN";
+
+ case INSTANCEOF:
+ return "INSTANCEOF";
+
+ case LOCAL_LOAD:
+ return "LOCAL_LOAD";
+
+ case GETVAR:
+ return "GETVAR";
+
+ case SETVAR:
+ return "SETVAR";
+
+ case CATCH_SCOPE:
+ return "CATCH_SCOPE";
+
+ case ENUM_INIT_KEYS:
+ return "ENUM_INIT_KEYS";
+
+ case ENUM_INIT_VALUES:
+ return "ENUM_INIT_VALUES";
+
+ case ENUM_NEXT:
+ return "ENUM_NEXT";
+
+ case ENUM_ID:
+ return "ENUM_ID";
+
+ case THISFN:
+ return "THISFN";
+
+ case RETURN_RESULT:
+ return "RETURN_RESULT";
+
+ case ARRAYLIT:
+ return "ARRAYLIT";
+
+ case OBJECTLIT:
+ return "OBJECTLIT";
+
+ case GET_REF:
+ return "GET_REF";
+
+ case SET_REF:
+ return "SET_REF";
+
+ case DEL_REF:
+ return "DEL_REF";
+
+ case REF_CALL:
+ return "REF_CALL";
+
+ case REF_SPECIAL:
+ return "REF_SPECIAL";
+
+ case DEFAULTNAMESPACE:
+ return "DEFAULTNAMESPACE";
+
+ case ESCXMLTEXT:
+ return "ESCXMLTEXT";
+
+ case ESCXMLATTR:
+ return "ESCXMLATTR";
+
+ case REF_MEMBER:
+ return "REF_MEMBER";
+
+ case REF_NS_MEMBER:
+ return "REF_NS_MEMBER";
+
+ case REF_NAME:
+ return "REF_NAME";
+
+ case REF_NS_NAME:
+ return "REF_NS_NAME";
+
+ case TRY:
+ return "TRY";
+
+ case SEMI:
+ return "SEMI";
+
+ case LB:
+ return "LB";
+
+ case RB:
+ return "RB";
+
+ case LC:
+ return "LC";
+
+ case RC:
+ return "RC";
+
+ case LP:
+ return "LP";
+
+ case RP:
+ return "RP";
+
+ case COMMA:
+ return "COMMA";
+
+ case ASSIGN:
+ return "ASSIGN";
+
+ case ASSIGN_BITOR:
+ return "ASSIGN_BITOR";
+
+ case ASSIGN_BITXOR:
+ return "ASSIGN_BITXOR";
+
+ case ASSIGN_BITAND:
+ return "ASSIGN_BITAND";
+
+ case ASSIGN_LSH:
+ return "ASSIGN_LSH";
+
+ case ASSIGN_RSH:
+ return "ASSIGN_RSH";
+
+ case ASSIGN_URSH:
+ return "ASSIGN_URSH";
+
+ case ASSIGN_ADD:
+ return "ASSIGN_ADD";
+
+ case ASSIGN_SUB:
+ return "ASSIGN_SUB";
+
+ case ASSIGN_MUL:
+ return "ASSIGN_MUL";
+
+ case ASSIGN_DIV:
+ return "ASSIGN_DIV";
+
+ case ASSIGN_MOD:
+ return "ASSIGN_MOD";
+
+ case HOOK:
+ return "HOOK";
+
+ case COLON:
+ return "COLON";
+
+ case OR:
+ return "OR";
+
+ case AND:
+ return "AND";
+
+ case INC:
+ return "INC";
+
+ case DEC:
+ return "DEC";
+
+ case DOT:
+ return "DOT";
+
+ case FUNCTION:
+ return "FUNCTION";
+
+ case EXPORT:
+ return "EXPORT";
+
+ case IMPORT:
+ return "IMPORT";
+
+ case IF:
+ return "IF";
+
+ case ELSE:
+ return "ELSE";
+
+ case SWITCH:
+ return "SWITCH";
+
+ case CASE:
+ return "CASE";
+
+ case DEFAULT:
+ return "DEFAULT";
+
+ case WHILE:
+ return "WHILE";
+
+ case DO:
+ return "DO";
+
+ case FOR:
+ return "FOR";
+
+ case BREAK:
+ return "BREAK";
+
+ case CONTINUE:
+ return "CONTINUE";
+
+ case VAR:
+ return "VAR";
+
+ case WITH:
+ return "WITH";
+
+ case CATCH:
+ return "CATCH";
+
+ case FINALLY:
+ return "FINALLY";
+
+ case RESERVED:
+ return "RESERVED";
+
+ case EMPTY:
+ return "EMPTY";
+
+ case BLOCK:
+ return "BLOCK";
+
+ case LABEL:
+ return "LABEL";
+
+ case TARGET:
+ return "TARGET";
+
+ case LOOP:
+ return "LOOP";
+
+ case EXPR_VOID:
+ return "EXPR_VOID";
+
+ case EXPR_RESULT:
+ return "EXPR_RESULT";
+
+ case JSR:
+ return "JSR";
+
+ case SCRIPT:
+ return "SCRIPT";
+
+ case TYPEOFNAME:
+ return "TYPEOFNAME";
+
+ case USE_STACK:
+ return "USE_STACK";
+
+ case SETPROP_OP:
+ return "SETPROP_OP";
+
+ case SETELEM_OP:
+ return "SETELEM_OP";
+
+ case LOCAL_BLOCK:
+ return "LOCAL_BLOCK";
+
+ case SET_REF_OP:
+ return "SET_REF_OP";
+
+ case DOTDOT:
+ return "DOTDOT";
+
+ case COLONCOLON:
+ return "COLONCOLON";
+
+ case XML:
+ return "XML";
+
+ case DOTQUERY:
+ return "DOTQUERY";
+
+ case XMLATTR:
+ return "XMLATTR";
+
+ case XMLEND:
+ return "XMLEND";
+
+ case TO_OBJECT: return "TO_OBJECT";
+ case TO_DOUBLE: return "TO_DOUBLE";
+ case GET: return "GET";
+ case SET: return "SET";
+ case CONST: return "CONST";
+ case SETCONST: return "SETCONST";
+ case SETCONSTVAR: return "SETCONSTVAR";
+ case CONDCOMMENT: return "CONDCOMMENT";
+ case KEEPCOMMENT: return "KEEPCOMMENT";
+ case DEBUGGER: return "DEBUGGER";
+ default: return "UNKNOWN Token Type";
+ }
+
+ // Token without name
+ throw new Exception ("Unknown token: " + Convert.ToString (token));
+ }
+ }
}
\ No newline at end of file
diff --git a/Code/EcmaScript.NET/TokenStream.cs b/src/EcmaScript.NET/TokenStream.cs
similarity index 97%
rename from Code/EcmaScript.NET/TokenStream.cs
rename to src/EcmaScript.NET/TokenStream.cs
index a61694b..1688acd 100644
--- a/Code/EcmaScript.NET/TokenStream.cs
+++ b/src/EcmaScript.NET/TokenStream.cs
@@ -1,1909 +1,1920 @@
-//------------------------------------------------------------------------------
-//
-//
-// The use and distribution terms for this software are contained in the file
-// named 'LICENSE', which can be found in the resources directory of this
-// distribution.
-//
-// By using this software in any fashion, you are agreeing to be bound by the
-// terms of this license.
-//
-//
-//------------------------------------------------------------------------------
-
-using System;
-using System.Text;
-using System.Globalization;
-
-using EcmaScript.NET.Types;
-using EcmaScript.NET.Collections;
-
-namespace EcmaScript.NET
-{
-
- /// This class implements the JavaScript scanner.
- ///
- /// It is based on the C source files jsscan.c and jsscan.h
- /// in the jsref package.
- ///
- ///
- internal class TokenStream
- {
- internal int Lineno
- {
- get
- {
- return lineno;
- }
-
- }
- internal string String
- {
- get
- {
- return str;
- }
-
- }
- internal double Number
- {
- get
- {
- return dNumber;
- }
-
- }
- internal int Token
- {
- get
- {
- int c;
-
-
- for (; ; )
- {
- // Eat whitespace, possibly sensitive to newlines.
- for (; ; )
- {
- c = Char;
- if (c == EOF_CHAR)
- {
- return EcmaScript.NET.Token.EOF;
- }
- else if (c == '\n')
- {
- dirtyLine = false;
- return EcmaScript.NET.Token.EOL;
- }
- else if (!isJSSpace(c))
- {
- if (c != '-')
- {
- dirtyLine = true;
- }
- break;
- }
- }
-
- if (c == '@')
- return EcmaScript.NET.Token.XMLATTR;
-
- // identifier/keyword/instanceof?
- // watch out for starting with a
- bool identifierStart;
- bool isUnicodeEscapeStart = false;
- if (c == '\\')
- {
- c = Char;
- if (c == 'u')
- {
- identifierStart = true;
- isUnicodeEscapeStart = true;
- stringBufferTop = 0;
- }
- else
- {
- identifierStart = false;
- ungetChar(c);
- c = '\\';
- }
- }
- else
- {
- char ch = (char)c;
- identifierStart = char.IsLetter(ch)
- || ch == '$'
- || ch == '_';
- if (identifierStart)
- {
- stringBufferTop = 0;
- addToString(c);
- }
- }
-
- if (identifierStart)
- {
- bool containsEscape = isUnicodeEscapeStart;
- for (; ; )
- {
- if (isUnicodeEscapeStart)
- {
- // strictly speaking we should probably push-back
- // all the bad characters if the u
- // sequence is malformed. But since there isn't a
- // correct context(is there?) for a bad Unicode
- // escape sequence in an identifier, we can report
- // an error here.
- int escapeVal = 0;
- for (int i = 0; i != 4; ++i)
- {
- c = Char;
- escapeVal = ScriptConvert.XDigitToInt(c, escapeVal);
- // Next check takes care about c < 0 and bad escape
- if (escapeVal < 0)
- {
- break;
- }
- }
- if (escapeVal < 0)
- {
- parser.AddError("msg.invalid.escape");
- return EcmaScript.NET.Token.ERROR;
- }
- addToString(escapeVal);
- isUnicodeEscapeStart = false;
- }
- else
- {
- c = Char;
- if (c == '\\')
- {
- c = Char;
- if (c == 'u')
- {
- isUnicodeEscapeStart = true;
- containsEscape = true;
- }
- else
- {
- parser.AddError("msg.illegal.character");
- return EcmaScript.NET.Token.ERROR;
- }
- }
- else
- {
- if (c == EOF_CHAR || !IsJavaIdentifierPart((char)c))
- {
- break;
- }
- addToString(c);
- }
- }
- }
- ungetChar(c);
-
- string str = StringFromBuffer;
- if (!containsEscape)
- {
- // OPT we shouldn't have to make a string (object!) to
- // check if it's a keyword.
-
- // Return the corresponding token if it's a keyword
- int result = stringToKeyword(str);
- if (result != EcmaScript.NET.Token.EOF)
- {
- if (result != EcmaScript.NET.Token.RESERVED)
- {
- return result;
- }
- else if (!parser.compilerEnv.isReservedKeywordAsIdentifier())
- {
- return result;
- }
- else
- {
- // If implementation permits to use future reserved
- // keywords in violation with the EcmaScript,
- // treat it as name but issue warning
- parser.AddWarning("msg.reserved.keyword", str);
- }
- }
- }
- this.str = ((string)allStrings.intern(str));
- return EcmaScript.NET.Token.NAME;
- }
-
- // is it a number?
- if (isDigit(c) || (c == '.' && isDigit(peekChar())))
- {
-
- stringBufferTop = 0;
- int toBase = 10;
-
- if (c == '0')
- {
- c = Char;
- if (c == 'x' || c == 'X')
- {
- toBase = 16;
- c = Char;
- }
- else if (isDigit(c))
- {
- toBase = 8;
- }
- else
- {
- addToString('0');
- }
- }
-
- if (toBase == 16)
- {
- while (0 <= ScriptConvert.XDigitToInt(c, 0))
- {
- addToString(c);
- c = Char;
- }
- }
- else
- {
- while ('0' <= c && c <= '9')
- {
- /*
- * We permit 08 and 09 as decimal numbers, which
- * makes our behavior a superset of the ECMA
- * numeric grammar. We might not always be so
- * permissive, so we warn about it.
- */
- if (toBase == 8 && c >= '8')
- {
- parser.AddWarning("msg.bad.octal.literal", c == '8' ? "8" : "9");
- toBase = 10;
- }
- addToString(c);
- c = Char;
- }
- }
-
- bool isInteger = true;
-
- if (toBase == 10 && (c == '.' || c == 'e' || c == 'E'))
- {
- isInteger = false;
- if (c == '.')
- {
- do
- {
- addToString(c);
- c = Char;
- }
- while (isDigit(c));
- }
- if (c == 'e' || c == 'E')
- {
- addToString(c);
- c = Char;
- if (c == '+' || c == '-')
- {
- addToString(c);
- c = Char;
- }
- if (!isDigit(c))
- {
- parser.AddError("msg.missing.exponent");
- return EcmaScript.NET.Token.ERROR;
- }
- do
- {
- addToString(c);
- c = Char;
- }
- while (isDigit(c));
- }
- }
- ungetChar(c);
- string numString = StringFromBuffer;
-
- double dval;
- if (toBase == 10 && !isInteger)
- {
- try
- {
- // Use Java conversion to number from string...
- dval = System.Double.Parse(numString, BuiltinNumber.NumberFormatter);
- }
- catch (OverflowException)
- {
- // HACK
- if (numString[0] == '-')
- dval = double.NegativeInfinity;
- else
- dval = double.PositiveInfinity;
- }
- catch (Exception)
- {
- parser.AddError("msg.caught.nfe");
- return EcmaScript.NET.Token.ERROR;
- }
- }
- else
- {
- dval = ScriptConvert.ToNumber(numString, 0, toBase);
- }
-
- this.dNumber = dval;
- return EcmaScript.NET.Token.NUMBER;
- }
-
- // is it a string?
- if (c == '"' || c == '\'')
- {
- // We attempt to accumulate a string the fast way, by
- // building it directly out of the reader. But if there
- // are any escaped characters in the string, we revert to
- // building it out of a StringBuffer.
-
- int quoteChar = c;
- stringBufferTop = 0;
-
- c = Char;
-
- while (c != quoteChar)
- {
- if (c == '\n' || c == EOF_CHAR)
- {
- ungetChar(c);
- parser.AddError("msg.unterminated.string.lit");
- return EcmaScript.NET.Token.ERROR;
- }
-
- if (c == '\\')
- {
- // We've hit an escaped character
-
- c = Char;
- switch (c)
- {
-
- case '\\': // backslash
- case 'b': // backspace
- case 'f': // form feed
- case 'n': // line feed
- case 'r': // carriage return
- case 't': // horizontal tab
- case 'v': // vertical tab
- case 'd': // octal sequence
- case 'u': // unicode sequence
- case 'x': // hexadecimal sequence
- // Only keep the '\' character for those
- // characters that need to be escaped...
- // Don't escape quoting characters...
- addToString('\\');
- addToString(c);
- break;
-
- case '\n':
- // Remove line terminator after escape
- break;
-
-
- default:
- if (isDigit(c))
- {
- // Octal representation of a character.
- // Preserve the escaping (see Y! bug #1637286)
- addToString('\\');
- }
- addToString(c);
- break;
- break;
-
- }
- }
- else
- {
- addToString(c);
- }
-
- c = Char;
- }
-
- string str = StringFromBuffer;
- this.str = ((string)allStrings.intern(str));
- return EcmaScript.NET.Token.STRING;
- }
-
- switch (c)
- {
-
- case ';':
- return EcmaScript.NET.Token.SEMI;
-
- case '[':
- return EcmaScript.NET.Token.LB;
-
- case ']':
- return EcmaScript.NET.Token.RB;
-
- case '{':
- return EcmaScript.NET.Token.LC;
-
- case '}':
- return EcmaScript.NET.Token.RC;
-
- case '(':
- return EcmaScript.NET.Token.LP;
-
- case ')':
- return EcmaScript.NET.Token.RP;
-
- case ',':
- return EcmaScript.NET.Token.COMMA;
-
- case '?':
- return EcmaScript.NET.Token.HOOK;
-
- case ':':
- if (matchChar(':'))
- {
- return EcmaScript.NET.Token.COLONCOLON;
- }
- else
- {
- return EcmaScript.NET.Token.COLON;
- }
-
- case '.':
- if (matchChar('.'))
- {
- return EcmaScript.NET.Token.DOTDOT;
- }
- else if (matchChar('('))
- {
- return EcmaScript.NET.Token.DOTQUERY;
- }
- else
- {
- return EcmaScript.NET.Token.DOT;
- }
-
- case '|':
- if (matchChar('|'))
- {
- return EcmaScript.NET.Token.OR;
- }
- else if (matchChar('='))
- {
- return EcmaScript.NET.Token.ASSIGN_BITOR;
- }
- else
- {
- return EcmaScript.NET.Token.BITOR;
- }
-
-
- case '^':
- if (matchChar('='))
- {
- return EcmaScript.NET.Token.ASSIGN_BITXOR;
- }
- else
- {
- return EcmaScript.NET.Token.BITXOR;
- }
-
-
- case '&':
- if (matchChar('&'))
- {
- return EcmaScript.NET.Token.AND;
- }
- else if (matchChar('='))
- {
- return EcmaScript.NET.Token.ASSIGN_BITAND;
- }
- else
- {
- return EcmaScript.NET.Token.BITAND;
- }
-
-
- case '=':
- if (matchChar('='))
- {
- if (matchChar('='))
- return EcmaScript.NET.Token.SHEQ;
- else
- return EcmaScript.NET.Token.EQ;
- }
- else
- {
- return EcmaScript.NET.Token.ASSIGN;
- }
-
-
- case '!':
- if (matchChar('='))
- {
- if (matchChar('='))
- return EcmaScript.NET.Token.SHNE;
- else
- return EcmaScript.NET.Token.NE;
- }
- else
- {
- return EcmaScript.NET.Token.NOT;
- }
-
-
- case '<':
- /* NB:treat HTML begin-comment as comment-till-eol */
- if (matchChar('!'))
- {
- if (matchChar('-'))
- {
- if (matchChar('-'))
- {
- skipLine();
-
- goto retry;
- }
- ungetChar('-');
- }
- ungetChar('!');
- }
- if (matchChar('<'))
- {
- if (matchChar('='))
- {
- return EcmaScript.NET.Token.ASSIGN_LSH;
- }
- else
- {
- return EcmaScript.NET.Token.LSH;
- }
- }
- else
- {
- if (matchChar('='))
- {
- return EcmaScript.NET.Token.LE;
- }
- else
- {
- return EcmaScript.NET.Token.LT;
- }
- }
-
-
- case '>':
- if (matchChar('>'))
- {
- if (matchChar('>'))
- {
- if (matchChar('='))
- {
- return EcmaScript.NET.Token.ASSIGN_URSH;
- }
- else
- {
- return EcmaScript.NET.Token.URSH;
- }
- }
- else
- {
- if (matchChar('='))
- {
- return EcmaScript.NET.Token.ASSIGN_RSH;
- }
- else
- {
- return EcmaScript.NET.Token.RSH;
- }
- }
- }
- else
- {
- if (matchChar('='))
- {
- return EcmaScript.NET.Token.GE;
- }
- else
- {
- return EcmaScript.NET.Token.GT;
- }
- }
-
-
- case '*':
- if (matchChar('='))
- {
- return EcmaScript.NET.Token.ASSIGN_MUL;
- }
- else
- {
- return EcmaScript.NET.Token.MUL;
- }
-
-
- case '/':
- // is it a // comment?
- if (matchChar('/'))
- {
- skipLine();
-
- goto retry;
- }
- if (matchChar('*'))
- {
- bool lookForSlash = false;
- StringBuilder sb = new StringBuilder();
- for (; ; )
- {
- c = Char;
- if (c == EOF_CHAR)
- {
- parser.AddError("msg.unterminated.comment");
- return EcmaScript.NET.Token.ERROR;
- }
- sb.Append((char)c);
- if (c == '*')
- {
- lookForSlash = true;
- }
- else if (c == '/')
- {
- if (lookForSlash)
- {
- sb.Remove(sb.Length - 2, 2);
- string s1 = sb.ToString();
- string s2 = s1.Trim();
- if (s1.StartsWith("!"))
- {
- // Remove the leading '!'
- this.str = s1.Substring(1);
- return NET.Token.KEEPCOMMENT;
- }
- else if (s2.StartsWith("@cc_on") ||
- s2.StartsWith("@if") ||
- s2.StartsWith("@elif") ||
- s2.StartsWith("@else") ||
- s2.StartsWith("@end"))
- {
- this.str = s1;
- return NET.Token.CONDCOMMENT;
- }
- else
- {
- goto retry;
- }
- }
- }
- else
- {
- lookForSlash = false;
- }
- }
- }
-
- if (matchChar('='))
- {
- return EcmaScript.NET.Token.ASSIGN_DIV;
- }
- else
- {
- return EcmaScript.NET.Token.DIV;
- }
-
-
- case '%':
- if (matchChar('='))
- {
- return EcmaScript.NET.Token.ASSIGN_MOD;
- }
- else
- {
- return EcmaScript.NET.Token.MOD;
- }
-
-
- case '~':
- return EcmaScript.NET.Token.BITNOT;
-
-
- case '+':
- if (matchChar('='))
- {
- return EcmaScript.NET.Token.ASSIGN_ADD;
- }
- else if (matchChar('+'))
- {
- return EcmaScript.NET.Token.INC;
- }
- else
- {
- return EcmaScript.NET.Token.ADD;
- }
-
-
- case '-':
- if (matchChar('='))
- {
- c = EcmaScript.NET.Token.ASSIGN_SUB;
- }
- else if (matchChar('-'))
- {
- if (!dirtyLine)
- {
- // treat HTML end-comment after possible whitespace
- // after line start as comment-utill-eol
- if (matchChar('>'))
- {
- skipLine();
-
- goto retry;
- }
- }
- c = EcmaScript.NET.Token.DEC;
- }
- else
- {
- c = EcmaScript.NET.Token.SUB;
- }
- dirtyLine = true;
- return c;
-
-
- default:
- parser.AddError("msg.illegal.character");
- return EcmaScript.NET.Token.ERROR;
-
- }
-
- retry:
- ;
- }
- }
-
- }
- internal bool XMLAttribute
- {
- get
- {
- return xmlIsAttribute;
- }
-
- }
- internal int FirstXMLToken
- {
- get
- {
- xmlOpenTagsCount = 0;
- xmlIsAttribute = false;
- xmlIsTagContent = false;
- ungetChar('<');
- return NextXMLToken;
- }
-
- }
- internal int NextXMLToken
- {
- get
- {
- stringBufferTop = 0; // remember the XML
-
- for (int c = Char; c != EOF_CHAR; c = Char)
- {
- if (xmlIsTagContent)
- {
- switch (c)
- {
-
- case '>':
- addToString(c);
- xmlIsTagContent = false;
- xmlIsAttribute = false;
- break;
-
- case '/':
- addToString(c);
- if (peekChar() == '>')
- {
- c = Char;
- addToString(c);
- xmlIsTagContent = false;
- xmlOpenTagsCount--;
- }
- break;
-
- case '{':
- ungetChar(c);
- this.str = StringFromBuffer;
- return EcmaScript.NET.Token.XML;
-
- case '\'':
- case '"':
- addToString(c);
- if (!readQuotedString(c))
- return EcmaScript.NET.Token.ERROR;
- break;
-
- case '=':
- addToString(c);
- xmlIsAttribute = true;
- break;
-
- case ' ':
- case '\t':
- case '\r':
- case '\n':
- addToString(c);
- break;
-
- default:
- addToString(c);
- xmlIsAttribute = false;
- break;
-
- }
-
- if (!xmlIsTagContent && xmlOpenTagsCount == 0)
- {
- this.str = StringFromBuffer;
- return EcmaScript.NET.Token.XMLEND;
- }
- }
- else
- {
- switch (c)
- {
-
- case '<':
- addToString(c);
- c = peekChar();
- switch (c)
- {
-
- case '!':
- c = Char; // Skip !
- addToString(c);
- c = peekChar();
- switch (c)
- {
-
- case '-':
- c = Char; // Skip -
- addToString(c);
- c = Char;
- if (c == '-')
- {
- addToString(c);
- if (!readXmlComment())
- return EcmaScript.NET.Token.ERROR;
- }
- else
- {
- // throw away the string in progress
- stringBufferTop = 0;
- this.str = null;
- parser.AddError("msg.XML.bad.form");
- return EcmaScript.NET.Token.ERROR;
- }
- break;
-
- case '[':
- c = Char; // Skip [
- addToString(c);
- if (Char == 'C' && Char == 'D' && Char == 'A' && Char == 'T' && Char == 'A' && Char == '[')
- {
- addToString('C');
- addToString('D');
- addToString('A');
- addToString('T');
- addToString('A');
- addToString('[');
- if (!readCDATA())
- return EcmaScript.NET.Token.ERROR;
- }
- else
- {
- // throw away the string in progress
- stringBufferTop = 0;
- this.str = null;
- parser.AddError("msg.XML.bad.form");
- return EcmaScript.NET.Token.ERROR;
- }
- break;
-
- default:
- if (!readEntity())
- return EcmaScript.NET.Token.ERROR;
- break;
-
- }
- break;
-
- case '?':
- c = Char; // Skip ?
- addToString(c);
- if (!readPI())
- return EcmaScript.NET.Token.ERROR;
- break;
-
- case '/':
- // End tag
- c = Char; // Skip /
- addToString(c);
- if (xmlOpenTagsCount == 0)
- {
- // throw away the string in progress
- stringBufferTop = 0;
- this.str = null;
- parser.AddError("msg.XML.bad.form");
- return EcmaScript.NET.Token.ERROR;
- }
- xmlIsTagContent = true;
- xmlOpenTagsCount--;
- break;
-
- default:
- // Start tag
- xmlIsTagContent = true;
- xmlOpenTagsCount++;
- break;
-
- }
- break;
-
- case '{':
- ungetChar(c);
- this.str = StringFromBuffer;
- return EcmaScript.NET.Token.XML;
-
- default:
- addToString(c);
- break;
-
- }
- }
- }
-
-
- stringBufferTop = 0; // throw away the string in progress
- this.str = null;
- parser.AddError("msg.XML.bad.form");
- return EcmaScript.NET.Token.ERROR;
- }
-
- }
- private string StringFromBuffer
- {
- get
- {
- return new string(stringBuffer, 0, stringBufferTop);
- }
-
- }
- private int Char
- {
- get
- {
- if (ungetCursor != 0)
- {
- return ungetBuffer[--ungetCursor];
- }
-
- for (; ; )
- {
- int c;
- if (sourceString != null)
- {
- if (sourceCursor == sourceEnd)
- {
- hitEOF = true;
- return EOF_CHAR;
- }
- c = sourceString[sourceCursor++];
- }
- else
- {
- if (sourceCursor == sourceEnd)
- {
- if (!fillSourceBuffer())
- {
- hitEOF = true;
- return EOF_CHAR;
- }
- }
- c = sourceBuffer[sourceCursor++];
- }
-
- if (lineEndChar >= 0)
- {
- if (lineEndChar == '\r' && c == '\n')
- {
- lineEndChar = '\n';
- continue;
- }
- lineEndChar = -1;
- lineStart = sourceCursor - 1;
- lineno++;
- }
-
- if (c <= 127)
- {
- if (c == '\n' || c == '\r')
- {
- lineEndChar = c;
- c = '\n';
- }
- }
- else
- {
- if (isJSFormatChar(c))
- {
- continue;
- }
- if (ScriptRuntime.isJSLineTerminator(c))
- {
- lineEndChar = c;
- c = '\n';
- }
- }
- return c;
- }
- }
-
- }
- internal int Offset
- {
- get
- {
- int n = sourceCursor - lineStart;
- if (lineEndChar >= 0)
- {
- --n;
- }
- return n;
- }
-
- }
- internal string Line
- {
- get
- {
- if (sourceString != null)
- {
- // String case
- int lineEnd = sourceCursor;
- if (lineEndChar >= 0)
- {
- --lineEnd;
- }
- else
- {
- for (; lineEnd != sourceEnd; ++lineEnd)
- {
- int c = sourceString[lineEnd];
- if (ScriptRuntime.isJSLineTerminator(c))
- {
- break;
- }
- }
- }
- return sourceString.Substring(lineStart, (lineEnd) - (lineStart));
- }
- else
- {
- // Reader case
- int lineLength = sourceCursor - lineStart;
- if (lineEndChar >= 0)
- {
- --lineLength;
- }
- else
- {
- // Read until the end of line
- for (; ; ++lineLength)
- {
- int i = lineStart + lineLength;
- if (i == sourceEnd)
- {
- try
- {
- if (!fillSourceBuffer())
- {
- break;
- }
- }
- catch (System.IO.IOException)
- {
- // ignore it, we're already displaying an error...
- break;
- }
- // i recalculuation as fillSourceBuffer can move saved
- // line buffer and change lineStart
- i = lineStart + lineLength;
- }
- int c = sourceBuffer[i];
- if (ScriptRuntime.isJSLineTerminator(c))
- {
- break;
- }
- }
- }
- return new string(sourceBuffer, lineStart, lineLength);
- }
- }
-
- }
- /*
- * For chars - because we need something out-of-range
- * to check. (And checking EOF by exception is annoying.)
- * Note distinction from EOF token type!
- */
- private const int EOF_CHAR = -1;
-
-
- internal TokenStream(Parser parser, System.IO.StreamReader sourceReader, string sourceString, int lineno)
- {
- this.parser = parser;
- this.lineno = lineno;
- if (sourceReader != null)
- {
- if (sourceString != null)
- Context.CodeBug();
- this.sourceReader = sourceReader;
- this.sourceBuffer = new char[512];
- this.sourceEnd = 0;
- }
- else
- {
- if (sourceString == null)
- Context.CodeBug();
- this.sourceString = sourceString;
- this.sourceEnd = sourceString.Length;
- }
- this.sourceCursor = 0;
- }
-
- /* This function uses the cached op, string and number fields in
- * TokenStream; if getToken has been called since the passed token
- * was scanned, the op or string printed may be incorrect.
- */
- internal string tokenToString(int token)
- {
- if (EcmaScript.NET.Token.printTrees)
- {
- string name = EcmaScript.NET.Token.name(token);
-
- switch (token)
- {
-
- case EcmaScript.NET.Token.STRING:
- case EcmaScript.NET.Token.REGEXP:
- case EcmaScript.NET.Token.NAME:
- return name + " `" + this.str + "'";
-
-
- case EcmaScript.NET.Token.NUMBER:
- return "NUMBER " + this.dNumber;
- }
-
- return name;
- }
- return "";
- }
-
- internal static bool isKeyword(string s)
- {
- return EcmaScript.NET.Token.EOF != stringToKeyword(s);
- }
-
- #region Ids
- private const int Id_break = EcmaScript.NET.Token.BREAK;
- private const int Id_case = EcmaScript.NET.Token.CASE;
- private const int Id_continue = EcmaScript.NET.Token.CONTINUE;
- private const int Id_default = EcmaScript.NET.Token.DEFAULT;
- private const int Id_delete = EcmaScript.NET.Token.DELPROP;
- private const int Id_do = EcmaScript.NET.Token.DO;
- private const int Id_else = EcmaScript.NET.Token.ELSE;
- private const int Id_export = EcmaScript.NET.Token.EXPORT;
- private const int Id_false = EcmaScript.NET.Token.FALSE;
- private const int Id_for = EcmaScript.NET.Token.FOR;
- private const int Id_function = EcmaScript.NET.Token.FUNCTION;
- private const int Id_if = EcmaScript.NET.Token.IF;
- private const int Id_in = EcmaScript.NET.Token.IN;
- private const int Id_new = EcmaScript.NET.Token.NEW;
- private const int Id_null = EcmaScript.NET.Token.NULL;
- private const int Id_return = EcmaScript.NET.Token.RETURN;
- private const int Id_switch = EcmaScript.NET.Token.SWITCH;
- private const int Id_this = EcmaScript.NET.Token.THIS;
- private const int Id_true = EcmaScript.NET.Token.TRUE;
- private const int Id_typeof = EcmaScript.NET.Token.TYPEOF;
- private const int Id_var = EcmaScript.NET.Token.VAR;
- private const int Id_void = EcmaScript.NET.Token.VOID;
- private const int Id_while = EcmaScript.NET.Token.WHILE;
- private const int Id_with = EcmaScript.NET.Token.WITH;
- private const int Id_abstract = EcmaScript.NET.Token.RESERVED;
- private const int Id_boolean = EcmaScript.NET.Token.RESERVED;
- private const int Id_byte = EcmaScript.NET.Token.RESERVED;
- private const int Id_catch = EcmaScript.NET.Token.CATCH;
- private const int Id_char = EcmaScript.NET.Token.RESERVED;
- private const int Id_class = EcmaScript.NET.Token.RESERVED;
- private const int Id_const = EcmaScript.NET.Token.RESERVED;
- private const int Id_debugger = EcmaScript.NET.Token.DEBUGGER;
- private const int Id_double = EcmaScript.NET.Token.RESERVED;
- private const int Id_enum = EcmaScript.NET.Token.RESERVED;
- private const int Id_extends = EcmaScript.NET.Token.RESERVED;
- private const int Id_final = EcmaScript.NET.Token.RESERVED;
- private const int Id_finally = EcmaScript.NET.Token.FINALLY;
- private const int Id_float = EcmaScript.NET.Token.RESERVED;
- private const int Id_goto = EcmaScript.NET.Token.RESERVED;
- private const int Id_implements = EcmaScript.NET.Token.RESERVED;
- private const int Id_import = EcmaScript.NET.Token.IMPORT;
- private const int Id_instanceof = EcmaScript.NET.Token.INSTANCEOF;
- private const int Id_int = EcmaScript.NET.Token.RESERVED;
- private const int Id_interface = EcmaScript.NET.Token.RESERVED;
- private const int Id_long = EcmaScript.NET.Token.RESERVED;
- private const int Id_native = EcmaScript.NET.Token.RESERVED;
- private const int Id_package = EcmaScript.NET.Token.RESERVED;
- private const int Id_private = EcmaScript.NET.Token.RESERVED;
- private const int Id_protected = EcmaScript.NET.Token.RESERVED;
- private const int Id_public = EcmaScript.NET.Token.RESERVED;
- private const int Id_short = EcmaScript.NET.Token.RESERVED;
- private const int Id_static = EcmaScript.NET.Token.RESERVED;
- private const int Id_super = EcmaScript.NET.Token.RESERVED;
- private const int Id_synchronized = EcmaScript.NET.Token.RESERVED;
- private const int Id_throw = EcmaScript.NET.Token.THROW;
- private const int Id_throws = EcmaScript.NET.Token.RESERVED;
- private const int Id_transient = EcmaScript.NET.Token.RESERVED;
- private const int Id_try = EcmaScript.NET.Token.TRY;
- private const int Id_volatile = EcmaScript.NET.Token.RESERVED;
- #endregion
-
- private static int stringToKeyword(string name)
- {
- // The following assumes that EcmaScript.NET.Token.EOF == 0
- int id;
- string s = name;
- #region Generated Id Switch
- L0:
- {
- id = 0;
- string X = null;
- int c;
- L:
- switch (s.Length)
- {
- case 2:
- c = s[1];
- if (c == 'f') { if (s[0] == 'i') { id = Id_if; goto EL0; } }
- else if (c == 'n') { if (s[0] == 'i') { id = Id_in; goto EL0; } }
- else if (c == 'o') { if (s[0] == 'd') { id = Id_do; goto EL0; } }
- break;
- case 3:
- switch (s[0])
- {
- case 'f':
- if (s[2] == 'r' && s[1] == 'o') { id = Id_for; goto EL0; }
- break;
- case 'i':
- if (s[2] == 't' && s[1] == 'n') { id = Id_int; goto EL0; }
- break;
- case 'n':
- if (s[2] == 'w' && s[1] == 'e') { id = Id_new; goto EL0; }
- break;
- case 't':
- if (s[2] == 'y' && s[1] == 'r') { id = Id_try; goto EL0; }
- break;
- case 'v':
- if (s[2] == 'r' && s[1] == 'a') { id = Id_var; goto EL0; }
- break;
- }
- break;
- case 4:
- switch (s[0])
- {
- case 'b':
- X = "byte";
- id = Id_byte;
- break;
- case 'c':
- c = s[3];
- if (c == 'e') { if (s[2] == 's' && s[1] == 'a') { id = Id_case; goto EL0; } }
- else if (c == 'r') { if (s[2] == 'a' && s[1] == 'h') { id = Id_char; goto EL0; } }
- break;
- case 'e':
- c = s[3];
- if (c == 'e') { if (s[2] == 's' && s[1] == 'l') { id = Id_else; goto EL0; } }
- else if (c == 'm') { if (s[2] == 'u' && s[1] == 'n') { id = Id_enum; goto EL0; } }
- break;
- case 'g':
- X = "goto";
- id = Id_goto;
- break;
- case 'l':
- X = "long";
- id = Id_long;
- break;
- case 'n':
- X = "null";
- id = Id_null;
- break;
- case 't':
- c = s[3];
- if (c == 'e') { if (s[2] == 'u' && s[1] == 'r') { id = Id_true; goto EL0; } }
- else if (c == 's') { if (s[2] == 'i' && s[1] == 'h') { id = Id_this; goto EL0; } }
- break;
- case 'v':
- X = "void";
- id = Id_void;
- break;
- case 'w':
- X = "with";
- id = Id_with;
- break;
- }
- break;
- case 5:
- switch (s[2])
- {
- case 'a':
- X = "class";
- id = Id_class;
- break;
- case 'e':
- X = "break";
- id = Id_break;
- break;
- case 'i':
- X = "while";
- id = Id_while;
- break;
- case 'l':
- X = "false";
- id = Id_false;
- break;
- case 'n':
- c = s[0];
- if (c == 'c') { X = "const"; id = Id_const; }
- else if (c == 'f') { X = "final"; id = Id_final; }
- break;
- case 'o':
- c = s[0];
- if (c == 'f') { X = "float"; id = Id_float; }
- else if (c == 's') { X = "short"; id = Id_short; }
- break;
- case 'p':
- X = "super";
- id = Id_super;
- break;
- case 'r':
- X = "throw";
- id = Id_throw;
- break;
- case 't':
- X = "catch";
- id = Id_catch;
- break;
- }
- break;
- case 6:
- switch (s[1])
- {
- case 'a':
- X = "native";
- id = Id_native;
- break;
- case 'e':
- c = s[0];
- if (c == 'd') { X = "delete"; id = Id_delete; }
- else if (c == 'r') { X = "return"; id = Id_return; }
- break;
- case 'h':
- X = "throws";
- id = Id_throws;
- break;
- case 'm':
- X = "import";
- id = Id_import;
- break;
- case 'o':
- X = "double";
- id = Id_double;
- break;
- case 't':
- X = "static";
- id = Id_static;
- break;
- case 'u':
- X = "public";
- id = Id_public;
- break;
- case 'w':
- X = "switch";
- id = Id_switch;
- break;
- case 'x':
- X = "export";
- id = Id_export;
- break;
- case 'y':
- X = "typeof";
- id = Id_typeof;
- break;
- }
- break;
- case 7:
- switch (s[1])
- {
- case 'a':
- X = "package";
- id = Id_package;
- break;
- case 'e':
- X = "default";
- id = Id_default;
- break;
- case 'i':
- X = "finally";
- id = Id_finally;
- break;
- case 'o':
- X = "boolean";
- id = Id_boolean;
- break;
- case 'r':
- X = "private";
- id = Id_private;
- break;
- case 'x':
- X = "extends";
- id = Id_extends;
- break;
- }
- break;
- case 8:
- switch (s[0])
- {
- case 'a':
- X = "abstract";
- id = Id_abstract;
- break;
- case 'c':
- X = "continue";
- id = Id_continue;
- break;
- case 'd':
- X = "debugger";
- id = Id_debugger;
- break;
- case 'f':
- X = "function";
- id = Id_function;
- break;
- case 'v':
- X = "volatile";
- id = Id_volatile;
- break;
- }
- break;
- case 9:
- c = s[0];
- if (c == 'i') { X = "interface"; id = Id_interface; }
- else if (c == 'p') { X = "protected"; id = Id_protected; }
- else if (c == 't') { X = "transient"; id = Id_transient; }
- break;
- case 10:
- c = s[1];
- if (c == 'm') { X = "implements"; id = Id_implements; }
- else if (c == 'n') { X = "instanceof"; id = Id_instanceof; }
- break;
- case 12:
- X = "synchronized";
- id = Id_synchronized;
- break;
- }
- if (X != null && X != s && !X.Equals(s))
- id = 0;
- }
- EL0:
-
- #endregion
- if (id == 0)
- {
- return EcmaScript.NET.Token.EOF;
- }
- return id & 0xff;
- }
-
- internal bool eof()
- {
- return hitEOF;
- }
-
- private static bool isAlpha(int c)
- {
- // Use 'Z' < 'a'
- if (c <= 'Z')
- {
- return 'A' <= c;
- }
- else
- {
- return 'a' <= c && c <= 'z';
- }
- }
-
- internal static bool isDigit(int c)
- {
- return '0' <= c && c <= '9';
- }
-
- /* As defined in ECMA. jsscan.c uses C isspace() (which allows
- * \v, I think.) note that code in getChar() implicitly accepts
- * '\r' ==
- as well.
- */
- internal static bool isJSSpace(int c)
- {
- if (c <= 127)
- {
- return c == 0x20 || c == 0x9 || c == 0xC || c == 0xB;
- }
- else
- {
- return c == 0xA0 || (int)char.GetUnicodeCategory((char)c) == (sbyte)System.Globalization.UnicodeCategory.SpaceSeparator;
- }
- }
-
- private static bool isJSFormatChar(int c)
- {
- return c > 127 && (int)char.GetUnicodeCategory((char)c) == (sbyte)System.Globalization.UnicodeCategory.Format;
- }
-
- /// Parser calls the method when it gets / or /= in literal context.
- internal void readRegExp(int startToken)
- {
- stringBufferTop = 0;
- if (startToken == EcmaScript.NET.Token.ASSIGN_DIV)
- {
- // Miss-scanned /=
- addToString('=');
- }
- else
- {
- if (startToken != EcmaScript.NET.Token.DIV)
- Context.CodeBug();
- }
-
- int c;
- bool inClass = false;
- while ((c = Char) != '/' || inClass)
- {
- if (c == '\n' || c == EOF_CHAR)
- {
- ungetChar(c);
- throw parser.ReportError("msg.unterminated.re.lit");
- }
- if (c == '\\')
- {
- addToString(c);
- c = Char;
- }
- else if (c == '[')
- {
- inClass = true;
- }
- else if (c == ']')
- {
- inClass = false;
- }
-
- addToString(c);
- }
-
- int reEnd = stringBufferTop;
-
- while (true)
- {
- if (matchChar('g'))
- addToString('g');
- else if (matchChar('i'))
- addToString('i');
- else if (matchChar('m'))
- addToString('m');
- else
- break;
- }
-
- if (isAlpha(peekChar()))
- {
- throw parser.ReportError("msg.invalid.re.flag");
- }
-
- this.str = new string(stringBuffer, 0, reEnd);
- this.regExpFlags = new string(stringBuffer, reEnd, stringBufferTop - reEnd);
- }
-
- ///
- private bool readQuotedString(int quote)
- {
- for (int c = Char; c != EOF_CHAR; c = Char)
- {
- addToString(c);
- if (c == quote)
- return true;
- }
-
- stringBufferTop = 0; // throw away the string in progress
- this.str = null;
- parser.AddError("msg.XML.bad.form");
- return false;
- }
-
- ///
- private bool readXmlComment()
- {
- for (int c = Char; c != EOF_CHAR; )
- {
- addToString(c);
- if (c == '-' && peekChar() == '-')
- {
- c = Char;
- addToString(c);
- if (peekChar() == '>')
- {
- c = Char; // Skip >
- addToString(c);
- return true;
- }
- else
- {
- continue;
- }
- }
- c = Char;
- }
-
- stringBufferTop = 0; // throw away the string in progress
- this.str = null;
- parser.AddError("msg.XML.bad.form");
- return false;
- }
-
- ///
- private bool readCDATA()
- {
- for (int c = Char; c != EOF_CHAR; )
- {
- addToString(c);
- if (c == ']' && peekChar() == ']')
- {
- c = Char;
- addToString(c);
- if (peekChar() == '>')
- {
- c = Char; // Skip >
- addToString(c);
- return true;
- }
- else
- {
- continue;
- }
- }
- c = Char;
- }
-
- stringBufferTop = 0; // throw away the string in progress
- this.str = null;
- parser.AddError("msg.XML.bad.form");
- return false;
- }
-
- ///
- private bool readEntity()
- {
- int declTags = 1;
- for (int c = Char; c != EOF_CHAR; c = Char)
- {
- addToString(c);
- switch (c)
- {
-
- case '<':
- declTags++;
- break;
-
- case '>':
- declTags--;
- if (declTags == 0)
- return true;
- break;
- }
- }
-
- stringBufferTop = 0; // throw away the string in progress
- this.str = null;
- parser.AddError("msg.XML.bad.form");
- return false;
- }
-
- ///
- private bool readPI()
- {
- for (int c = Char; c != EOF_CHAR; c = Char)
- {
- addToString(c);
- if (c == '?' && peekChar() == '>')
- {
- c = Char; // Skip >
- addToString(c);
- return true;
- }
- }
-
- stringBufferTop = 0; // throw away the string in progress
- this.str = null;
- parser.AddError("msg.XML.bad.form");
- return false;
- }
-
- private void addToString(int c)
- {
- int N = stringBufferTop;
- if (N == stringBuffer.Length)
- {
- char[] tmp = new char[stringBuffer.Length * 4];
- Array.Copy(stringBuffer, 0, tmp, 0, N);
- stringBuffer = tmp;
- }
- stringBuffer[N] = (char)c;
- stringBufferTop = N + 1;
- }
-
- private void ungetChar(int c)
- {
- // can not unread past across line boundary
- if (ungetCursor != 0 && ungetBuffer[ungetCursor - 1] == '\n')
- Context.CodeBug();
- ungetBuffer[ungetCursor++] = c;
- }
-
- private bool matchChar(int test)
- {
- int c = Char;
- if (c == test)
- {
- return true;
- }
- else
- {
- ungetChar(c);
- return false;
- }
- }
-
- private int peekChar()
- {
- int c = Char;
- ungetChar(c);
- return c;
- }
-
- private void skipLine()
- {
- // skip to end of line
- int c;
- while ((c = Char) != EOF_CHAR && c != '\n')
- {
- }
- ungetChar(c);
- }
-
- private bool fillSourceBuffer()
- {
- if (sourceString != null)
- Context.CodeBug();
- if (sourceEnd == sourceBuffer.Length)
- {
- if (lineStart != 0)
- {
- Array.Copy(sourceBuffer, lineStart, sourceBuffer, 0, sourceEnd - lineStart);
- sourceEnd -= lineStart;
- sourceCursor -= lineStart;
- lineStart = 0;
- }
- else
- {
- char[] tmp = new char[sourceBuffer.Length * 2];
- Array.Copy(sourceBuffer, 0, tmp, 0, sourceEnd);
- sourceBuffer = tmp;
- }
- }
- int n = sourceReader.Read(sourceBuffer, sourceEnd, sourceBuffer.Length - sourceEnd);
- if (n <= 0)
- {
- return false;
- }
- sourceEnd += n;
- return true;
- }
-
- // stuff other than whitespace since start of line
- private bool dirtyLine;
-
- internal string regExpFlags;
-
-
- // Set this to an inital non-null value so that the Parser has
- // something to retrieve even if an error has occured and no
- // string is found. Fosters one class of error, but saves lots of
- // code.
- private string str = "";
- private double dNumber;
-
-
- private char[] stringBuffer = new char[128];
- private int stringBufferTop;
- private ObjToIntMap allStrings = new ObjToIntMap(50);
-
- // Room to backtrace from to < on failed match of the last - in