public void ExecuteVariableDeclaration(RuntimeState state) { VariableDeclaration statement = (VariableDeclaration)state.arg; var declarationsCount = statement.Declarations.Count; if (state.stage < declarationsCount) { var declaration = statement.Declarations[(int)state.stage]; if (declaration.Init != null) { if (state.local == null) { if (state.calleeReturned) { state.calleeReturned = false; state.local = state.calleeReturnValue; } else { Call(_engine.EvaluateExpression, declaration.Id); return; } } if (state.calleeReturned) { state.calleeReturned = false; var lhs = (Reference)state.local; lhs.AssertValid(_engine); var value = _engine.GetValue(state.calleeReturnValue, true); _engine.PutValue(lhs, value); _engine._referencePool.Return(lhs); state.local = null; state.stage++; return; } else { Call(_engine.EvaluateExpression, declaration.Init); return; } } state.stage++; return; } else { Return(new Completion(CompletionType.Normal, Undefined.Instance, null)); return; } }
private void ExecuteStatement(RuntimeState state) { Statement statement = (Statement)state.arg; if (state.calleeReturned) { Return(state.calleeReturnValue); return; } Call(_engine.ExecuteStatement, statement); }
public void ExecuteProgram(RuntimeState state) { Program program = (Program)state.arg; if (state.calleeReturned) { Return(state.calleeReturnValue); return; } this.Call(ExecuteStatementList, program.Body); }
public void ExecuteBlockStatement(RuntimeState state) { BlockStatement blockStatement = (BlockStatement)state.arg; if (state.calleeReturned) { Return((Completion)state.calleeReturnValue); return; } Call(ExecuteStatementList, blockStatement.Body); return; }
public void ExecuteExpressionStatement(RuntimeState state) { ExpressionStatement expressionStatement = (ExpressionStatement)state.arg; if (state.calleeReturned) { Return(new Completion(CompletionType.Normal, _engine.GetValue(state.calleeReturnValue, true), null)); } else { Call(_engine.EvaluateExpression, expressionStatement.Expression); return; } }
/// <summary> /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.13 /// </summary> /// <param name="throwStatement"></param> /// <returns></returns> public void ExecuteThrowStatement(RuntimeState state) { ThrowStatement throwStatement = (ThrowStatement)state.arg; if (state.calleeReturned) { var jsValue = _engine.GetValue(state.calleeReturnValue, true); Return(new Completion(CompletionType.Throw, jsValue, null, throwStatement.Location)); return; } else { Call(_engine.EvaluateExpression, throwStatement.Argument); return; } }
public void ExecuteStatementList(RuntimeState state) { if (state.calleeReturned) { Return((Completion)state.calleeReturnValue); return; } var statementList = (List <StatementListItem>)state.arg; // optimize common case without loop if (statementList.Count == 1) { this.Call(ExecuteSingleStatement, (Statement)statementList[0]); } else { this.Call(ExecuteMultipleStatements, statementList); } }
public void ExecuteIfStatement(RuntimeState state) { IfStatement ifStatement = (IfStatement)state.arg; if (state.stage == 0) { if (state.calleeReturned) { state.calleeReturned = false; state.stage = 1; } else { Call(_engine.EvaluateExpression, ifStatement.Test); return; } } // Stage 1 if (state.calleeReturned) { Return(state.calleeReturnValue); return; } if (TypeConverter.ToBoolean(_engine.GetValue(state.calleeReturnValue, true))) { Call(_engine.ExecuteStatement, ifStatement.Consequent); } else if (ifStatement.Alternate != null) { Call(_engine.ExecuteStatement, ifStatement.Alternate); } else { Return(new Completion(CompletionType.Normal, null, null)); } return; }
public bool Step() { if (stack.Count == 0) { return(false); } RuntimeState current = stack.Peek(); try { current.Call(); } catch (JavaScriptException v) { var s = (Statement)current.arg; Return(new Completion(CompletionType.Throw, v.Error, null, v.Location ?? s?.Location)); } return(true); }
public void ExecuteLabeledStatement(RuntimeState state) { LabeledStatement labeledStatement = (LabeledStatement)state.arg; // TODO: Esprima added Statement.Label, maybe not necessary as this line is finding the // containing label and could keep a table per program with all the labels // labeledStatement.Body.LabelSet = labeledStatement.Label; if (state.calleeReturned) { Completion result = (Completion)state.calleeReturnValue; if (result.Type == CompletionType.Break && result.Identifier == labeledStatement.Label.Name) { var value = result.Value; Return(new Completion(CompletionType.Normal, value, null)); return; } Return(result); return; } Call(_engine.ExecuteStatement, labeledStatement.Body); }
/// <summary> /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.11 /// </summary> /// <param name="switchStatement"></param> /// <returns></returns> public void ExecuteSwitchStatement(RuntimeState state) { SwitchStatement switchStatement = (SwitchStatement)state.arg; if (state.stage == 0) { if (state.calleeReturned) { state.calleeReturned = false; state.stage = 1; var jsValue = _engine.GetValue(state.calleeReturnValue, true); ExecuteSwitchBlockArgs args = new ExecuteSwitchBlockArgs(); args.switchBlock = switchStatement.Cases; args.input = jsValue; Call(ExecuteSwitchBlock, args); return; } else { Call(_engine.EvaluateExpression, switchStatement.Discriminant); return; } } // Stage 1 if (state.calleeReturned) { Completion r = (Completion)state.calleeReturnValue; if (r.Type == CompletionType.Break && r.Identifier == switchStatement.LabelSet?.Name) { Return(new Completion(CompletionType.Normal, r.Value, null)); return; } Return(r); return; } }
/// <summary> /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.10 /// </summary> /// <param name="withStatement"></param> /// <returns></returns> public void ExecuteWithStatement(RuntimeState state) { WithStatement withStatement = (WithStatement)state.arg; ExecuteWithStatementLocal local = null; if (state.stage == 0) { if (state.calleeReturned) { state.calleeReturned = false; state.local = local = new ExecuteWithStatementLocal(); var jsValue = _engine.GetValue(state.calleeReturnValue, true); var obj = TypeConverter.ToObject(_engine, jsValue); local.oldEnv = _engine.ExecutionContext.LexicalEnvironment; var newEnv = LexicalEnvironment.NewObjectEnvironment(_engine, obj, local.oldEnv, true); _engine.UpdateLexicalEnvironment(newEnv); state.stage = 1; } else { Call(_engine.EvaluateExpression, withStatement.Object); return; } } // Stage 1 if (local == null) { local = (ExecuteWithStatementLocal)state.local; } if (state.calleeReturned) { _engine.UpdateLexicalEnvironment(local.oldEnv); Return(state.calleeReturnValue); return; } }
/// <summary> /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.9 /// </summary> /// <param name="statement"></param> /// <returns></returns> public void ExecuteReturnStatement(RuntimeState state) { ReturnStatement statement = (ReturnStatement)state.arg; if (statement.Argument == null) { Return(new Completion(CompletionType.Return, Undefined.Instance, null)); return; } if (state.calleeReturned) { var jsValue = _engine.GetValue(state.calleeReturnValue, true); Return(new Completion(CompletionType.Return, jsValue, null)); return; } else { Call(_engine.EvaluateExpression, statement.Argument); return; } }
/// <summary> /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.6.3 /// </summary> /// <param name="forStatement"></param> /// <returns></returns> public void ExecuteForStatement(RuntimeState state) { ForStatement forStatement = (ForStatement)state.arg; ExecuteForStatementLocal local; if (state.local == null) { state.local = local = new ExecuteForStatementLocal(); local.init = forStatement.Init; local.v = Undefined.Instance; local.stage = 0; } else { local = (ExecuteForStatementLocal)state.local; } if (local.stage == 0) { if (state.calleeReturned) { if (state.stage == 1) { _engine.GetValue(state.calleeReturnValue, true); } state.calleeReturned = false; state.calleeReturnValue = null; local.stage = 1; return; } if (local.init != null) { if (local.init.Type == Nodes.VariableDeclaration) { Call(_engine.ExecuteStatement, (Statement)local.init); return; } else { state.stage = 1; Call(_engine.EvaluateExpression, local.init); return; } } local.stage = 1; } if (local.stage == 1) { if (state.calleeReturned && state.stage != 10) { Completion stmt = (Completion)state.calleeReturnValue; state.calleeReturned = false; state.calleeReturnValue = null; if (!ReferenceEquals(stmt.Value, null)) { local.v = stmt.Value; } var stmtType = stmt.Type; if (stmtType == CompletionType.Break && (stmt.Identifier == null || stmt.Identifier == forStatement?.LabelSet?.Name)) { Return(new Completion(CompletionType.Normal, local.v, null)); return; } if (stmtType != CompletionType.Continue || ((stmt.Identifier != null) && stmt.Identifier != forStatement?.LabelSet?.Name)) { if (stmtType != CompletionType.Normal) { Return(stmt); return; } } if (forStatement.Update != null) { local.stage = 2; Call(_engine.EvaluateExpression, forStatement.Update); return; } } if (forStatement.Test != null) { if (state.calleeReturned) { state.stage = 0; state.calleeReturned = false; var testExprRef = state.calleeReturnValue; if (!TypeConverter.ToBoolean(_engine.GetValue(testExprRef, true))) { Return(new Completion(CompletionType.Normal, local.v, null)); return; } } else { Call(_engine.EvaluateExpression, forStatement.Test); state.stage = 10; return; } } Call(_engine.ExecuteStatement, forStatement.Body); return; } if (local.stage == 2) { if (state.calleeReturned) { state.calleeReturned = false; _engine.GetValue(state.calleeReturnValue, true); local.stage = 1; return; } } }
private void ExecuteMultipleStatements(RuntimeState state) { List <StatementListItem> statementList = (List <StatementListItem>)state.arg; ExecuteMultipleStatementsLocal local; if (state.local == null) { state.local = local = new ExecuteMultipleStatementsLocal(); local.c = new Completion(CompletionType.Normal, null, null); local.sl = local.c; local.statementListCount = statementList.Count; local.stage = 0; local.i = 0; } else { local = (ExecuteMultipleStatementsLocal)state.local; } if (local.stage == 0) // for loop { if (local.i < local.statementListCount) { local.stage = 1; } else { local.stage = 2; } } if (local.stage == 1) // inside for loop { if (state.calleeReturned) { local.c = (Completion)state.calleeReturnValue; if (local.c.Type != CompletionType.Normal) { var executeStatementList = new Completion( local.c.Type, local.c.Value ?? local.sl.Value, local.c.Identifier, local.c.Location); Return(executeStatementList); return; } local.sl = local.c; state.calleeReturned = false; local.i++; local.stage = 0; return; } Call(_engine.ExecuteStatement, (Statement)statementList[local.i]); return; } if (local.stage == 2) // after for loop { Return(new Completion(local.c.Type, local.c.GetValueOrDefault(), local.c.Identifier)); return; } }
public void ExecuteSwitchBlock(RuntimeState state) { ExecuteSwitchBlockArgs args = (ExecuteSwitchBlockArgs)state.arg; List <SwitchCase> switchBlock = args.switchBlock; JsValue input = args.input; ExecuteSwitchBlockLocal local; if (state.local == null) { state.local = local = new ExecuteSwitchBlockLocal(); local.v = Undefined.Instance; local.defaultCase = null; local.hit = false; local.switchBlockCount = switchBlock.Count; local.i = 0; local.stage = 0; } else { local = (ExecuteSwitchBlockLocal)state.local; } if (local.stage == 0) // for loop { if (local.i < local.switchBlockCount) { local.stage = 1; } else { local.stage = 2; } } if (local.stage == 1) // inside for loop { if (state.calleeReturned && state.stage != 10) { Completion r = (Completion)state.calleeReturnValue; if (r.Type != CompletionType.Normal) { Return(r); return; } local.v = r.Value ?? Undefined.Instance; } var clause = switchBlock[local.i]; if (clause.Test == null) { local.defaultCase = clause; } else { if (state.calleeReturned) { state.calleeReturned = false; state.stage = 0; var clauseSelector = _engine.GetValue(state.calleeReturnValue, true); if (ExpressionInterpreter.StrictlyEqual(clauseSelector, input)) { local.hit = true; } } else { state.stage = 10; Call(_engine.EvaluateExpression, clause.Test); return; } } if (local.hit && clause.Consequent != null) { Call(ExecuteStatementList, clause.Consequent); return; } local.i++; local.stage = 0; return; } if (local.stage == 2) { if (state.calleeReturned) { Completion r = (Completion)state.calleeReturnValue; if (r.Type != CompletionType.Normal) { Return(r); return; } local.v = r.Value ?? Undefined.Instance; } // do we need to execute the default case ? if (local.hit == false && local.defaultCase != null) { Call(ExecuteStatementList, local.defaultCase.Consequent); return; } Return(new Completion(CompletionType.Normal, local.v, null)); return; } }
/// <summary> /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.6.2 /// </summary> /// <param name="whileStatement"></param> /// <returns></returns> public void ExecuteWhileStatement(RuntimeState state) { WhileStatement whileStatement = (WhileStatement)state.arg; ExecuteWhileStatementLocal local; if (state.local == null) { state.local = local = new ExecuteWhileStatementLocal(); local.v = Undefined.Instance; } else { local = (ExecuteWhileStatementLocal)state.local; } if (state.stage == 0) { if (state.calleeReturned) { state.calleeReturned = false; state.stage = 1; var jsValue = _engine.GetValue(state.calleeReturnValue, true); if (!TypeConverter.ToBoolean(jsValue)) { Return(new Completion(CompletionType.Normal, local.v, null)); return; } } else { Call(_engine.EvaluateExpression, whileStatement.Test); return; } } // Stage 1 if (state.calleeReturned) { state.calleeReturned = false; var stmt = (Completion)state.calleeReturnValue; if (!ReferenceEquals(stmt.Value, null)) { local.v = stmt.Value; } if (stmt.Type != CompletionType.Continue || stmt.Identifier != whileStatement?.LabelSet?.Name) { if (stmt.Type == CompletionType.Break && (stmt.Identifier == null || stmt.Identifier == whileStatement?.LabelSet?.Name)) { Return(new Completion(CompletionType.Normal, local.v, null)); return; } if (stmt.Type != CompletionType.Normal) { Return(stmt); return; } } state.stage = 0; return; } Call(_engine.ExecuteStatement, whileStatement.Body); return; }
/// <summary> /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.6.4 /// </summary> /// <param name="forInStatement"></param> /// <returns></returns> public void ExecuteForInStatement(RuntimeState state) { ForInStatement forInStatement = (ForInStatement)state.arg; ExecuteForInStatementLocal local = null; if (state.stage == 0) { if (state.calleeReturned) { state.calleeReturned = false; local = (ExecuteForInStatementLocal)state.local; local.varRef = state.calleeReturnValue as Reference; state.stage = 1; } else { state.local = local = new ExecuteForInStatementLocal(); local.stage = 0; local.identifier = forInStatement.Left.Type == Nodes.VariableDeclaration ? (Identifier)((VariableDeclaration)forInStatement.Left).Declarations[0].Id : (Identifier)forInStatement.Left; Call(_engine.EvaluateExpression, local.identifier); return; } } if (local == null) { local = (ExecuteForInStatementLocal)state.local; } if (state.stage == 1) { if (state.calleeReturned) { state.calleeReturned = false; local.experValue = _engine.GetValue(state.calleeReturnValue, true); if (local.experValue.IsUndefined() || local.experValue.IsNull()) { Return(new Completion(CompletionType.Normal, null, null)); return; } local.obj = TypeConverter.ToObject(_engine, local.experValue); JsValue v = Null.Instance; // keys are constructed using the prototype chain local.cursor = local.obj; local.processedKeys = new HashSet <string>(); state.stage = 2; } else { Call(_engine.EvaluateExpression, forInStatement.Right); return; } } // Stage 2 if (state.calleeReturned) { Completion stmt = (Completion)state.calleeReturnValue; if (!ReferenceEquals(stmt.Value, null)) { local.v = stmt.Value; } if (stmt.Type == CompletionType.Break) { Return(new Completion(CompletionType.Normal, local.v, null)); return; } if (stmt.Type != CompletionType.Continue) { if (stmt.Type != CompletionType.Normal) { Return(stmt); return; } } } if (local.stage == 0) { if (!ReferenceEquals(local.cursor, null)) { Return(new Completion(CompletionType.Normal, local.v, null)); return; } local.stage = 1; return; } if (local.stage == 1) // While loop { local.keys = _engine.Object.GetOwnPropertyNames(Undefined.Instance, Arguments.From(local.cursor)).AsArray(); local.length = local.keys.GetLength(); local.i = 0; local.stage = 2; return; } if (local.stage == 2) // For loop { if (local.i < local.length) { local.stage = 3; } else { local.stage = 4; } } if (local.stage == 3) // For contents { if (state.calleeReturned) { local.i++; local.stage = 2; return; } var p = local.keys.GetOwnProperty(TypeConverter.ToString(local.i)).Value.AsStringWithoutTypeCheck(); if (local.processedKeys.Contains(p)) { local.i++; local.stage = 2; return; } local.processedKeys.Add(p); // collection might be modified by inner statement if (local.cursor.GetOwnProperty(p) == PropertyDescriptor.Undefined) { local.i++; local.stage = 2; return; } var value = local.cursor.GetOwnProperty(p); if (!value.Enumerable) { local.i++; local.stage = 2; return; } _engine.PutValue(local.varRef, p); local.i++; local.stage = 2; return; } if (local.stage == 4) // after for loop { local.cursor = local.cursor.Prototype; local.stage = 0; return; } }
/// <summary> /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.14 /// </summary> /// <param name="tryStatement"></param> /// <returns></returns> public void ExecuteTryStatement(RuntimeState state) { TryStatement tryStatement = (TryStatement)state.arg; ExecuteTryStatementLocal local; if (state.local == null) { state.local = local = new ExecuteTryStatementLocal(); local.stage = 0; } else { local = (ExecuteTryStatementLocal)state.local; } if (local.stage == 0) { if (state.calleeReturned) { state.calleeReturned = false; local.stage = 1; local.b = (Completion)state.calleeReturnValue; return; } Call(_engine.ExecuteStatement, tryStatement.Block); return; } if (local.stage == 1) { if (state.calleeReturned) { state.calleeReturned = false; local.stage = 2; local.b = (Completion)state.calleeReturnValue; return; } var catchClause = tryStatement.Handler; if (catchClause != null) { var c = local.b.Value; local.oldEnv = _engine.ExecutionContext.LexicalEnvironment; var catchEnv = LexicalEnvironment.NewDeclarativeEnvironment(_engine, local.oldEnv); catchEnv._record.CreateMutableBinding(((Identifier)catchClause.Param).Name, c); _engine.UpdateLexicalEnvironment(catchEnv); Call(_engine.ExecuteStatement, catchClause.Body); return; } local.stage = 2; } if (local.stage == 2) { if (state.calleeReturned) { var f = (Completion)state.calleeReturnValue; if (f.Type == CompletionType.Normal) { Return(local.b); return; } Return(f); return; } if (tryStatement.Finalizer != null) { Call(_engine.ExecuteStatement, tryStatement.Finalizer); return; } Return(local.b); return; } }