using System.Runtime.CompilerServices; using Esprima; using Esprima.Ast; using Jint.Runtime.Interpreter.Expressions; namespace Jint.Runtime.Interpreter.Statements { internal abstract class JintStatement : JintStatement where T : Statement { internal readonly T _statement; protected JintStatement(Engine engine, T statement) : base(engine, statement) { _statement = statement; } } internal abstract class JintStatement { protected readonly Engine _engine; private readonly Statement _statement; // require sub-classes to set to false explicitly to skip virtual call protected bool _initialized = true; protected JintStatement(Engine engine, Statement statement) { _engine = engine; _statement = statement; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Completion Execute() { if (_statement.Type != Nodes.BlockStatement) { _engine._lastSyntaxNode = _statement; _engine.RunBeforeExecuteStatementChecks(_statement); } if (!_initialized) { Initialize(); _initialized = true; } return ExecuteInternal(); } protected abstract Completion ExecuteInternal(); public Location Location => _statement.Location; /// /// Opportunity to build one-time structures and caching based on lexical context. /// protected virtual void Initialize() { } protected internal static JintStatement Build(Engine engine, Statement statement) { return statement.Type switch { Nodes.BlockStatement => new JintBlockStatement(engine, (BlockStatement) statement), Nodes.ReturnStatement => new JintReturnStatement(engine, (ReturnStatement) statement), Nodes.VariableDeclaration => new JintVariableDeclaration(engine, (VariableDeclaration) statement), Nodes.BreakStatement => new JintBreakStatement(engine, (BreakStatement) statement), Nodes.ContinueStatement => new JintContinueStatement(engine, (ContinueStatement) statement), Nodes.DoWhileStatement => new JintDoWhileStatement(engine, (DoWhileStatement) statement), Nodes.EmptyStatement => new JintEmptyStatement(engine, (EmptyStatement) statement), Nodes.ExpressionStatement => new JintExpressionStatement(engine, (ExpressionStatement) statement), Nodes.ForStatement => new JintForStatement(engine, (ForStatement) statement), Nodes.ForInStatement => new JintForInForOfStatement(engine, (ForInStatement) statement), Nodes.ForOfStatement => new JintForInForOfStatement(engine, (ForOfStatement) statement), Nodes.IfStatement => new JintIfStatement(engine, (IfStatement) statement), Nodes.LabeledStatement => new JintLabeledStatement(engine, (LabeledStatement) statement), Nodes.SwitchStatement => new JintSwitchStatement(engine, (SwitchStatement) statement), Nodes.FunctionDeclaration => new JintFunctionDeclarationStatement(engine, (FunctionDeclaration) statement), Nodes.ThrowStatement => new JintThrowStatement(engine, (ThrowStatement) statement), Nodes.TryStatement => new JintTryStatement(engine, (TryStatement) statement), Nodes.WhileStatement => new JintWhileStatement(engine, (WhileStatement) statement), Nodes.WithStatement => new JintWithStatement(engine, (WithStatement) statement), Nodes.DebuggerStatement => new JintDebuggerStatement(engine, (DebuggerStatement) statement), Nodes.Program => new JintScript(engine, statement as Script ?? ExceptionHelper.ThrowArgumentException