Exemple #1
0
        public override bool HasInstance(ExecutionContext GLOBAL, object ident)
        {
            JSInstanceWrapper iw = ident as JSInstanceWrapper;

            if (iw == null)
            {
                return(false);
            }
            return(mThisType.IsAssignableFrom(iw.This.GetType()));
        }
Exemple #2
0
        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;
        }
Exemple #3
0
        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);
        }
Exemple #4
0
        //
        // 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);
        }