123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538 |
- using System.Collections.Generic;
- using System.Linq;
- using Jint.Native;
- using Jint.Native.Errors;
- using Jint.Native.Function;
- using Jint.Parser.Ast;
- using Jint.Runtime.Environments;
- using Jint.Runtime.References;
- namespace Jint.Runtime
- {
- public class StatementInterpreter
- {
- private readonly Engine _engine;
- public StatementInterpreter(Engine engine)
- {
- _engine = engine;
- }
- private Completion ExecuteStatement(Statement statement)
- {
- return _engine.ExecuteStatement(statement);
- }
- public Completion ExecuteEmptyStatement(EmptyStatement emptyStatement)
- {
- return new Completion(Completion.Normal, null, null);
- }
- public Completion ExecuteExpressionStatement(ExpressionStatement expressionStatement)
- {
- var exprRef = _engine.EvaluateExpression(expressionStatement.Expression);
- return new Completion(Completion.Normal, _engine.GetValue(exprRef), null);
- }
- public Completion ExecuteIfStatement(IfStatement ifStatement)
- {
- var exprRef = _engine.EvaluateExpression(ifStatement.Test);
- Completion result;
- if (TypeConverter.ToBoolean(_engine.GetValue(exprRef)))
- {
- result = ExecuteStatement(ifStatement.Consequent);
- }
- else if (ifStatement.Alternate != null)
- {
- result = ExecuteStatement(ifStatement.Alternate);
- }
- else
- {
- return new Completion(Completion.Normal, null, null);
- }
- return result;
- }
- /// <summary>
- /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.6.1
- /// </summary>
- /// <param name="doWhileStatement"></param>
- /// <returns></returns>
- public Completion ExecuteDoWhileStatement(DoWhileStatement doWhileStatement)
- {
- object v = null;
- bool iterating;
- do
- {
- var stmt = ExecuteStatement(doWhileStatement.Body);
- if (stmt.Value != null)
- {
- v = stmt.Value;
- }
- if (stmt.Type != Completion.Continue /* todo: || stmt.Target*/)
- {
- if (stmt.Type == Completion.Break /* todo: complete */)
- {
- return new Completion(Completion.Normal, v, null);
- }
- if (stmt.Type != Completion.Normal)
- {
- return stmt;
- }
- }
- var exprRef = _engine.EvaluateExpression(doWhileStatement.Test);
- iterating = TypeConverter.ToBoolean(_engine.GetValue(exprRef));
- } while (iterating);
- return new Completion(Completion.Normal, v, null);
- }
- /// <summary>
- /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.6.2
- /// </summary>
- /// <param name="whileStatement"></param>
- /// <returns></returns>
- public Completion ExecuteWhileStatement(WhileStatement whileStatement)
- {
- object v = null;
- while (true)
- {
- var exprRef = _engine.EvaluateExpression(whileStatement.Test);
- if (!TypeConverter.ToBoolean(_engine.GetValue(exprRef)))
- {
- return new Completion(Completion.Normal, v, null);
- }
- var stmt = ExecuteStatement(whileStatement.Body);
- if (stmt.Value != null)
- {
- v = stmt.Value;
- }
- if (stmt.Type != Completion.Continue /* todo: complete */)
- {
- if (stmt.Type == Completion.Break /* todo: complete */)
- {
- return new Completion(Completion.Normal, v, null);
- }
- if (stmt.Type != Completion.Normal)
- {
- return stmt;
- }
- }
- }
- }
- /// <summary>
- /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.6.3
- /// </summary>
- /// <param name="forStatement"></param>
- /// <returns></returns>
- public Completion ExecuteForStatement(ForStatement forStatement)
- {
-
- if (forStatement.Init != null)
- {
- if (forStatement.Init.Type == SyntaxNodes.VariableDeclaration)
- {
- ExecuteStatement(forStatement.Init.As<Statement>());
- }
- else
- {
- _engine.GetValue(_engine.EvaluateExpression(forStatement.Init.As<Expression>()));
- }
- }
- object v = null;
- while (true)
- {
- if (forStatement.Test != null)
- {
- var testExprRef = _engine.EvaluateExpression(forStatement.Test);
- if (!TypeConverter.ToBoolean(_engine.GetValue(testExprRef)))
- {
- return new Completion(Completion.Normal, v, null);
- }
- }
- var stmt = ExecuteStatement(forStatement.Body);
- if (stmt.Value != null)
- {
- v = stmt.Value;
- }
- if (stmt.Type == Completion.Break /* todo: complete */)
- {
- return new Completion(Completion.Normal, v, null);
- }
- if (stmt.Type != Completion.Continue /* todo: complete */)
- {
- if (stmt.Type != Completion.Normal)
- {
- return stmt;
- }
- }
- if (forStatement.Update != null)
- {
- var incExprRef = _engine.EvaluateExpression(forStatement.Update);
- _engine.GetValue(incExprRef);
- }
- }
- }
- /// <summary>
- /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.6.4
- /// </summary>
- /// <param name="forInStatement"></param>
- /// <returns></returns>
- public Completion ForInStatement(ForInStatement forInStatement)
- {
- object varName = null;
- if (forInStatement.Left.Type == SyntaxNodes.VariableDeclaration)
- {
- varName = ExecuteStatement(forInStatement.Left.As<Statement>()).Value;
- }
-
- var exprRef = _engine.EvaluateExpression(forInStatement.Right);
- var experValue = _engine.GetValue(exprRef);
- if (experValue == Undefined.Instance || experValue == Null.Instance)
- {
- return new Completion(Completion.Normal, null, null);
- }
- var obj = TypeConverter.ToObject(_engine, experValue);
- object v = null;
- foreach (var entry in obj.Properties)
- {
- if (!entry.Value.Enumerable)
- {
- continue;
- }
- var p = entry.Key;
- if (varName != null)
- {
- var varRef = varName as Reference;
- _engine.PutValue(varRef, p);
- }
- else
- {
- var lhsRef = _engine.EvaluateExpression(forInStatement.Left.As<Expression>()) as Reference;
- _engine.PutValue(lhsRef, p);
- }
- var stmt = ExecuteStatement(forInStatement.Body);
- if (stmt.Value != null)
- {
- v = stmt.Value;
- }
- if (stmt.Type == Completion.Break /* todo: complete */)
- {
- return new Completion(Completion.Normal, v, null);
- }
- if (stmt.Type != Completion.Continue /* todo: complete */)
- {
- if (stmt.Type != Completion.Normal)
- {
- return stmt;
- }
- }
- }
- return new Completion(Completion.Normal, v, null);
- }
- /// <summary>
- /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.7
- /// </summary>
- /// <param name="continueStatement"></param>
- /// <returns></returns>
- public Completion ExecuteContinueStatement(ContinueStatement continueStatement)
- {
- return new Completion(Completion.Continue, null, continueStatement.Label != null ? continueStatement.Label.Name : null);
- }
- /// <summary>
- /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.8
- /// </summary>
- /// <param name="breakStatement"></param>
- /// <returns></returns>
- public Completion ExecuteBreakStatement(BreakStatement breakStatement)
- {
- return new Completion(Completion.Break, null, breakStatement.Label != null ? breakStatement.Label.Name : null);
- }
- /// <summary>
- /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.9
- /// </summary>
- /// <param name="statement"></param>
- /// <returns></returns>
- public Completion ExecuteReturnStatement(ReturnStatement statement)
- {
- if (statement.Argument == null)
- {
- return new Completion(Completion.Return, Undefined.Instance, null);
- }
-
- var exprRef = _engine.EvaluateExpression(statement.Argument);
- return new Completion(Completion.Return, _engine.GetValue(exprRef), null);
- }
- /// <summary>
- /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.10
- /// </summary>
- /// <param name="withStatement"></param>
- /// <returns></returns>
- public Completion ExecuteWithStatement(WithStatement withStatement)
- {
- var val = _engine.EvaluateExpression(withStatement.Object);
- var obj = TypeConverter.ToObject(_engine, _engine.GetValue(val));
- var oldEnv = _engine.ExecutionContext.LexicalEnvironment;
- var newEnv = LexicalEnvironment.NewObjectEnvironment(obj, oldEnv);
- // todo: handle ProvideThis
- // newEnv.ProvideThis = true;
- _engine.ExecutionContext.LexicalEnvironment = newEnv;
- Completion c;
- try
- {
- c = ExecuteStatement(withStatement.Body);
- }
- catch (Error v)
- {
- c = new Completion(Completion.Throw, v, null);
- }
- finally
- {
- _engine.ExecutionContext.LexicalEnvironment = oldEnv;
- }
- return c;
- }
- /// <summary>
- /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.11
- /// </summary>
- /// <param name="switchStatement"></param>
- /// <returns></returns>
- public Completion ExecuteSwitchStatement(SwitchStatement switchStatement)
- {
- var exprRef = _engine.EvaluateExpression(switchStatement.Discriminant);
- var r = ExecuteSwitchBlock(switchStatement.Cases, _engine.GetValue(exprRef));
- if (r.Type == Completion.Break /* too: complete */)
- {
- return new Completion(Completion.Normal, r.Value, null);
- }
- return r;
- }
- public Completion ExecuteSwitchBlock(IEnumerable<SwitchCase> switchBlock, object input)
- {
- object v = null;
- SwitchCase defaultCase = null;
- foreach (var clause in switchBlock)
- {
- if (clause.Test == null)
- {
- defaultCase = clause;
- }
- else
- {
- var clauseSelector = _engine.GetValue(_engine.EvaluateExpression(clause.Test));
- if (ExpressionInterpreter.StriclyEqual(clauseSelector, input))
- {
- if (clause.Consequent != null)
- {
- var r = ExecuteStatementList(clause.Consequent);
- if (r.Type != Completion.Normal)
- {
- return r;
- }
- v = r.Value;
- }
- }
- }
- }
- if (defaultCase != null)
- {
- var r = ExecuteStatementList(defaultCase.Consequent);
- if (r.Type != Completion.Normal)
- {
- return r;
- }
- v = r.Value;
- }
- return new Completion(Completion.Normal, v, null);
- }
- public Completion ExecuteStatementList(IEnumerable<Statement> statementList)
- {
- var c = new Completion(Completion.Normal, null, null);
-
- try
- {
- foreach (var statement in statementList)
- {
- c = ExecuteStatement(statement);
- if (c.Type != Completion.Normal)
- {
- return c;
- }
- }
- }
- catch(Error v)
- {
- return new Completion(Completion.Throw, v, null);
- }
- return c;
- }
- /// <summary>
- /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.13
- /// </summary>
- /// <param name="throwStatement"></param>
- /// <returns></returns>
- public Completion ExecuteThrowStatement(ThrowStatement throwStatement)
- {
- var exprRef = _engine.EvaluateExpression(throwStatement.Argument);
- return new Completion(Completion.Throw, _engine.GetValue(exprRef), null);
- }
- /// <summary>
- /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.14
- /// </summary>
- /// <param name="tryStatement"></param>
- /// <returns></returns>
- public Completion ExecuteTryStatement(TryStatement tryStatement)
- {
- var b = ExecuteStatement(tryStatement.Block);
- if (b.Type == Completion.Throw)
- {
- // execute catch
- if (tryStatement.Handlers.Any())
- {
- foreach (var catchClause in tryStatement.Handlers)
- {
- var c = _engine.GetValue(b);
- var oldEnv = _engine.ExecutionContext.LexicalEnvironment;
- var catchEnv = LexicalEnvironment.NewDeclarativeEnvironment(oldEnv);
- catchEnv.Record.CreateMutableBinding(catchClause.Param.Name);
- catchEnv.Record.SetMutableBinding(catchClause.Param.Name, c, false);
- _engine.ExecutionContext.LexicalEnvironment = catchEnv;
- b = ExecuteStatement(catchClause.Body);
- _engine.ExecutionContext.LexicalEnvironment = oldEnv;
- }
- }
- }
- if (tryStatement.Finalizer != null)
- {
- var f = ExecuteStatement(tryStatement.Finalizer);
- if (f.Type == Completion.Normal)
- {
- return b;
- }
-
- return f;
- }
- return b;
- }
- public void EvaluateVariableScope(IVariableScope variableScope)
- {
- foreach (var variableDeclaration in variableScope.VariableDeclarations)
- {
- // declare the variables only
- ExecuteVariableDeclaration(variableDeclaration, false);
- }
- }
- public Completion ExecuteProgram(Program program)
- {
- if (program.Strict)
- {
- _engine.Options.Strict();
- }
- EvaluateVariableScope(program);
- return ExecuteStatementList(program.Body);
- }
- public Completion ExecuteVariableDeclaration(VariableDeclaration statement, bool initializeOnly)
- {
- var env = _engine.ExecutionContext.VariableEnvironment.Record;
- object value = Undefined.Instance;
- foreach (var declaration in statement.Declarations)
- {
- var dn = declaration.Id.Name;
- if (!initializeOnly)
- {
- var varAlreadyDeclared = env.HasBinding(dn);
- if (!varAlreadyDeclared)
- {
- env.CreateMutableBinding(dn, true);
- }
- }
- else
- {
- if (declaration.Init != null)
- {
- value = _engine.GetValue(_engine.EvaluateExpression(declaration.Init));
- }
- env.SetMutableBinding(dn, value, false);
- }
- }
- return new Completion(Completion.Normal, value, null);
- }
- public Completion ExecuteBlockStatement(BlockStatement blockStatement)
- {
- return ExecuteStatementList(blockStatement.Body);
- }
- public Completion ExecuteFunctionDeclaration(FunctionDeclaration functionDeclaration)
- {
- // create function objects
- // http://www.ecma-international.org/ecma-262/5.1/#sec-13.2
- var identifier = functionDeclaration.Id.Name;
- // todo: should be declared in the current context
- _engine.Global.Set(
- identifier,
- new ScriptFunctionInstance(
- _engine,
- functionDeclaration.Body,
- identifier,
- functionDeclaration.Parameters.ToArray(),
- _engine.Function.Prototype,
- _engine.Object.Construct(Arguments.Empty),
- LexicalEnvironment.NewDeclarativeEnvironment(_engine.ExecutionContext.LexicalEnvironment),
- functionDeclaration.Strict
- )
- );
- return new Completion(Completion.Normal, null, null);
- }
- public Completion ExecuteDebuggerStatement(DebuggerStatement debuggerStatement)
- {
- throw new System.NotImplementedException();
- }
- }
- }
|