protected override Completion ExecuteInternal(EvaluationContext context) { EnvironmentRecord oldEnv = null; EnvironmentRecord loopEnv = null; var engine = context.Engine; if (_boundNames != null) { oldEnv = engine.ExecutionContext.LexicalEnvironment; loopEnv = JintEnvironment.NewDeclarativeEnvironment(engine, oldEnv); var loopEnvRec = loopEnv; var kind = _initStatement._statement.Kind; for (var i = 0; i < _boundNames.Count; i++) { var name = _boundNames[i]; if (kind == VariableDeclarationKind.Const) { loopEnvRec.CreateImmutableBinding(name, true); } else { loopEnvRec.CreateMutableBinding(name, false); } } engine.UpdateLexicalEnvironment(loopEnv); } try { if (_initExpression != null) { _initExpression?.GetValue(context); } else { _initStatement?.Execute(context); } return(ForBodyEvaluation(context)); } finally { if (oldEnv is not null) { engine.UpdateLexicalEnvironment(oldEnv); } } }
public override Completion GetValue(EvaluationContext context) { var engine = context.Engine; var funcEnv = JintEnvironment.NewDeclarativeEnvironment(engine, engine.ExecutionContext.LexicalEnvironment); var closure = new ScriptFunctionInstance( engine, _function, funcEnv, _function.ThisMode); closure.MakeConstructor(); if (_function.Name != null) { funcEnv.CreateMutableBindingAndInitialize(_function.Name, canBeDeleted: false, closure); } return(Completion.Normal(closure, _expression.Location)); }
protected override Completion ExecuteInternal(EvaluationContext context) { EnvironmentRecord oldEnv = null; var engine = context.Engine; if (_lexicalDeclarations != null) { oldEnv = engine.ExecutionContext.LexicalEnvironment; var blockEnv = JintEnvironment.NewDeclarativeEnvironment(engine, engine.ExecutionContext.LexicalEnvironment); JintStatementList.BlockDeclarationInstantiation(engine, blockEnv, _lexicalDeclarations); engine.UpdateLexicalEnvironment(blockEnv); } var blockValue = _statementList.Execute(context); if (oldEnv is not null) { engine.UpdateLexicalEnvironment(oldEnv); } return(blockValue); }
private void CreatePerIterationEnvironment(EvaluationContext context) { if (_boundNames == null || _boundNames.Count == 0) { return; } var engine = context.Engine; var lastIterationEnv = engine.ExecutionContext.LexicalEnvironment; var lastIterationEnvRec = lastIterationEnv; var outer = lastIterationEnv._outerEnv; var thisIterationEnv = JintEnvironment.NewDeclarativeEnvironment(engine, outer); for (var j = 0; j < _boundNames.Count; j++) { var bn = _boundNames[j]; var lastValue = lastIterationEnvRec.GetBindingValue(bn, true); thisIterationEnv.CreateMutableBindingAndInitialize(bn, false, lastValue); } engine.UpdateLexicalEnvironment(thisIterationEnv); }
/// <summary> /// https://tc39.es/ecma262/#sec-runtime-semantics-forin-div-ofheadevaluation-tdznames-expr-iterationkind /// </summary> private bool HeadEvaluation(EvaluationContext context, out IteratorInstance result) { var engine = context.Engine; var oldEnv = engine.ExecutionContext.LexicalEnvironment; var tdz = JintEnvironment.NewDeclarativeEnvironment(engine, oldEnv); if (_tdzNames != null) { var TDZEnvRec = tdz; foreach (var name in _tdzNames) { TDZEnvRec.CreateMutableBinding(name); } } engine.UpdateLexicalEnvironment(tdz); var exprValue = _right.GetValue(context).Value; engine.UpdateLexicalEnvironment(oldEnv); if (_iterationKind == IterationKind.Enumerate) { if (exprValue.IsNullOrUndefined()) { result = null; return(false); } var obj = TypeConverter.ToObject(engine.Realm, exprValue); result = new ObjectKeyVisitor(engine, obj); } else { result = exprValue as IteratorInstance ?? exprValue.GetIterator(engine.Realm); } return(true); }
public Completion Execute(EvaluationContext context, JsValue input) { if (!_initialized) { Initialize(context); _initialized = true; } var engine = context.Engine; JsValue v = Undefined.Instance; Location l = context.LastSyntaxNode.Location; JintSwitchCase defaultCase = null; bool hit = false; for (var i = 0; i < (uint)_jintSwitchBlock.Length; i++) { var clause = _jintSwitchBlock[i]; EnvironmentRecord oldEnv = null; if (clause.LexicalDeclarations != null) { oldEnv = engine.ExecutionContext.LexicalEnvironment; var blockEnv = JintEnvironment.NewDeclarativeEnvironment(engine, oldEnv); JintStatementList.BlockDeclarationInstantiation(engine, blockEnv, clause.LexicalDeclarations); engine.UpdateLexicalEnvironment(blockEnv); } if (clause.Test == null) { defaultCase = clause; } else { var clauseSelector = clause.Test.GetValue(context).Value; if (clauseSelector == input) { hit = true; } } if (hit && clause.Consequent != null) { var r = clause.Consequent.Execute(context); if (oldEnv is not null) { engine.UpdateLexicalEnvironment(oldEnv); } if (r.Type != CompletionType.Normal) { return(r); } l = r.Location; v = r.Value ?? Undefined.Instance; } } // do we need to execute the default case ? if (hit == false && defaultCase != null) { EnvironmentRecord oldEnv = null; if (defaultCase.LexicalDeclarations != null) { oldEnv = engine.ExecutionContext.LexicalEnvironment; var blockEnv = JintEnvironment.NewDeclarativeEnvironment(engine, oldEnv); JintStatementList.BlockDeclarationInstantiation(engine, blockEnv, defaultCase.LexicalDeclarations); engine.UpdateLexicalEnvironment(blockEnv); } var r = defaultCase.Consequent.Execute(context); if (oldEnv is not null) { engine.UpdateLexicalEnvironment(oldEnv); } if (r.Type != CompletionType.Normal) { return(r); } l = r.Location; v = r.Value ?? Undefined.Instance; } return(new Completion(CompletionType.Normal, v, null, l)); }
/// <summary> /// https://tc39.es/ecma262/#sec-runtime-semantics-forin-div-ofbodyevaluation-lhs-stmt-iterator-lhskind-labelset /// </summary> private Completion BodyEvaluation( EvaluationContext context, JintExpression lhs, JintStatement stmt, IteratorInstance iteratorRecord, IterationKind iterationKind, LhsKind lhsKind, IteratorKind iteratorKind = IteratorKind.Sync) { var engine = context.Engine; var oldEnv = engine.ExecutionContext.LexicalEnvironment; var v = Undefined.Instance; var destructuring = _destructuring; string lhsName = null; var completionType = CompletionType.Normal; var close = false; try { while (true) { EnvironmentRecord iterationEnv = null; if (!iteratorRecord.TryIteratorStep(out var nextResult)) { close = true; return(new Completion(CompletionType.Normal, v, null, Location)); } if (iteratorKind == IteratorKind.Async) { // nextResult = await nextResult; ExceptionHelper.ThrowNotImplementedException("await"); } var nextValue = nextResult.Get(CommonProperties.Value); close = true; var lhsRef = new ExpressionResult(); if (lhsKind != LhsKind.LexicalBinding) { if (!destructuring) { lhsRef = lhs.Evaluate(context); } } else { iterationEnv = JintEnvironment.NewDeclarativeEnvironment(engine, oldEnv); if (_tdzNames != null) { BindingInstantiation(iterationEnv); } engine.UpdateLexicalEnvironment(iterationEnv); if (!destructuring) { var identifier = (Identifier)((VariableDeclaration)_leftNode).Declarations[0].Id; lhsName ??= identifier.Name; lhsRef = new ExpressionResult(ExpressionCompletionType.Normal, engine.ResolveBinding(lhsName), identifier.Location); } } if (context.DebugMode) { context.Engine.DebugHandler.OnStep(_leftNode); } var status = new Completion(); if (!destructuring) { if (lhsRef.IsAbrupt()) { close = true; status = new Completion(lhsRef); } else if (lhsKind == LhsKind.LexicalBinding) { ((Reference)lhsRef.Value).InitializeReferencedBinding(nextValue); } else { engine.PutValue((Reference)lhsRef.Value, nextValue); } } else { status = BindingPatternAssignmentExpression.ProcessPatterns( context, _assignmentPattern, nextValue, iterationEnv, checkObjectPatternPropertyReference: _lhsKind != LhsKind.VarBinding); if (lhsKind == LhsKind.Assignment) { // DestructuringAssignmentEvaluation of assignmentPattern using nextValue as the argument. } else if (lhsKind == LhsKind.VarBinding) { // BindingInitialization for lhs passing nextValue and undefined as the arguments. } else { // BindingInitialization for lhs passing nextValue and iterationEnv as arguments } } if (status.IsAbrupt()) { engine.UpdateLexicalEnvironment(oldEnv); if (_iterationKind == IterationKind.AsyncIterate) { iteratorRecord.Close(status.Type); return(status); } if (iterationKind == IterationKind.Enumerate) { return(status); } iteratorRecord.Close(status.Type); return(status); } var result = stmt.Execute(context); engine.UpdateLexicalEnvironment(oldEnv); if (!ReferenceEquals(result.Value, null)) { v = result.Value; } if (result.Type == CompletionType.Break && (result.Target == null || result.Target == _statement?.LabelSet?.Name)) { completionType = CompletionType.Normal; return(new Completion(CompletionType.Normal, v, null, Location)); } if (result.Type != CompletionType.Continue || (result.Target != null && result.Target != _statement?.LabelSet?.Name)) { completionType = result.Type; if (result.IsAbrupt()) { close = true; return(result); } } } } catch { completionType = CompletionType.Throw; throw; } finally { if (close) { try { iteratorRecord.Close(completionType); } catch { // if we already have and exception, use it if (completionType != CompletionType.Throw) { throw; } } } engine.UpdateLexicalEnvironment(oldEnv); } }
/// <summary> /// https://tc39.es/ecma262/#sec-performeval /// </summary> public JsValue PerformEval(JsValue x, Realm callerRealm, bool strictCaller, bool direct) { if (!x.IsString()) { return(x); } var evalRealm = _realm; _engine._host.EnsureCanCompileStrings(callerRealm, evalRealm); var inFunction = false; var inMethod = false; var inDerivedConstructor = false; if (direct) { var thisEnvRec = _engine.ExecutionContext.GetThisEnvironment(); if (thisEnvRec is FunctionEnvironmentRecord functionEnvironmentRecord) { var F = functionEnvironmentRecord._functionObject; inFunction = true; inMethod = thisEnvRec.HasSuperBinding(); if (F._constructorKind == ConstructorKind.Derived) { inDerivedConstructor = true; } } } var parser = new JavaScriptParser(x.ToString(), ParserOptions); Script script = null; try { script = parser.ParseScript(strictCaller); } catch (ParserException e) { if (e.Description == Messages.InvalidLHSInAssignment) { ExceptionHelper.ThrowReferenceError(callerRealm, (string)null); } else { ExceptionHelper.ThrowSyntaxError(callerRealm, e.Message); } } var body = script.Body; if (body.Count == 0) { return(Undefined); } if (!inFunction) { // if body Contains NewTarget, throw a SyntaxError exception. } if (!inMethod) { // if body Contains SuperProperty, throw a SyntaxError exception. } if (!inDerivedConstructor) { // if body Contains SuperCall, throw a SyntaxError exception. } var strictEval = script.Strict || _engine._isStrict; var ctx = _engine.ExecutionContext; using (new StrictModeScope(strictEval)) { EnvironmentRecord lexEnv; EnvironmentRecord varEnv; PrivateEnvironmentRecord privateEnv; if (direct) { lexEnv = JintEnvironment.NewDeclarativeEnvironment(_engine, ctx.LexicalEnvironment); varEnv = ctx.VariableEnvironment; privateEnv = ctx.PrivateEnvironment; } else { lexEnv = JintEnvironment.NewDeclarativeEnvironment(_engine, evalRealm.GlobalEnv); varEnv = evalRealm.GlobalEnv; privateEnv = null; } if (strictEval) { varEnv = lexEnv; } // If ctx is not already suspended, suspend ctx. Engine.EnterExecutionContext(lexEnv, varEnv, evalRealm, privateEnv); try { Engine.EvalDeclarationInstantiation(script, varEnv, lexEnv, privateEnv, strictEval); var statement = new JintScript(script); var result = statement.Execute(_engine._activeEvaluationContext); var value = result.GetValueOrDefault(); if (result.Type == CompletionType.Throw) { var ex = new JavaScriptException(value).SetCallstack(_engine, result.Location); throw ex; } else { return(value); } } finally { Engine.LeaveExecutionContext(); } } }
protected override Completion ExecuteInternal(EvaluationContext context) { var engine = context.Engine; int callStackSizeBeforeExecution = engine.CallStack.Count; var b = _block.Execute(context); if (b.Type == CompletionType.Throw) { // initialize lazily if (_statement.Handler is not null && _catch is null) { _catch = Build(_statement.Handler.Body); } // execute catch if (_statement.Handler is not null) { // Quick-patch for call stack not being unwinded when an exception is caught. // Ideally, this should instead be solved by always popping the stack when returning // from a call, regardless of whether it throws (i.e. CallStack.Pop() in finally clause // in Engine.Call/Engine.Construct - however, that method currently breaks stack traces // in error messages. while (callStackSizeBeforeExecution < engine.CallStack.Count) { engine.CallStack.Pop(); } // https://tc39.es/ecma262/#sec-runtime-semantics-catchclauseevaluation var thrownValue = b.Value; var oldEnv = engine.ExecutionContext.LexicalEnvironment; var catchEnv = JintEnvironment.NewDeclarativeEnvironment(engine, oldEnv, catchEnvironment: true); var boundNames = new List <string>(); _statement.Handler.Param.GetBoundNames(boundNames); foreach (var argName in boundNames) { catchEnv.CreateMutableBinding(argName, false); } engine.UpdateLexicalEnvironment(catchEnv); var catchParam = _statement.Handler?.Param; catchParam.BindingInitialization(context, thrownValue, catchEnv); b = _catch.Execute(context); engine.UpdateLexicalEnvironment(oldEnv); } } if (_finalizer != null) { var f = _finalizer.Execute(context); if (f.Type == CompletionType.Normal) { return(b); } return(f.UpdateEmpty(Undefined.Instance)); } return(b.UpdateEmpty(Undefined.Instance)); }