123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- using Esprima.Ast;
- using Jint.Native;
- using Jint.Native.Array;
- using Jint.Native.Function;
- using Jint.Native.Iterator;
- using Jint.Runtime.Environments;
- namespace Jint.Runtime.Interpreter.Expressions
- {
- internal sealed class BindingPatternAssignmentExpression : JintExpression
- {
- private readonly BindingPattern _pattern;
- private readonly JintExpression _right;
- public BindingPatternAssignmentExpression(
- Engine engine,
- AssignmentExpression expression) : base(engine, expression)
- {
- _pattern = (BindingPattern) expression.Left;
- _right = Build(engine, expression.Right);
- }
- protected override object EvaluateInternal()
- {
- var rightValue = _right.GetValue();
- ProcessPatterns(_engine, _pattern, rightValue);
- return JsValue.Undefined;
- }
- internal static void ProcessPatterns(Engine engine, BindingPattern pattern, JsValue argument)
- {
- if (pattern is ArrayPattern ap)
- {
- HandleArrayPattern(engine, ap, argument);
- }
- else if (pattern is ObjectPattern op)
- {
- HandleObjectPattern(engine, op, argument);
- }
- }
- private static void HandleArrayPattern(Engine engine, ArrayPattern pattern, JsValue argument)
- {
- bool ConsumeFromIterator(IIterator it, out JsValue value, out bool done)
- {
- var item = it.Next();
- value = JsValue.Undefined;
- done = false;
- if (item.TryGetValue("done", out var d) && d.AsBoolean())
- {
- done = true;
- return false;
- }
- if (!item.TryGetValue("value", out value))
- {
- return false;
- }
- return true;
- }
- var obj = TypeConverter.ToObject(engine, argument);
- ArrayOperations arrayOperations = null;
- IIterator iterator = null;
- if (obj.IsArrayLike)
- {
- arrayOperations = ArrayOperations.For(obj);
- }
- else
- {
- if (!obj.TryGetIterator(engine, out iterator))
- {
- ExceptionHelper.ThrowTypeError(engine);
- return;
- }
- }
- bool iterationEnded = false;
- for (uint i = 0; i < pattern.Elements.Count; i++)
- {
- var left = pattern.Elements[(int) i];
- if (left is Identifier identifier)
- {
- JsValue value;
- if (arrayOperations != null)
- {
- arrayOperations.TryGetValue(i, out value);
- }
- else
- {
- if (!ConsumeFromIterator(iterator, out value, out iterationEnded))
- {
- break;
- }
- }
- AssignToIdentifier(engine, identifier.Name, value);
- }
- else if (left is BindingPattern bindingPattern)
- {
- JsValue value;
- if (arrayOperations != null)
- {
- arrayOperations.TryGetValue(i, out value);
- }
- else
- {
- value = iterator.Next();
- }
- ProcessPatterns(engine, bindingPattern, value);
- }
- else if (left is IArrayPatternElement arrayPatternElement)
- {
- if (arrayPatternElement is RestElement restElement)
- {
- ArrayInstance array;
- if (arrayOperations != null)
- {
- var length = arrayOperations.GetLength();
- array = engine.Array.ConstructFast(length - i);
- for (uint j = i; j < length; ++j)
- {
- arrayOperations.TryGetValue(j, out var indexValue);
- array.SetIndexValue(j - i, indexValue, updateLength: false);
- }
- }
- else
- {
- array = engine.Array.ConstructFast(0);
- var protocol = new ArrayConstructor.ArrayProtocol(engine, obj, array, iterator, null);
- protocol.Execute();
- }
- if (restElement.Argument is Esprima.Ast.Identifier leftIdentifier)
- {
- AssignToIdentifier(engine, leftIdentifier.Name, array);
- }
- else if (restElement.Argument is BindingPattern bp)
- {
- ProcessPatterns(engine, bp, array);
- }
- }
- else if (arrayPatternElement is AssignmentPattern assignmentPattern)
- {
- JsValue value;
- if (arrayOperations != null)
- {
- arrayOperations.TryGetValue(i, out value);
- }
- else
- {
- ConsumeFromIterator(iterator, out value, out iterationEnded);
- }
- if (value.IsUndefined()
- && assignmentPattern.Right is Expression expression)
- {
- var jintExpression = Build(engine, expression);
- value = jintExpression.GetValue();
- }
- if (assignmentPattern.Left is Identifier leftIdentifier)
- {
- if (assignmentPattern.Right.IsFunctionWithName())
- {
- ((FunctionInstance) value).SetFunctionName(leftIdentifier.Name);
- }
- AssignToIdentifier(engine, leftIdentifier.Name, value);
- }
- else if (assignmentPattern.Left is BindingPattern bp)
- {
- ProcessPatterns(engine, bp, value);
- }
- }
- else
- {
- ExceptionHelper.ThrowArgumentOutOfRangeException("pattern", "Unable to determine how to handle array pattern element");
- break;
- }
- }
- }
- if (!iterationEnded)
- {
- iterator?.Return();
- }
- }
- private static void HandleObjectPattern(Engine engine, ObjectPattern pattern, JsValue argument)
- {
- var source = TypeConverter.ToObject(engine, argument);
- for (uint i = 0; i < pattern.Properties.Count; i++)
- {
- var left = pattern.Properties[(int) i];
- string sourceKey;
- var identifier = left.Key as Identifier;
- if (identifier == null)
- {
- var keyExpression = Build(engine, left.Key);
- sourceKey = TypeConverter.ToPropertyKey(keyExpression.GetValue());
- }
- else
- {
- sourceKey = identifier.Name;
- }
- source.TryGetValue(sourceKey, out var value);
- if (left.Value is AssignmentPattern assignmentPattern)
- {
- if (value.IsUndefined() && assignmentPattern.Right is Expression expression)
- {
- var jintExpression = Build(engine, expression);
- value = jintExpression.GetValue();
- }
-
- if (assignmentPattern.Left is BindingPattern bp)
- {
- ProcessPatterns(engine, bp, value);
- continue;
- }
-
- var target = assignmentPattern.Left as Identifier ?? identifier;
- if (assignmentPattern.Right.IsFunctionWithName())
- {
- ((FunctionInstance) value).SetFunctionName(target.Name);
- }
- AssignToIdentifier(engine, target.Name, value);
- }
- else if (left.Value is BindingPattern bindingPattern)
- {
- ProcessPatterns(engine, bindingPattern, value);
- }
- else
- {
- var target = left.Value as Identifier ?? identifier;
- AssignToIdentifier(engine, target.Name, value);
- }
- }
- }
- private static void AssignToIdentifier(Engine engine,
- string name,
- JsValue rval)
- {
- var env = engine.ExecutionContext.LexicalEnvironment;
- var strict = StrictModeScope.IsStrictModeCode;
- if (LexicalEnvironment.TryGetIdentifierEnvironmentWithBindingValue(
- env,
- name,
- strict,
- out var environmentRecord,
- out _))
- {
- environmentRecord.SetMutableBinding(name, rval, strict);
- }
- else
- {
- env._record.CreateMutableBinding(name, rval);
- }
- }
- }
- }
|