示例#1
0
            RuntimeObj BitwiseShiftRightUnsigned(RuntimeObj left, RuntimeObj right)
            {
                if (left == DoubleObj.Zero)
                {
                    return(left);
                }

                double dR = right.ToDouble();

                if (double.IsNaN(dR))
                {
                    return(left is DoubleObj ? left : DoubleObj.Create(left.ToDouble()));
                }
                int iShift = (dR < 0 ? (int)Math.Ceiling(dR) : (int)Math.Floor(dR)) % 64;

                if (iShift < 0)
                {
                    return(DoubleObj.Zero);
                }

                uint lN = (uint)JSSupport.ToInt64(left.ToDouble());

                if (lN == 0)
                {
                    return(DoubleObj.Zero);
                }

                return(DoubleObj.Create(lN >> iShift));
            }
示例#2
0
            RuntimeObj BitwiseShift(RuntimeObj val, RuntimeObj shift, bool right)
            {
                if (val == DoubleObj.Zero)
                {
                    return(val);
                }
                double dR = shift.ToDouble();
                int    iShift;

                if (double.IsNaN(dR) || (iShift = (dR < 0 ? (int)Math.Ceiling(dR) : (int)Math.Floor(dR)) % 64) == 0)
                {
                    return(val.ToValue() as DoubleObj ?? DoubleObj.Create(val.ToDouble()));
                }
                if (right && iShift < 0)
                {
                    return(DoubleObj.Zero);
                }
                int lN = JSSupport.ToInt32(val.ToDouble());

                if (lN == 0)
                {
                    return(DoubleObj.Zero);
                }
                return(DoubleObj.Create(right ? lN >> iShift : lN << iShift));
            }
        /// <summary>
        /// Default implementation of <see cref="IAccessorVisitor.Visit"/> that supports evaluation of intrinsic
        /// functions Number(), String(), Boolean().
        /// By overriding this any binding to to external objects can be achieved (recall to call this base
        /// method when overriding).
        /// </summary>
        /// <param name="frame">The current frame (gives access to the next frame if any).</param>
        public virtual PExpr Visit(IAccessorFrame frame)
        {
            IAccessorMemberFrame head = frame as IAccessorMemberFrame;

            // We can only handle member access at the root level:
            if (head == null)
            {
                return(frame.SetError());
            }

            // Lookup from the longest path to the head in registered objects:
            // more "precise" objects mask root ones.
            var deepestMemberFrame = frame.NextAccessors(true)
                                     .Select(f => f as IAccessorMemberFrame)
                                     .TakeWhile(f => f != null)
                                     .LastOrDefault();

            // We obtain at least the head, hence the do...while.
            do
            {
                RuntimeObj obj;
                if (_objects.TryGetValue(deepestMemberFrame.Expr.MemberFullName, out obj))
                {
                    return(deepestMemberFrame.SetResult(obj));
                }
                deepestMemberFrame = deepestMemberFrame.PrevMemberAccessor;
            }while(deepestMemberFrame != null);
            var s = frame.GetImplementationState(c =>
                                                 c.On("Number").OnCall((f, args) =>
            {
                if (args.Count == 0)
                {
                    return(f.SetResult(DoubleObj.Zero));
                }
                return(f.SetResult(args[0] as DoubleObj ?? DoubleObj.Create(args[0].ToDouble())));
            }
                                                                       )
                                                 .On("String").OnCall((f, args) =>
            {
                if (args.Count == 0)
                {
                    return(f.SetResult(StringObj.EmptyString));
                }
                return(f.SetResult(StringObj.Create(args[0].ToString())));
            })
                                                 .On("Boolean").OnCall((f, args) =>
            {
                return(f.SetResult(args.Count == 1 && args[0].ToBoolean() ? BooleanObj.True : BooleanObj.False));
            })
                                                 );

            return(s != null?s.Visit() : frame.SetError());
        }
        public RuntimeObj Create(object o)
        {
            if (o == null)
            {
                return(RuntimeObj.Null);
            }
            if (o is ValueType)
            {
                if (o is int)
                {
                    return(DoubleObj.Create((int)o));
                }
                if (o is double)
                {
                    return(DoubleObj.Create((double)o));
                }
                if (o is float)
                {
                    return(DoubleObj.Create((float)o));
                }
                if (o is bool)
                {
                    return((bool)o ? BooleanObj.True : BooleanObj.False);
                }
                return(new ExternalObjectObj(this, o));
            }
            string s = o as string;

            if (s != null)
            {
                return(StringObj.Create(s));
            }
            Delegate func = o as Delegate;

            if (func != null)
            {
                return(new NativeFunctionObj(func));
            }
            return(new ExternalObjectObj(this, o));
        }
 public PExpr Visit(ConstantExpr e)
 {
     if (e.Value == null)
     {
         return(new PExpr(RuntimeObj.Null));
     }
     if (e.Value is string)
     {
         return(new PExpr(StringObj.Create((string)e.Value)));
     }
     if (e == ConstantExpr.UndefinedExpr)
     {
         return(new PExpr(RuntimeObj.Undefined));
     }
     if (e.Value is double)
     {
         return(new PExpr(DoubleObj.Create((double)e.Value)));
     }
     if (e.Value is bool)
     {
         return(new PExpr((bool)e.Value ? BooleanObj.True : BooleanObj.False));
     }
     return(new PExpr(new RuntimeError(e, "Unsupported JS type: " + e.Value.GetType().Name)));
 }
