123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- using Esprima.Ast;
- using Jint.Native;
- using Jint.Native.Function;
- using Jint.Runtime.Environments;
- using Jint.Runtime.References;
- namespace Jint.Runtime.Interpreter.Expressions
- {
- internal sealed class JintAssignmentExpression : JintExpression
- {
- private readonly JintExpression _left;
- private readonly JintExpression _right;
- private JintAssignmentExpression(Engine engine, AssignmentExpression expression) : base(engine, expression)
- {
- _left = Build(engine, (Expression) expression.Left);
- _right = Build(engine, expression.Right);
- }
- internal static JintExpression Build(Engine engine, AssignmentExpression expression)
- {
- if (expression.Operator == AssignmentOperator.Assign)
- {
- if (expression.Left is Expression)
- {
- return new SimpleAssignmentExpression(engine, expression);
- }
- if (expression.Left is BindingPattern)
- {
- return new BindingPatternAssignmentExpression(engine, expression);
- }
- }
- return new JintAssignmentExpression(engine, expression);
- }
- protected override object EvaluateInternal()
- {
- var lref = _left.Evaluate() as Reference ?? ExceptionHelper.ThrowReferenceError<Reference>(_engine);
- JsValue rval = _right.GetValue();
- JsValue lval = _engine.GetValue(lref, false);
- var expression = (AssignmentExpression) _expression;
- switch (expression.Operator)
- {
- case AssignmentOperator.PlusAssign:
- var lprim = TypeConverter.ToPrimitive(lval);
- var rprim = TypeConverter.ToPrimitive(rval);
- if (lprim.IsString() || rprim.IsString())
- {
- if (!(lprim is JsString jsString))
- {
- jsString = new JsString.ConcatenatedString(TypeConverter.ToString(lprim));
- }
- lval = jsString.Append(rprim);
- }
- else
- {
- lval = TypeConverter.ToNumber(lprim) + TypeConverter.ToNumber(rprim);
- }
- break;
- case AssignmentOperator.MinusAssign:
- lval = TypeConverter.ToNumber(lval) - TypeConverter.ToNumber(rval);
- break;
- case AssignmentOperator.TimesAssign:
- if (lval.IsUndefined() || rval.IsUndefined())
- {
- lval = Undefined.Instance;
- }
- else
- {
- lval = TypeConverter.ToNumber(lval) * TypeConverter.ToNumber(rval);
- }
- break;
- case AssignmentOperator.DivideAssign:
- lval = Divide(lval, rval);
- break;
- case AssignmentOperator.ModuloAssign:
- if (lval.IsUndefined() || rval.IsUndefined())
- {
- lval = Undefined.Instance;
- }
- else
- {
- lval = TypeConverter.ToNumber(lval) % TypeConverter.ToNumber(rval);
- }
- break;
- case AssignmentOperator.BitwiseAndAssign:
- lval = TypeConverter.ToInt32(lval) & TypeConverter.ToInt32(rval);
- break;
- case AssignmentOperator.BitwiseOrAssign:
- lval = TypeConverter.ToInt32(lval) | TypeConverter.ToInt32(rval);
- break;
- case AssignmentOperator.BitwiseXOrAssign:
- lval = TypeConverter.ToInt32(lval) ^ TypeConverter.ToInt32(rval);
- break;
- case AssignmentOperator.LeftShiftAssign:
- lval = TypeConverter.ToInt32(lval) << (int) (TypeConverter.ToUint32(rval) & 0x1F);
- break;
- case AssignmentOperator.RightShiftAssign:
- lval = TypeConverter.ToInt32(lval) >> (int) (TypeConverter.ToUint32(rval) & 0x1F);
- break;
- case AssignmentOperator.UnsignedRightShiftAssign:
- lval = (uint) TypeConverter.ToInt32(lval) >> (int) (TypeConverter.ToUint32(rval) & 0x1F);
- break;
- default:
- ExceptionHelper.ThrowNotImplementedException();
- return null;
- }
- _engine.PutValue(lref, lval);
- _engine._referencePool.Return(lref);
- return lval;
- }
- internal sealed class SimpleAssignmentExpression : JintExpression
- {
- private readonly JintExpression _left;
- private readonly JintExpression _right;
- private readonly JintIdentifierExpression _leftIdentifier;
- private readonly bool _evalOrArguments;
- private readonly ArrayPattern _arrayPattern;
- public SimpleAssignmentExpression(Engine engine, AssignmentExpression expression) : base(engine, expression)
- {
- if (expression.Left is ArrayPattern arrayPattern)
- {
- _arrayPattern = arrayPattern;
- }
- else
- {
- _left = Build(engine, (Expression) expression.Left);
- _leftIdentifier = _left as JintIdentifierExpression;
- _evalOrArguments = _leftIdentifier?.ExpressionName == KnownKeys.Eval
- || _leftIdentifier?.ExpressionName == KnownKeys.Arguments;
- }
- _right = Build(engine, expression.Right);
- }
- protected override object EvaluateInternal()
- {
- JsValue rval = null;
- if (_leftIdentifier != null)
- {
- rval = AssignToIdentifier(_engine, _leftIdentifier, _right, _evalOrArguments);
- }
- else if (_arrayPattern != null)
- {
- foreach (var element in _arrayPattern.Elements)
- {
- AssignToIdentifier(_engine, _leftIdentifier, _right, false);
- }
- }
- return rval ?? SetValue();
- }
- private JsValue SetValue()
- {
- // slower version
- var lref = _left.Evaluate() as Reference ?? ExceptionHelper.ThrowReferenceError<Reference>(_engine);
- lref.AssertValid(_engine);
- var rval = _right.GetValue();
- if (_right._expression.IsFunctionWithName())
- {
- ((FunctionInstance) rval).SetFunctionName(lref.GetReferencedName());
- }
- _engine.PutValue(lref, rval);
- _engine._referencePool.Return(lref);
- return rval;
- }
- internal static JsValue AssignToIdentifier(
- Engine engine,
- JintIdentifierExpression left,
- JintExpression right,
- bool hasEvalOrArguments)
- {
- var env = engine.ExecutionContext.LexicalEnvironment;
- var strict = StrictModeScope.IsStrictModeCode;
- if (LexicalEnvironment.TryGetIdentifierEnvironmentWithBindingValue(
- env,
- left.ExpressionName,
- strict,
- out var environmentRecord,
- out _))
- {
- if (strict && hasEvalOrArguments)
- {
- ExceptionHelper.ThrowSyntaxError(engine);
- }
- var rval = right.GetValue();
- if (right._expression.IsFunctionWithName())
- {
- ((FunctionInstance) rval).SetFunctionName(left.ExpressionName);
- }
- environmentRecord.SetMutableBinding(left.ExpressionName, rval, strict);
- return rval;
- }
- return null;
- }
- }
- }
- }
|