import { ArrowFunctionExpression , Expression , FunctionDeclaration , FunctionExpression , Statement , } from "@babel/types" ; export class ExecutionContext { VariableEnvironment : EnvironmentRecord ; LexicalEnvironment : EnvironmentRecord ; Function : FunctionObject ; } export type EnvironmentRecordType = "function" | "declarative" ; export class EnvironmentRecord { readonly OuterEnv : EnvironmentRecord ; private readonly bindingMap = new Map < string , BindingState > ( ) ; constructor ( outer ) { this . OuterEnv = outer ; } HasBinding ( name ) { return this . bindingMap . has ( name ) ; } CreateMutableBinding ( name , deletable ) { this . bindingMap . set ( name , { mutable : true , deletable , } ) ; return NormalCompletion ( undefined ) ; } param name param strict returns CreateImmutableBinding ( name , strict ) { this . bindingMap . set ( name , { strict , } ) ; return NormalCompletion ( undefined ) ; } InitializeBinding ( name , value ) { const binding = this . bindingMap . get ( name ) ; Object . assign < BindingState , Partial < BindingState > > ( binding , { initialized : true , value , } ) ; return NormalCompletion ( undefined ) ; } param name param value param strict returns SetMutableBinding ( name , value , strict ) { const binding = this . bindingMap . get ( name ) ; if ( ! binding . initialized ) { throw new ReferenceError ( `${ name } is not initialized` ) ; } else if ( binding . mutable ) { binding . value = value ; } else { throw new TypeError ( `Assignment to constant variable` ) ; } return NormalCompletion ( undefined ) ; } GetBindingValue ( name , strict ) { const binding = this . bindingMap . get ( name ) ; if ( ! binding . initialized ) { throw new ReferenceError ( `${ name } is not initialized` ) ; } return binding . value ; } } export class DeclarativeEnvironment extends EnvironmentRecord { } export class FunctionEnvironment extends EnvironmentRecord { } export interface BindingState { initialized ? : boolean ; value ? : unknown ; mutable ? : boolean ; /** This is used for mutable bindings only. */ deletable ? : boolean ; /**
     * This is used for immutable bindings only.
     * For named function expressions, `strict` is false,
     * otherwise it's true.
     */ strict ? : boolean ; } export const SourceNode = Symbol . for ( "SourceNode" ) ; export const FormalParameters = Symbol . for ( "FormalParameters" ) ; export const ECMAScriptCode = Symbol . for ( "ECMAScriptCode" ) ; export const Environment = Symbol . for ( "Environment" ) ; export const IsConstructor = Symbol . for ( "IsConstructor" ) ; export interface FunctionObject { ( ... args ) : unknown ; [ SourceNode ] : FunctionDeclaration | FunctionExpression | ArrowFunctionExpression ; [ FormalParameters ] : FunctionDeclaration [ "params" ] ; [ ECMAScriptCode ] : Statement [ ] | Expression ; [ Environment ] : EnvironmentRecord ; [ IsConstructor ] : boolean ; } export class ReferenceRecord { readonly Base ? : Record < PropertyKey , unknown > | EnvironmentRecord | "unresolvable" ; readonly ReferenceName ? : PropertyKey ; /** Whether the reference is in strict mode. */ readonly Strict ? : boolean ; constructor ( base , referenceName , strict ) { this . Base = base ; this . ReferenceName = referenceName ; this . Strict = strict ; } } export class CompletionRecord { readonly Type : CompletionRecordType ; readonly Value : unknown ; constructor ( type , value ) { this . Type = type ; this . Value = value ; } } export type CompletionRecordType = "normal" | "break" | "continue" | "return" | "throw" ; export function NormalCompletion ( value ) { return new CompletionRecord ( "normal" , value ) ; } export const Empty = Symbol ( "empty completion" ) ; export interface OptionalChainRef { skipped ? : boolean ; }