public override bool HasInstance(ExecutionContext GLOBAL, object ident) { JSInstanceWrapper iw = ident as JSInstanceWrapper; if (iw == null) { return(false); } return(mThisType.IsAssignableFrom(iw.This.GetType())); }
internal object execute(Node n, ExecutionContext x) { int i, j; List<Node> aNode; ExecutionContext sEcon; JSObjectBase jaa; JSObjectBase f, tVal; object r, s, u = null, v = null; Node tNode = null, rNode = null, uNode = null; bool matchDefault = false; bool switchLoop; if (TraceExec) System.Console.Write("Execute[" + n.ToString() + " => "); try { switch (n.type) { case TokenType.Function: if (n.functionForm != StatementForm.DECLARED_FORM) { if (n.name == null || n.name == "" || n.functionForm == StatementForm.STATEMENT_FORM) { v = new FunctionObject(GLOBAL, n, x.scope); if (n.functionForm == StatementForm.STATEMENT_FORM) x.scope.jobject.SetItem(GLOBAL, n.name, new JSSimpleProperty(n.name, v)); } else { tVal = new JSObject(); ExecutionContext tmp = x.scope; x.scope = new ExecutionContext(); x.scope.jobject = tVal; x.scope.parent = tmp; try { v = new FunctionObject(GLOBAL, n, x.scope); tVal.SetItem(GLOBAL, n.name, new JSSimpleProperty(n.name, v, true, true)); } finally { x.scope = x.scope.parent; } } } break; case TokenType.SCRIPT: tVal = x.scope.jobject; aNode = n.funDecls; for (i = 0, j = aNode.Count; i < j; i++) { s = aNode[i].name; f = new FunctionObject(GLOBAL, aNode[i], x.scope); tVal.SetItem(GLOBAL, s.ToString(), new JSSimpleProperty(s.ToString(), f, x.type != CodeType.EVAL_CODE)); } aNode = n.varDecls; for (i = 0, j = aNode.Count; i < j; i++) { uNode = aNode[i]; s = uNode.name; if (uNode.readOnly && tVal.HasOwnProperty(s.ToString())) { throw new TypeError ("Redeclaration of const " + s, uNode.filename, uNode.lineno); } if (uNode.readOnly || !tVal.HasOwnProperty(s.ToString())) { tVal.SetItem(GLOBAL, s.ToString(), new JSSimpleProperty(s.ToString(), JSUndefined.Undefined, x.type != CodeType.EVAL_CODE, uNode.readOnly)); } } // FALL THROUGH for (i = 0, j = n.Count; i < j; i++) execute(n[i], x); break; case TokenType.BLOCK: for (i = 0, j = n.Count; i < j; i++) execute(n[i], x); break; case TokenType.If: if (JSObject.ToBool(GLOBAL, execute(n.condition, x))) execute(n.thenPart, x); else if (n.elsePart != null) execute(n.elsePart, x); break; case TokenType.Switch: s = execute(n.discriminant, x); aNode = n.cases; Node tt; switchLoop = false; for (i = 0, j = aNode.Count; ; i++) { if (i == j) { if (n.defaultIndex >= 0) { i = n.defaultIndex - 1; // no case matched, do default matchDefault = true; continue; } break; // no default, exit switch_loop } tt = aNode[i]; // next case (might be default!) if (tt.type == TokenType.Case) { u = Reference.GetValue(GLOBAL, execute(tt.caseLabel, x)); } else { if (!matchDefault) // not defaulting, skip for now continue; u = s; // force match to do default } if (object.Equals(u, s)) { for (; ; ) { // this loop exits switch_loop if (tt.statements != null) { try { execute(tt.statements, x); } catch (BreakException) { if (x.target == n) { switchLoop = true; break; } else { throw; } } } if (++i == j) { switchLoop = true; break; } tNode = aNode[i]; } // NOT REACHED } if (switchLoop) break; } break; case TokenType.For: if (n.setup != null) Reference.GetValue(GLOBAL, execute(n.setup, x)); // FALL THROUGH while (n.condition == null || JSObject.ToBool(GLOBAL, Reference.GetValue(GLOBAL, execute(n.condition, x)))) { try { execute(n.body, x); } catch (BreakException) { if (x.target == n) break; throw; } catch (ContinueException) { if (x.target == n) { if (n.update != null) Reference.GetValue(GLOBAL, execute(n.update, x)); if (n.condition != null && !JSObject.ToBool(GLOBAL, Reference.GetValue(GLOBAL, execute(n.condition, x)))) break; else continue; } throw; } if (n.update != null) Reference.GetValue(GLOBAL, execute(n.update, x)); } break; case TokenType.While: while (n.condition != null || JSObject.ToBool(GLOBAL, Reference.GetValue(GLOBAL, execute(n.condition, x)))) { try { execute(n.body, x); } catch (BreakException) { if (x.target == n) break; throw; } catch (ContinueException) { if (x.target == n) continue; throw; } if (n.update != null) Reference.GetValue(GLOBAL, execute(n.update, x)); } break; case TokenType.FOR_IN: uNode = n.varDecl; if (uNode != null) execute(uNode, x); rNode = n.iterator; v = Reference.GetValue(GLOBAL, execute(n.jobject, x)); // ECMA deviation to track extant browser JS implementation behavior. tVal = JSObject.ToObject(GLOBAL, v); i = 0; jaa = new JSArray(GLOBAL); foreach (string ii in tVal.Properties) { string istr = (i++).ToString(); jaa.SetItem(GLOBAL, istr, new JSSimpleProperty(istr, ii)); } for (j = i, i = 0; i < j; i++) { Reference.PutValue(GLOBAL, execute(rNode, x), jaa.GetItem(GLOBAL, i.ToString()).GetValue(GLOBAL)); try { execute(n.body, x); } catch (BreakException) { if (x.target != n) break; throw; } catch (ContinueException) { if (x.target != n) continue; throw; } } break; case TokenType.Do: do { try { execute(n.body, x); } catch (BreakException) { if (x.target != n) break; throw; } catch (ContinueException) { if (x.target != n) continue; throw; } } while (JSObject.ToBool(GLOBAL, Reference.GetValue(GLOBAL, execute(n.condition, x)))); break; case TokenType.Break: x.target = n.target; throw new BreakException(); case TokenType.Continue: x.target = ((Node)n).target; throw new ContinueException(); case TokenType.Try: try { execute(n.tryBlock, x); } catch (Exception exn) { ThrownException ex = exn as ThrownException; object e; if (ex != null) e = ex.Value; else e = new JSInstanceWrapper(GLOBAL, exn); j = n.catchClauses.Count; x.result = JSUndefined.Undefined; for (i = 0; ; i++) { if (i == j) { throw; } tNode = n.catchClauses[i]; ExecutionContext xscope = new ExecutionContext(); xscope.jobject = new JSObject(); xscope.jobject.SetItem(GLOBAL, tNode.varName, new JSSimpleProperty(tNode.varName, e, false, false, true)); xscope.parent = x.scope; x.scope = xscope; try { if (tNode.guard != null && !JSObject.ToBool(GLOBAL, Reference.GetValue(GLOBAL, execute(tNode.guard, x)))) continue; execute(tNode.block, x); break; } finally { x.scope = x.scope.parent; } } } finally { if (n.finallyBlock != null) execute(n.finallyBlock, x); } break; case TokenType.Throw: x.result = Reference.GetValue(GLOBAL, execute(n.exception, x)); throw new ThrownException((double)(int)TokenType.Throw); case TokenType.Return: x.result = Reference.GetValue(GLOBAL, execute(n.valueNode, x)); throw new ReturnException(); case TokenType.With: { r = execute(n.jobject, x); tVal = JSObject.ToObject(GLOBAL, Reference.GetValue(GLOBAL, r)); ExecutionContext tmp = x.scope; x.scope = new ExecutionContext(); x.scope.jobject = tVal; x.scope.parent = tmp; try { execute(n.body, x); } finally { x.scope = x.scope.parent; } } break; case TokenType.Var: case TokenType.Const: for (i = 0, j = n.Count; i < j; i++) { uNode = n[i].initializer; if (uNode == null) continue; string identName = n[i].name; for (sEcon = x.scope; sEcon != null; sEcon = sEcon.parent) { if (sEcon.jobject.HasOwnProperty(identName)) break; } u = Reference.GetValue(GLOBAL, execute(uNode, x)); if (n.type == TokenType.Const) sEcon.jobject.SetItem(GLOBAL, identName, new JSSimpleProperty(identName, u, true, true, false)); else sEcon.jobject.SetItem(GLOBAL, identName, new JSSimpleProperty(identName, u)); } break; case TokenType.Debugger: throw new Exception("NYI: debugger"); case TokenType.SEMICOLON: if (n.expression != null) x.result = Reference.GetValue(GLOBAL, execute(n.expression, x)); break; case TokenType.LABEL: try { execute(n.statement, x); } catch (BreakException) { if (x.target != n) throw; } break; case TokenType.COMMA: for (i = 0, j = n.Count; i < j; i++) v = Reference.GetValue(GLOBAL, execute(n[i], x)); break; case TokenType.ASSIGN: r = execute(n[0], x); TokenType tok = jsdefs.tokenWords[n.value.ToString()]; v = Reference.GetValue(GLOBAL, execute(n[1], x)); if (tok != TokenType.ASSIGN) { u = Reference.GetValue(GLOBAL, r); if (tok != TokenType.PLUS) { double ld = JSObject.ToNumber(GLOBAL, u), bd = JSObject.ToNumber(GLOBAL, v); long laa = (long)ld, bb = (long)bd; int bint = (int)bb; switch (tok) { case TokenType.BITWISE_OR: ld = laa | bb; break; case TokenType.BITWISE_XOR: ld = laa ^ bb; break; case TokenType.BITWISE_AND: ld = laa & bb; break; case TokenType.LSH: ld = laa << bint; break; case TokenType.RSH: ld = laa >> bint; break; case TokenType.URSH: ld = ((uint)laa) >> bint; break; case TokenType.MINUS: ld = ld - bd; break; case TokenType.MUL: ld = ld * bd; break; case TokenType.DIV: ld = ld / bd; break; case TokenType.MOD: ld = laa % bb; break; } v = ld; } else { v = Add(u, v); } } Reference.PutValue(GLOBAL, r, v); break; case TokenType.HOOK: { object res1 = Reference.GetValue(GLOBAL, execute(n[0], x)); v = JSObject.ToBool(GLOBAL, res1) ? Reference.GetValue(GLOBAL, execute(n[1], x)) : Reference.GetValue(GLOBAL, execute(n[2], x)); } break; case TokenType.OR: { object res1 = Reference.GetValue(GLOBAL, execute(n[0], x)); v = JSObject.ToBool(GLOBAL, res1) ? res1 : Reference.GetValue(GLOBAL, execute(n[1], x)); } break; case TokenType.AND: { object res1 = Reference.GetValue(GLOBAL, execute(n[0], x)); v = JSObject.ToBool(GLOBAL, res1) ? Reference.GetValue(GLOBAL, execute(n[1], x)) : res1; } break; case TokenType.BITWISE_OR: v = (double)((int)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x))) | (int)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[1], x)))); break; case TokenType.BITWISE_XOR: v = (double)((int)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x))) ^ (int)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[1], x)))); break; case TokenType.BITWISE_AND: v = (double)((int)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x))) & (int)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[1], x)))); break; case TokenType.EQ: v = Reference.GetValue(GLOBAL, execute(n[0], x)); u = Reference.GetValue(GLOBAL, execute(n[1], x)); if ((v == null || v == JSUndefined.Undefined) && (u == null || u == JSUndefined.Undefined)) v = true; else v = JSObject.CompareTo(GLOBAL, v, u) == 0; break; case TokenType.NE: if (((u == null || u is JSUndefined) && (v != null && !(v is JSUndefined))) || ((v == null || v is JSUndefined) && (u != null && !(u is JSUndefined)))) return true; v = JSObject.CompareTo(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x)), Reference.GetValue(GLOBAL, execute(n[1], x))) != 0; break; case TokenType.STRICT_EQ: v = Object.ReferenceEquals(Reference.GetValue(GLOBAL, execute(n[0], x)), Reference.GetValue(GLOBAL, execute(n[1], x))); break; case TokenType.STRICT_NE: v = !Object.ReferenceEquals(Reference.GetValue(GLOBAL, execute(n[0], x)), Reference.GetValue(GLOBAL, execute(n[1], x))); break; case TokenType.LT: v = JSObject.CompareTo(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x)), Reference.GetValue(GLOBAL, execute(n[1], x))) == -1; break; case TokenType.LE: v = JSObject.CompareTo(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x)), Reference.GetValue(GLOBAL, execute(n[1], x))) != 1; break; case TokenType.GE: v = JSObject.CompareTo(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x)), Reference.GetValue(GLOBAL, execute(n[1], x))) != -1; break; case TokenType.GT: v = JSObject.CompareTo(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x)), Reference.GetValue(GLOBAL, execute(n[1], x))) == 1; break; case TokenType.In: v = execute(n[1], x); tVal = Reference.GetValue(GLOBAL, v) as JSObjectBase; if (tVal == null) throw new TypeError("invalid 'in' operand " + v.ToString()); v = tVal.HasProperty(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x)).ToString()); break; case TokenType.Instanceof: u = Reference.GetValue(GLOBAL, execute(n[0], x)); tVal = Reference.GetValue(GLOBAL, execute(n[1], x)) as JSObjectBase; if (tVal == null) throw new TypeError("Not an object in instanceof"); v = tVal.HasInstance(GLOBAL, u); break; case TokenType.LSH: v = (double)((int)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x))) << (int)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[1], x)))); break; case TokenType.RSH: v = (double)((int)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x))) >> (int)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[1], x)))); break; case TokenType.URSH: v = (double)((int)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x))) >> (int)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[1], x)))); break; case TokenType.PLUS: v = Add(Reference.GetValue(GLOBAL, execute(n[0], x)), Reference.GetValue(GLOBAL, execute(n[1], x))); break; case TokenType.MINUS: v = JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x))) - JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[1], x))); break; case TokenType.MUL: v = JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x))) * JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[1], x))); break; case TokenType.DIV: v = JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x))) / JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[1], x))); break; case TokenType.MOD: v = JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x))) % (long)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[1], x))); break; case TokenType.Delete: { u = execute((Node)n[0], x); Reference refer = u as Reference; if (refer != null) { v = refer.GetBase().Delete(refer.GetPropertyName()); } } break; case TokenType.Void: Reference.GetValue(GLOBAL, execute((Node)n[0], x)); v = JSUndefined.Undefined; break; case TokenType.Typeof: u = execute((Node)n[0], x); if (u is Reference) { Reference refer = (Reference)u; if (refer.GetBase() == null) { v = JSUndefined.Undefined; break; } u = Reference.GetValue(GLOBAL, refer); } v = JSObject.Typeof(u).ToLower(); break; case TokenType.NOT: v = !JSObject.ToBool(GLOBAL, Reference.GetValue(GLOBAL, execute((Node)n[0], x))); break; case TokenType.BITWISE_NOT: v = (double)~(long)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute((Node)n[0], x))); break; case TokenType.UNARY_PLUS: v = JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute((Node)n[0], x))); break; case TokenType.UNARY_MINUS: v = -JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute((Node)n[0], x))); break; case TokenType.INCREMENT: case TokenType.DECREMENT: { object t = execute(n[0], x); u = Reference.GetValue(GLOBAL, t); if (n.postfix) v = u; Reference.PutValue(GLOBAL, t, n.type == TokenType.INCREMENT ? JSObject.ToNumber(GLOBAL, u) + 1 : JSObject.ToNumber(GLOBAL, u) - 1); if (!n.postfix) v = u; } break; case TokenType.DOT: { r = execute((Node)n[0], x); object t = Reference.GetValue(GLOBAL, r); u = n[1].value; v = new Reference(JSObject.ToObject(GLOBAL, t), u.ToString()); } break; case TokenType.INDEX: { r = execute(n[0], x); object t = Reference.GetValue(GLOBAL, r); u = Reference.GetValue(GLOBAL, execute(n[1], x)); v = new Reference(JSObject.ToObject(GLOBAL, t), u.ToString()); } break; case TokenType.LIST: // Curse ECMA for specifying that arguments is not an Array object! tVal = new JSObject(); int k = 0; CollectArguments(tVal, n, ref k, x); tVal.SetItem(GLOBAL, "length", new JSSimpleProperty("length", (double)k)); v = tVal; break; case TokenType.CALL: { r = execute(n[0], x); JSObjectBase args = (JSObjectBase)execute(n[1], x); JSObjectBase fun = (JSObjectBase)Reference.GetValue(GLOBAL, r); tVal = (r is Reference) ? ((Reference)r).GetBase() : null; if (tVal is Activation) tVal = null; try { v = apply(true, fun, tVal, args, x); } catch (TypeError te) { if (r is Reference) throw new TypeError(((Reference)r).GetPropertyName() + ": " + te.Message); else throw; } } break; case TokenType.New: case TokenType.NEW_WITH_ARGS: { r = execute(n[0], x); JSObjectBase fun = (JSObjectBase)Reference.GetValue(GLOBAL, r); if (n.type == TokenType.New) { jaa = new JSArray(GLOBAL); } else { jaa = (JSObjectBase)execute(n[1], x); } v = fun.Construct(GLOBAL, jaa, x); } break; case TokenType.ARRAY_INIT: JSArray jaa1 = new JSArray(GLOBAL); for (i = 0, j = n.Count; i < j; i++) { if (n[i] != null) jaa1[i] = new JSSimpleProperty(i.ToString(), Reference.GetValue(GLOBAL, execute(n[i], x))); } jaa1.length = j; v = jaa1; break; case TokenType.OBJECT_INIT: tVal = new JSObject(); for (i = 0, j = n.Count; i < j; i++) { Node tx = n[i]; if (tx.type == TokenType.PROPERTY_INIT) { tVal.SetItem(GLOBAL, tx[0].value.ToString(), new JSSimpleProperty (tx[0].value.ToString(), Reference.GetValue(GLOBAL, execute(tx[1], x)))); } else { f = new FunctionObject(GLOBAL, tx, x.scope); string tname = tx.name; JSSimpleProperty prop; if (!tx.fields.TryGetValue(tname, out prop)) tx.fields[tname] = new JSSimpleProperty(tname, v); if (tx.type == TokenType.GETTER) prop.DefineGetter(new Thunk(tVal, f, x)); else prop.DefineSetter(new Thunk(tVal, f, x)); tVal.SetItem(GLOBAL, tname, prop); } } v = tVal; break; case TokenType.Null: v = null; break; case TokenType.This: v = x.thisOb; break; case TokenType.True: v = true; break; case TokenType.False: v = false; break; case TokenType.IDENTIFIER: { for (sEcon = x.scope; sEcon != null; sEcon = sEcon.parent) { if (sEcon.jobject != null && sEcon.jobject.HasProperty(GLOBAL, n.value.ToString())) break; } v = new Reference(sEcon != null ? sEcon.jobject : GLOBAL.jobject, n.value.ToString()); } break; case TokenType.NUMBER: case TokenType.STRING: case TokenType.REGEXP: v = n.value; break; case TokenType.GROUP: v = execute(n[0], x); break; default: throw new TypeError("PANIC: unknown operation " + n.type.ToString() + ": " + n.ToString()); } } catch (FalseReturn) { v = false; } catch (ContinueException) { throw; } catch (BreakException) { throw; } catch (ThrownException) { throw; } catch (ReturnException) { throw; } catch (Exception e) { throw new ScriptException(e.Message, n, e); } if (TraceExec) System.Console.WriteLine(v == null ? "(null)" : v.ToString() + " ]"); return v; }
internal object execute(Node n, ExecutionContext x) { int i, j; List <Node> aNode; ExecutionContext sEcon; JSObjectBase jaa; JSObjectBase f, tVal; object r, s, u = null, v = null; Node tNode = null, rNode = null, uNode = null; bool matchDefault = false; bool switchLoop; if (TraceExec) { UnityEngine.Debug.Log("Execute[" + n.ToString() + " => "); } try { switch (n.type) { case TokenType.Function: if (n.functionForm != StatementForm.DECLARED_FORM) { if (n.name == null || n.name == "" || n.functionForm == StatementForm.STATEMENT_FORM) { v = new FunctionObject(GLOBAL, n, x.scope); if (n.functionForm == StatementForm.STATEMENT_FORM) { x.scope.jobject.SetItem(GLOBAL, n.name, new JSSimpleProperty(n.name, v)); } } else { tVal = new JSObject(); ExecutionContext tmp = x.scope; x.scope = new ExecutionContext(); x.scope.jobject = tVal; x.scope.parent = tmp; try { v = new FunctionObject(GLOBAL, n, x.scope); tVal.SetItem(GLOBAL, n.name, new JSSimpleProperty(n.name, v, true, true)); } finally { x.scope = x.scope.parent; } } } break; case TokenType.SCRIPT: tVal = x.scope.jobject; aNode = n.funDecls; for (i = 0, j = aNode.Count; i < j; i++) { s = aNode[i].name; f = new FunctionObject(GLOBAL, aNode[i], x.scope); tVal.SetItem(GLOBAL, s.ToString(), new JSSimpleProperty(s.ToString(), f, x.type != CodeType.EVAL_CODE)); } aNode = n.varDecls; for (i = 0, j = aNode.Count; i < j; i++) { uNode = aNode[i]; s = uNode.name; if (uNode.readOnly && tVal.HasOwnProperty(s.ToString())) { throw new TypeError ("Redeclaration of const " + s, uNode.filename, uNode.lineno); } if (uNode.readOnly || !tVal.HasOwnProperty(s.ToString())) { tVal.SetItem(GLOBAL, s.ToString(), new JSSimpleProperty(s.ToString(), JSUndefined.Undefined, x.type != CodeType.EVAL_CODE, uNode.readOnly)); } } // FALL THROUGH for (i = 0, j = n.Count; i < j; i++) { execute(n[i], x); } break; case TokenType.BLOCK: for (i = 0, j = n.Count; i < j; i++) { execute(n[i], x); } break; case TokenType.If: if (JSObject.ToBool(GLOBAL, execute(n.condition, x))) { execute(n.thenPart, x); } else if (n.elsePart != null) { execute(n.elsePart, x); } break; case TokenType.Switch: s = Reference.GetValue(GLOBAL, execute(n.discriminant, x)); aNode = n.cases; Node tt; switchLoop = false; for (i = 0, j = aNode.Count; ; i++) { if (i == j) { if (n.defaultIndex >= 0) { i = n.defaultIndex - 1; // no case matched, do default matchDefault = true; continue; } break; // no default, exit switch_loop } tt = aNode[i]; // next case (might be default!) if (tt.type == TokenType.Case) { u = Reference.GetValue(GLOBAL, execute(tt.caseLabel, x)); } else { if (!matchDefault) // not defaulting, skip for now { continue; } u = s; // force match to do default } if (object.Equals(u, s)) { for (; ;) { // this loop exits switch_loop if (tt.statements != null) { try { execute(tt.statements, x); } catch (BreakException) { if (x.target == n) { switchLoop = true; break; } else { throw; } } } if (++i == j) { switchLoop = true; break; } tNode = aNode[i]; } // NOT REACHED } if (switchLoop) { break; } } break; case TokenType.For: if (n.setup != null) { Reference.GetValue(GLOBAL, execute(n.setup, x)); } // FALL THROUGH while (n.condition == null || JSObject.ToBool(GLOBAL, Reference.GetValue(GLOBAL, execute(n.condition, x)))) { try { execute(n.body, x); } catch (BreakException) { if (x.target == n) { break; } throw; } catch (ContinueException) { if (x.target == n) { if (n.update != null) { Reference.GetValue(GLOBAL, execute(n.update, x)); } if (n.condition != null && !JSObject.ToBool(GLOBAL, Reference.GetValue(GLOBAL, execute(n.condition, x)))) { break; } else { continue; } } throw; } if (n.update != null) { Reference.GetValue(GLOBAL, execute(n.update, x)); } } break; case TokenType.While: while (n.condition == null || JSObject.ToBool(GLOBAL, Reference.GetValue(GLOBAL, execute(n.condition, x)))) { try { execute(n.body, x); } catch (BreakException) { if (x.target == n) { break; } throw; } catch (ContinueException) { if (x.target == n) { continue; } throw; } if (n.update != null) { Reference.GetValue(GLOBAL, execute(n.update, x)); } } break; case TokenType.FOR_IN: uNode = n.varDecl; if (uNode != null) { execute(uNode, x); } rNode = n.iterator; v = Reference.GetValue(GLOBAL, execute(n.jobject, x)); // ECMA deviation to track extant browser JS implementation behavior. tVal = JSObject.ToObject(GLOBAL, v); i = 0; jaa = new JSArray(GLOBAL); foreach (string ii in tVal.Properties) { string istr = (i++).ToString(); jaa.SetItem(GLOBAL, istr, new JSSimpleProperty(istr, ii)); } for (j = i, i = 0; i < j; i++) { Reference.PutValue(GLOBAL, execute(rNode, x), jaa.GetItem(GLOBAL, i.ToString()).GetValue(GLOBAL)); try { execute(n.body, x); } catch (BreakException) { if (x.target == n) { break; } throw; } catch (ContinueException) { if (x.target == n) { continue; } throw; } } break; case TokenType.Do: do { try { execute(n.body, x); } catch (BreakException) { if (x.target != n) { break; } throw; } catch (ContinueException) { if (x.target != n) { continue; } throw; } } while (JSObject.ToBool(GLOBAL, Reference.GetValue(GLOBAL, execute(n.condition, x)))); break; case TokenType.Break: x.target = n.target; throw new BreakException(); case TokenType.Continue: x.target = ((Node)n).target; throw new ContinueException(); case TokenType.Try: try { execute(n.tryBlock, x); } catch (Exception exn) { ThrownException ex = exn as ThrownException; object e; if (ex != null) { e = ex.Value; } else { e = new JSInstanceWrapper(GLOBAL, exn); } j = n.catchClauses.Count; x.result = JSUndefined.Undefined; for (i = 0; ; i++) { if (i == j) { throw; } tNode = n.catchClauses[i]; ExecutionContext xscope = new ExecutionContext(); xscope.jobject = new JSObject(); xscope.jobject.SetItem(GLOBAL, tNode.varName, new JSSimpleProperty(tNode.varName, e, false, false, true)); xscope.parent = x.scope; x.scope = xscope; try { if (tNode.guard != null && !JSObject.ToBool(GLOBAL, Reference.GetValue(GLOBAL, execute(tNode.guard, x)))) { continue; } execute(tNode.block, x); break; } finally { x.scope = x.scope.parent; } } } finally { if (n.finallyBlock != null) { execute(n.finallyBlock, x); } } break; case TokenType.Throw: x.result = Reference.GetValue(GLOBAL, execute(n.exception, x)); throw new ThrownException((double)(int)TokenType.Throw); case TokenType.Return: x.result = n.valueNode == null ? JSUndefined.Undefined : Reference.GetValue(GLOBAL, execute(n.valueNode, x)); throw new ReturnException(); case TokenType.With: { r = execute(n.jobject, x); tVal = JSObject.ToObject(GLOBAL, Reference.GetValue(GLOBAL, r)); ExecutionContext tmp = x.scope; x.scope = new ExecutionContext(); x.scope.jobject = tVal; x.scope.parent = tmp; try { execute(n.body, x); } finally { x.scope = x.scope.parent; } } break; case TokenType.Var: case TokenType.Const: for (i = 0, j = n.Count; i < j; i++) { uNode = n[i].initializer; if (uNode == null) { continue; } string identName = n[i].name; for (sEcon = x.scope; sEcon != null; sEcon = sEcon.parent) { if (sEcon.jobject.HasOwnProperty(identName)) { break; } } u = Reference.GetValue(GLOBAL, execute(uNode, x)); if (n.type == TokenType.Const) { sEcon.jobject.SetItem(GLOBAL, identName, new JSSimpleProperty(identName, u, true, true, false)); } else { sEcon.jobject.SetItem(GLOBAL, identName, new JSSimpleProperty(identName, u)); } } break; case TokenType.Debugger: throw new Exception("NYI: debugger"); case TokenType.SEMICOLON: if (n.expression != null) { x.result = Reference.GetValue(GLOBAL, execute(n.expression, x)); } break; case TokenType.LABEL: try { execute(n.statement, x); } catch (BreakException) { if (x.target != n) { throw; } } break; case TokenType.COMMA: for (i = 0, j = n.Count; i < j; i++) { v = Reference.GetValue(GLOBAL, execute(n[i], x)); } break; case TokenType.ASSIGN: r = execute(n[0], x); TokenType tok = jsdefs.tokenWords[n.value.ToString()]; v = Reference.GetValue(GLOBAL, execute(n[1], x)); if (tok != TokenType.ASSIGN) { u = Reference.GetValue(GLOBAL, r); if (tok != TokenType.PLUS) { double ld = JSObject.ToNumber(GLOBAL, u), bd = JSObject.ToNumber(GLOBAL, v); long laa = (long)ld, bb = (long)bd; int bint = (int)bb; switch (tok) { case TokenType.BITWISE_OR: ld = laa | bb; break; case TokenType.BITWISE_XOR: ld = laa ^ bb; break; case TokenType.BITWISE_AND: ld = laa & bb; break; case TokenType.LSH: ld = laa << bint; break; case TokenType.RSH: ld = laa >> bint; break; case TokenType.URSH: ld = ((uint)laa) >> bint; break; case TokenType.MINUS: ld = ld - bd; break; case TokenType.MUL: ld = ld * bd; break; case TokenType.DIV: ld = ld / bd; break; case TokenType.MOD: ld = laa % bb; break; } v = ld; } else { v = Add(u, v); } } Reference.PutValue(GLOBAL, r, v); break; case TokenType.HOOK: { object res1 = Reference.GetValue(GLOBAL, execute(n[0], x)); v = JSObject.ToBool(GLOBAL, res1) ? Reference.GetValue(GLOBAL, execute(n[1], x)) : Reference.GetValue(GLOBAL, execute(n[2], x)); } break; case TokenType.OR: { object res1 = Reference.GetValue(GLOBAL, execute(n[0], x)); v = JSObject.ToBool(GLOBAL, res1) ? res1 : Reference.GetValue(GLOBAL, execute(n[1], x)); } break; case TokenType.AND: { object res1 = Reference.GetValue(GLOBAL, execute(n[0], x)); v = JSObject.ToBool(GLOBAL, res1) ? Reference.GetValue(GLOBAL, execute(n[1], x)) : res1; } break; case TokenType.BITWISE_OR: v = (double)((int)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x))) | (int)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[1], x)))); break; case TokenType.BITWISE_XOR: v = (double)((int)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x))) ^ (int)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[1], x)))); break; case TokenType.BITWISE_AND: v = (double)((int)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x))) & (int)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[1], x)))); break; case TokenType.EQ: v = Reference.GetValue(GLOBAL, execute(n[0], x)); u = Reference.GetValue(GLOBAL, execute(n[1], x)); if ((v == null || v == JSUndefined.Undefined) && (u == null || u == JSUndefined.Undefined)) { v = true; } else { v = JSObject.CompareTo(GLOBAL, v, u) == 0; } break; case TokenType.NE: if (((u == null || u is JSUndefined) && (v != null && !(v is JSUndefined))) || ((v == null || v is JSUndefined) && (u != null && !(u is JSUndefined)))) { return(true); } v = JSObject.CompareTo(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x)), Reference.GetValue(GLOBAL, execute(n[1], x))) != 0; break; case TokenType.STRICT_EQ: v = Object.Equals(Reference.GetValue(GLOBAL, execute(n[0], x)), Reference.GetValue(GLOBAL, execute(n[1], x))); break; case TokenType.STRICT_NE: v = !Object.Equals(Reference.GetValue(GLOBAL, execute(n[0], x)), Reference.GetValue(GLOBAL, execute(n[1], x))); break; case TokenType.LT: v = JSObject.CompareTo(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x)), Reference.GetValue(GLOBAL, execute(n[1], x))) == -1; break; case TokenType.LE: v = JSObject.CompareTo(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x)), Reference.GetValue(GLOBAL, execute(n[1], x))) != 1; break; case TokenType.GE: v = JSObject.CompareTo(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x)), Reference.GetValue(GLOBAL, execute(n[1], x))) != -1; break; case TokenType.GT: v = JSObject.CompareTo(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x)), Reference.GetValue(GLOBAL, execute(n[1], x))) == 1; break; case TokenType.In: v = execute(n[1], x); tVal = Reference.GetValue(GLOBAL, v) as JSObjectBase; if (tVal == null) { throw new TypeError("invalid 'in' operand " + v.ToString()); } v = tVal.HasProperty(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x)).ToString()); break; case TokenType.Instanceof: u = Reference.GetValue(GLOBAL, execute(n[0], x)); tVal = Reference.GetValue(GLOBAL, execute(n[1], x)) as JSObjectBase; if (tVal == null) { throw new TypeError("Not an object in instanceof"); } v = tVal.HasInstance(GLOBAL, u); break; case TokenType.LSH: v = (double)((int)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x))) << (int)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[1], x)))); break; case TokenType.RSH: v = (double)((int)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x))) >> (int)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[1], x)))); break; case TokenType.URSH: v = (double)((int)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x))) >> (int)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[1], x)))); break; case TokenType.PLUS: v = Add(Reference.GetValue(GLOBAL, execute(n[0], x)), Reference.GetValue(GLOBAL, execute(n[1], x))); break; case TokenType.MINUS: v = JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x))) - JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[1], x))); break; case TokenType.MUL: v = JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x))) * JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[1], x))); break; case TokenType.DIV: v = JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x))) / JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[1], x))); break; case TokenType.MOD: v = JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[0], x))) % (long)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute(n[1], x))); break; case TokenType.Delete: { u = execute((Node)n[0], x); Reference refer = u as Reference; if (refer != null) { v = refer.GetBase().Delete(refer.GetPropertyName()); } } break; case TokenType.Void: Reference.GetValue(GLOBAL, execute((Node)n[0], x)); v = JSUndefined.Undefined; break; case TokenType.Typeof: u = execute((Node)n[0], x); if (u is Reference) { Reference refer = (Reference)u; if (refer.GetBase() == null) { v = JSUndefined.Undefined; break; } u = Reference.GetValue(GLOBAL, refer); } v = JSObject.Typeof(u).ToLower(); break; case TokenType.NOT: v = !JSObject.ToBool(GLOBAL, Reference.GetValue(GLOBAL, execute((Node)n[0], x))); break; case TokenType.BITWISE_NOT: v = (double)~(long)JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute((Node)n[0], x))); break; case TokenType.UNARY_PLUS: v = JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute((Node)n[0], x))); break; case TokenType.UNARY_MINUS: v = -JSObject.ToNumber(GLOBAL, Reference.GetValue(GLOBAL, execute((Node)n[0], x))); break; case TokenType.INCREMENT: case TokenType.DECREMENT: { object t = execute(n[0], x); u = Reference.GetValue(GLOBAL, t); if (n.postfix) { v = u; } Reference.PutValue(GLOBAL, t, n.type == TokenType.INCREMENT ? JSObject.ToNumber(GLOBAL, u) + 1 : JSObject.ToNumber(GLOBAL, u) - 1); if (!n.postfix) { v = u; } } break; case TokenType.DOT: { r = execute((Node)n[0], x); object t = Reference.GetValue(GLOBAL, r); u = n[1].value; v = new Reference(JSObject.ToObject(GLOBAL, t), u.ToString()); } break; case TokenType.INDEX: { r = execute(n[0], x); object t = Reference.GetValue(GLOBAL, r); u = Reference.GetValue(GLOBAL, execute(n[1], x)); v = new Reference(JSObject.ToObject(GLOBAL, t), u.ToString()); } break; case TokenType.LIST: // Curse ECMA for specifying that arguments is not an Array object! tVal = new JSObject(); int k = 0; CollectArguments(tVal, n, ref k, x); tVal.SetItem(GLOBAL, "length", new JSSimpleProperty("length", (double)k)); v = tVal; break; case TokenType.CALL: { r = execute(n[0], x); JSObjectBase args = (JSObjectBase)execute(n[1], x); object o = Reference.GetValue(GLOBAL, r); if (Object.ReferenceEquals(o, JSUndefined.Undefined)) { throw new TypeError("Can't call undefined " + n[0].ToString() + " " + r); } JSObjectBase fun = (JSObjectBase)o; tVal = (r is Reference) ? ((Reference)r).GetBase() : null; if (tVal is Activation) { tVal = null; } try { v = apply(true, fun, tVal, args, x); } catch (TypeError te) { if (r is Reference) { throw new TypeError(((Reference)r).GetPropertyName() + ": " + te.Message); } else { throw; } } } break; case TokenType.New: case TokenType.NEW_WITH_ARGS: { r = execute(n[0], x); JSObjectBase fun = (JSObjectBase)Reference.GetValue(GLOBAL, r); if (n.type == TokenType.New) { jaa = new JSArray(GLOBAL); } else { jaa = (JSObjectBase)execute(n[1], x); } v = fun.Construct(GLOBAL, jaa, x); } break; case TokenType.ARRAY_INIT: JSArray jaa1 = new JSArray(GLOBAL); for (i = 0, j = n.Count; i < j; i++) { if (n[i] != null) { jaa1[i] = new JSSimpleProperty(i.ToString(), Reference.GetValue(GLOBAL, execute(n[i], x))); } } jaa1.length = j; v = jaa1; break; case TokenType.OBJECT_INIT: tVal = new JSObject(); for (i = 0, j = n.Count; i < j; i++) { Node tx = n[i]; if (tx.type == TokenType.PROPERTY_INIT) { tVal.SetItem(GLOBAL, tx[0].value.ToString(), new JSSimpleProperty (tx[0].value.ToString(), Reference.GetValue(GLOBAL, execute(tx[1], x)))); } else { f = new FunctionObject(GLOBAL, tx, x.scope); string tname = tx.name; JSSimpleProperty prop; if (!tx.fields.TryGetValue(tname, out prop)) { tx.fields[tname] = new JSSimpleProperty(tname, v); } if (tx.type == TokenType.GETTER) { prop.DefineGetter(new Thunk(tVal, f, x)); } else { prop.DefineSetter(new Thunk(tVal, f, x)); } tVal.SetItem(GLOBAL, tname, prop); } } v = tVal; break; case TokenType.Null: v = null; break; case TokenType.This: v = x.thisOb; break; case TokenType.True: v = true; break; case TokenType.False: v = false; break; case TokenType.IDENTIFIER: { for (sEcon = x.scope; sEcon != null; sEcon = sEcon.parent) { if (sEcon.jobject != null && sEcon.jobject.HasProperty(GLOBAL, n.value.ToString())) { break; } } v = new Reference(sEcon != null ? sEcon.jobject : GLOBAL.jobject, n.value.ToString()); } break; case TokenType.NUMBER: case TokenType.STRING: case TokenType.REGEXP: v = n.value; break; case TokenType.GROUP: v = execute(n[0], x); break; default: throw new TypeError("PANIC: unknown operation " + n.type.ToString() + ": " + n.ToString()); } } catch (FalseReturn) { v = false; } catch (ContinueException) { throw; } catch (BreakException) { throw; } catch (ThrownException) { throw; } catch (ReturnException) { throw; } catch (Exception e) { throw new ScriptException(e.Message, n, e); } if (TraceExec) { UnityEngine.Debug.Log(v == null ? "(null)" : v.ToString() + " ]"); } return(v); }
// // Basic matches // // The following requires double, float and decimal to be sorted before // integral types. We'll generally prefer using double, float or decimal // versions of a function to integral versions, due to javascript's // preference of double for numerics // // ParamsArrayAttribute <- stop loop, try to convert all remaining arguments // IsOptional <- undefined or null -> RawDefaultValue // IsOut or IsRef <- (Nullable?) // float ... double and decimal <- number // byte ... ulong <- number // char <- jsstring, length = 1 // string <- jsstring // Array <- jsarray (try to convert elements) // any kind of object <- IsAssignableFrom // bool <- almost anything // public static bool ConvertToType(ExecutionContext GLOBAL, object arg, Type argtype, out object result) { result = null; // Can't match: nonnumber into integral slot if (IsParamFloating(argtype)) { if (!(arg is double)) { return(false); } if (argtype == typeof(double)) { result = (double)arg; return(true); } else if (argtype == typeof(float)) { result = (float)(double)arg; return(true); } else if (argtype == typeof(decimal)) { result = (decimal)(double)arg; return(true); } else { return(false); } } if (IsParamIntegral(argtype)) { if (argtype == typeof(byte)) { result = (byte)(double)arg; return(true); } else if (argtype == typeof(short)) { result = (short)(double)arg; return(true); } else if (argtype == typeof(ushort)) { result = (ushort)(double)arg; return(true); } else if (argtype == typeof(int)) { result = (int)(double)arg; return(true); } else if (argtype == typeof(uint)) { result = (uint)(double)arg; return(true); } else if (argtype == typeof(long)) { result = (long)(double)arg; return(true); } else if (argtype == typeof(ulong)) { result = (ulong)(double)arg; return(true); } else { return(false); } } if (argtype == typeof(char)) { string str = arg as string; if (arg is double) { result = (char)(double)arg; return(true); } else if (str != null && str.Length == 1) { result = str[0]; return(true); } else { return(false); } } if (argtype == typeof(string)) { result = arg.ToString(); return(true); } if (argtype.IsArray) { JSArray ja = arg as JSArray; if (ja == null) { return(false); } Type eltType = argtype.GetElementType(); System.Collections.ArrayList lo = new System.Collections.ArrayList(); foreach (object aob in ja) { object obelt; if (!ConvertToType(GLOBAL, aob, eltType, out obelt)) { return(false); } lo.Add(obelt); } result = lo.ToArray(eltType); return(true); } if (argtype == typeof(DateTime)) { if (arg is JSDate) { result = ((JSDate)arg).Value; return(true); } else if (arg is DateTime) { result = arg; return(true); } else if (arg is long) { JSDate jd = new JSDate(GLOBAL); JSDate.setTime(jd, (long)arg); result = jd.Value; return(true); } else if (arg is double) { JSDate jd = new JSDate(GLOBAL); JSDate.setTime(jd, (long)((double)arg)); result = jd.Value; return(true); } else if (arg is decimal) { JSDate jd = new JSDate(GLOBAL); JSDate.setTime(jd, (long)((decimal)arg)); result = jd.Value; return(true); } else if (arg is JSInstanceWrapper) { JSInstanceWrapper iw = (JSInstanceWrapper)arg; if (iw.This is DateTime) { result = iw.This; return(true); } } } if (argtype == typeof(JSDate)) { if (arg is JSDate) { result = arg; return(true); } else if (arg is DateTime) { result = new JSDate(GLOBAL, (DateTime)arg); return(true); } else if (arg is long) { JSDate jd = new JSDate(GLOBAL); JSDate.setTime(jd, (long)arg); result = jd; return(true); } else if (arg is double) { JSDate jd = new JSDate(GLOBAL); JSDate.setTime(jd, (long)((double)arg)); result = jd; return(true); } else if (arg is decimal) { JSDate jd = new JSDate(GLOBAL); JSDate.setTime(jd, (long)((decimal)arg)); result = jd; return(true); } else if (arg is JSInstanceWrapper) { JSInstanceWrapper iw = (JSInstanceWrapper)arg; if (iw.This is DateTime) { result = new JSDate(GLOBAL, (DateTime)iw.This); return(true); } } } if (arg is JSInstanceWrapper) { JSInstanceWrapper wrapper = (JSInstanceWrapper)arg; if (!argtype.IsAssignableFrom(wrapper.This.GetType())) { return(false); } result = wrapper.This; return(true); } if (argtype == typeof(bool)) { string str = arg as string; if (arg is bool) { result = (bool)arg; } if (arg is double) { result = (double)arg != 0.0; } if (str != null) { result = str.ToString().Length != 0; } result = !(arg == null || arg == JSUndefined.Undefined); return(true); } return(false); }