import { Node , ESTree } from "../../Node" ; import { BaseClosure , } from '../../Closure' ; import { Messages } from '../../Message' ; import { Interpreter } from '../../../interpreter/main' ; import { EmptyStatementReturn , } from '../../Symbols' ; import { Return } from '../../TokenClass' ; import Scope , { createScope } from "../../Scope" ; const hasOwnProperty = Object . prototype . hasOwnProperty ; export function tryStatementHandler ( this , node ) { this . blockDeclareStart ( ) ; const blockClosure = this . createClosure ( node . block ) ; let tryLexDecl = this . blockDeclareEnd ( ) ; const handlerClosure = node . handler ? this . catchClauseHandler ( node . handler ) : null ; this . blockDeclareStart ( ) ; const finalizerClosure = node . finalizer ? this . createClosure ( node . finalizer ) : null ; let finalLexDecl = this . blockDeclareEnd ( ) ; return ( ) => { const currentScope = this . getCurrentScope ( ) ; const currentContext = this . getCurrentContext ( ) ; const labelStack = currentScope . labelStack . concat ( [ ] ) ; const callStack = this . callStack . concat ( [ ] ) ; let result = EmptyStatementReturn ; let finalReturn ; let throwError ; const reset = ( ) => { this . setCurrentScope ( currentScope ) ; this . setCurrentContext ( currentContext ) ; currentScope . labelStack = labelStack ; this . callStack = callStack ; } ; /**
         * try{...}catch(e){...}finally{...} execution sequence:
         * try stmt
         * try throw
         * catch stmt (if)
         * finally stmt
         * finally throw or finally return
         * catch throw or catch return
         * try return
         */ try { let prevScope ; let newScope ; if ( tryLexDecl ) { newScope = createScope ( this . getCurrentScope ( ) , `BScope(try)` , "block" ) ; newScope . lexDeclared = tryLexDecl ; prevScope = this . entryBlockScope ( newScope ) ; } result = this . setValue ( blockClosure ( ) ) ; if ( tryLexDecl ) { this . setCurrentContext ( prevScope ! ) ; } if ( result instanceof Return ) { finalReturn = result ; } } catch ( err ) { reset ( ) ; if ( this . isInterruptThrow ( err ) ) { throw err ; } if ( handlerClosure ) { try { result = this . setValue ( handlerClosure ( err ) ) ; if ( result instanceof Return ) { finalReturn = result ; } } catch ( err ) { reset ( ) ; if ( this . isInterruptThrow ( err ) ) { throw err ; } throwError = err ; } } } if ( finalizerClosure ) { try { let prevScope ; let newScope ; if ( finalLexDecl ) { newScope = createScope ( this . getCurrentScope ( ) , `BScope(final)` , "block" ) ; newScope . lexDeclared = finalLexDecl ; prevScope = this . entryBlockScope ( newScope ) ; } result = finalizerClosure ( ) ; if ( finalLexDecl ) { this . setCurrentScope ( prevScope ! ) ; } if ( result instanceof Return ) { finalReturn = result ; } } catch ( err ) { reset ( ) ; if ( this . isInterruptThrow ( err ) ) { throw err ; } throwError = err ; } } if ( throwError ) throw throwError ; if ( finalReturn ) { return finalReturn ; } return result ; } ; } export function catchClauseHandler ( this , node ) { const paramNameGetter = this . createParamNameGetter ( node . param ) ; const oldDeclVars = this . collectDeclVars ; const oldDeclFuncs = this . collectDeclFuncs ; const oldDeclLex = this . collectDeclLex ; this . collectDeclVars = Object . create ( null ) ; this . collectDeclFuncs = Object . create ( null ) ; this . collectDeclLex = [ ] ; this . blockDeclareStart ( ) ; const bodyClosure = this . createClosure ( node . body ) ; let lexDecl = this . blockDeclareEnd ( ) ; const declVars = this . collectDeclVars ; const declFuncs = this . collectDeclFuncs ; const declLex = this . collectDeclLex ; this . collectDeclVars = oldDeclVars ; this . collectDeclFuncs = oldDeclFuncs ; this . collectDeclLex = oldDeclLex ; return ( err ) => { const paramName = paramNameGetter ( ) ; const prevScope = this . getCurrentScope ( ) ; const currentScope = createScope ( prevScope , `FScope(catch)` ) ; currentScope . lexDeclared = lexDecl ! ; this . setCurrentScope ( currentScope ) ; this . addDeclarationsToScope ( declVars , declFuncs , currentScope ) ; currentScope . data [ paramName ] = err ; let result ; result = bodyClosure ( ) ; this . setCurrentScope ( prevScope ) ; return result ; } ; }