示例#6
0
            protected override PExpr DoVisit()
            {
                if (IsPendingOrSignal(ref _operand, Expr.Operand))
                {
                    return(PendingOrSignal(_operand));
                }
                RefRuntimeObj r = _operand.Result as RefRuntimeObj;

                if (r == null)
                {
                    return(SetResult(new RuntimeError(Expr.Operand, "Invalid increment or decrement operand.")));
                }

                var newValue = DoubleObj.Create(_operand.Result.ToDouble() + (Expr.Plus ? 1.0 : -1.0));

                if (Expr.Prefix)
                {
                    return(SetResult(r.SetValue(Expr, newValue)));
                }
                var result = SetResult(r.Value);

                r.SetValue(Expr, newValue);
                return(result);
            }
示例#7
0
            protected override PExpr DoVisit()
            {
                if (IsPendingOrSignal(ref _left, Expr.Left))
                {
                    return(PendingOrSignal(_left));
                }

                // Do not evaluate right expression if it is useless: short-circuit boolean evaluation.
                if ((Expr.BinaryOperatorToken == TokenizerToken.And && !_left.Result.ToBoolean()) ||
                    (Expr.BinaryOperatorToken == TokenizerToken.Or && _left.Result.ToBoolean()))
                {
                    return(SetResult(_left.Result));
                }

                if (IsPendingOrSignal(ref _right, Expr.Right))
                {
                    return(PendingOrSignal(_right));
                }

                RuntimeObj left  = _left.Result;
                RuntimeObj right = _right.Result;

                // Right value is the result for And and Or.
                RuntimeObj result = right;

                if (Expr.BinaryOperatorToken != TokenizerToken.And && Expr.BinaryOperatorToken != TokenizerToken.Or)
                {
                    if ((Expr.BinaryOperatorToken & TokenizerToken.IsCompareOperator) != 0)
                    {
                        #region ==, <, >, <=, >=, !=
                        int compareValue;
                        switch ((int)Expr.BinaryOperatorToken & 15)
                        {
                        case (int)TokenizerToken.Greater & 15:
                        {
                            result = new RuntimeObjComparer(left, right).Compare(Global, out compareValue) && compareValue > 0 ? BooleanObj.True : BooleanObj.False;
                            break;
                        }

                        case (int)TokenizerToken.GreaterOrEqual & 15:
                        {
                            result = new RuntimeObjComparer(left, right).Compare(Global, out compareValue) && compareValue >= 0 ? BooleanObj.True : BooleanObj.False;
                            break;
                        }

                        case (int)TokenizerToken.Less & 15:
                        {
                            result = new RuntimeObjComparer(left, right).Compare(Global, out compareValue) && compareValue < 0 ? BooleanObj.True : BooleanObj.False;
                            break;
                        }

                        case (int)TokenizerToken.LessOrEqual & 15:
                        {
                            result = new RuntimeObjComparer(left, right).Compare(Global, out compareValue) && compareValue <= 0 ? BooleanObj.True : BooleanObj.False;
                            break;
                        }

                        case (int)TokenizerToken.Equal & 15:
                        {
                            result = new RuntimeObjComparer(left, right).AreEqualStrict(Global) ? BooleanObj.True : BooleanObj.False;
                            break;
                        }

                        case (int)TokenizerToken.Different & 15:
                        {
                            result = !new RuntimeObjComparer(left, right).AreEqualStrict(Global) ? BooleanObj.True : BooleanObj.False;
                            break;
                        }

                        default: throw UnsupportedOperatorException();
                        }
                        #endregion
                    }
                    else if ((Expr.BinaryOperatorToken & TokenizerToken.IsBinaryOperator) != 0)
                    {
                        #region |, ^, &, >>, <<, >>>, +, -, /, * and %.
                        switch ((int)Expr.BinaryOperatorToken & 15)
                        {
                        case (int)TokenizerToken.Plus & 15:
                        {
                            if (ReferenceEquals(left.Type, RuntimeObj.TypeNumber) && ReferenceEquals(right.Type, RuntimeObj.TypeNumber))
                            {
                                result = DoubleObj.Create(left.ToDouble() + right.ToDouble());
                            }
                            else
                            {
                                result = StringObj.Create(left.ToString() + right.ToString());
                            }
                            break;
                        }

                        case (int)TokenizerToken.Minus & 15:
                        {
                            result = DoubleObj.Create(left.ToDouble() - right.ToDouble());
                            break;
                        }

                        case (int)TokenizerToken.Mult & 15:
                        {
                            result = DoubleObj.Create(left.ToDouble() * right.ToDouble());
                            break;
                        }

                        case (int)TokenizerToken.Divide & 15:
                        {
                            result = DoubleObj.Create(left.ToDouble() / right.ToDouble());
                            break;
                        }

                        case (int)TokenizerToken.Modulo & 15:
                        {
                            if (right == DoubleObj.Zero || left == DoubleObj.NegativeInfinity || left == DoubleObj.Infinity)
                            {
                                result = DoubleObj.NaN;
                            }
                            else if (left == DoubleObj.NegativeInfinity || left == DoubleObj.Infinity)
                            {
                                result = right;
                            }
                            else
                            {
                                result = DoubleObj.Create(left.ToDouble() % right.ToDouble());
                            }
                            break;
                        }

                        case (int)TokenizerToken.BitwiseAnd & 15:
                        {
                            long l  = JSSupport.ToInt64(left.ToDouble());
                            long rO = JSSupport.ToInt64(right.ToDouble());
                            result = DoubleObj.Create(l & rO);
                            break;
                        }

                        case (int)TokenizerToken.BitwiseOr & 15:
                        {
                            long l  = JSSupport.ToInt64(left.ToDouble());
                            long rO = JSSupport.ToInt64(right.ToDouble());
                            result = DoubleObj.Create(l | rO);
                            break;
                        }

                        case (int)TokenizerToken.BitwiseXOr & 15:
                        {
                            long l  = JSSupport.ToInt64(left.ToDouble());
                            long rO = JSSupport.ToInt64(right.ToDouble());
                            result = DoubleObj.Create(l ^ rO);
                            break;
                        }

                        case (int)TokenizerToken.BitwiseShiftLeft & 15:
                        {
                            result = BitwiseShift(left, right, false);
                            break;
                        }

                        case (int)TokenizerToken.BitwiseShiftRight & 15:
                        {
                            result = BitwiseShift(left, right, true);
                            break;
                        }

                        case (int)TokenizerToken.BitwiseShiftRightNoSignBit & 15:
                        {
                            result = BitwiseShiftRightUnsigned(left, right);
                            break;
                        }

                        default: throw UnsupportedOperatorException();
                        }
                        #endregion
                    }
                    else
                    {
                        throw UnsupportedOperatorException();
                    }
                }
                return(SetResult(result));
            }
