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)); }
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))); }
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); }
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)); }
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)); }