using Jint.Runtime.Environments; using Environment = Jint.Runtime.Environments.Environment; namespace Jint.Runtime.Interpreter.Statements { internal sealed class JintBlockStatement : JintStatement { private JintStatementList? _statementList; private JintStatement? _singleStatement; private List? _lexicalDeclarations; public JintBlockStatement(NestedBlockStatement blockStatement) : base(blockStatement) { } protected override void Initialize(EvaluationContext context) { _lexicalDeclarations = HoistingScope.GetLexicalDeclarations(_statement); if (_statement.Body.Count == 1) { _singleStatement = Build(_statement.Body[0]); } else { _statementList = new JintStatementList(_statement, _statement.Body); } } /// /// Optimized for direct access without virtual dispatch. /// public Completion ExecuteBlock(EvaluationContext context) { if (_statementList is null && _singleStatement is null) { Initialize(context); } Environment? oldEnv = null; var engine = context.Engine; if (_lexicalDeclarations != null) { oldEnv = engine.ExecutionContext.LexicalEnvironment; var blockEnv = JintEnvironment.NewDeclarativeEnvironment(engine, engine.ExecutionContext.LexicalEnvironment); JintStatementList.BlockDeclarationInstantiation(blockEnv, _lexicalDeclarations); engine.UpdateLexicalEnvironment(blockEnv); } Completion blockValue; if (_singleStatement is not null) { blockValue = ExecuteSingle(context); } else { blockValue = _statementList!.Execute(context); } if (oldEnv is not null) { engine.UpdateLexicalEnvironment(oldEnv); } return blockValue; } private Completion ExecuteSingle(EvaluationContext context) { Completion blockValue; try { blockValue = _singleStatement!.Execute(context); if (context.Engine._error is not null) { blockValue = JintStatementList.HandleError(context.Engine, _singleStatement); } } catch (Exception ex) { if (ex is JintException) { blockValue = JintStatementList.HandleException(context, ex, _singleStatement); } else { throw; } } return blockValue; } protected override Completion ExecuteInternal(EvaluationContext context) { return ExecuteBlock(context); } } }