示例#8
0
            protected override PExpr DoVisit()
            {
                if (IsPendingOrSignal(ref _expression, Expr.Expression))
                {
                    RuntimeError e = _expression.AsErrorResult;
                    if (e != null &&
                        e.IsReferenceError &&
                        ((int)Expr.TokenType & 15) == ((int)TokenizerToken.TypeOf & 15))
                    {
                        return(SetResult(StringObj.Create(RuntimeObj.TypeUndefined)));
                    }
                    return(PendingOrSignal(_expression));
                }
                RuntimeObj result = _expression.Result;

                // Minus and Plus are classified as a binary operator.
                // Handle those special cases here.
                if (Expr.TokenType == TokenizerToken.Minus)
                {
                    result = DoubleObj.Create(-result.ToDouble());
                }
                else if (Expr.TokenType == TokenizerToken.Plus)
                {
                    result = DoubleObj.Create(result.ToDouble());
                }
                else
                {
                    switch ((int)Expr.TokenType & 15)
                    {
                    case (int)TokenizerToken.Not & 15:
                    {
                        result = result.ToBoolean() ? BooleanObj.False : BooleanObj.True;
                        break;
                    }

                    case (int)TokenizerToken.BitwiseNot & 15:
                    {
                        result = DoubleObj.Create(~JSSupport.ToInt64(result.ToDouble()));
                        break;
                    }

                    case (int)TokenizerToken.TypeOf & 15:
                    {
                        // Well known Javascript bug: typeof null === "object".
                        if (result == RuntimeObj.Null)
                        {
                            result = StringObj.Create(RuntimeObj.TypeObject);
                        }
                        else
                        {
                            result = StringObj.Create(result.Type);
                        }
                        break;
                    }

                    case (int)TokenizerToken.IndexOf & 15:
                    {
                        RefRuntimeIndexedObj iO = result as RefRuntimeIndexedObj;
                        if (iO == null)
                        {
                            result = new RuntimeError(Expr, "No associated index. indexof must be used on a foreach variable.");
                        }
                        else
                        {
                            result = iO.Index;
                        }
                        break;
                    }

                    case (int)TokenizerToken.Void & 15:
                    {
                        result = RuntimeObj.Undefined;
                        break;
                    }

                    default: throw UnsupportedOperatorException();
                    }
                }
                return(SetResult(result));
            }