import { Node , ESTree } from "../../Node" ; import { BaseClosure , } from '../../Closure' ; import { Messages } from '../../Message' ; import { Interpreter } from '../../../interpreter/main' ; import { EmptyStatementReturn , Break , Continue , storeKey } from '../../Symbols' ; import { ContinueLabel , BreakLabel , Return } from '../../TokenClass' ; import Scope , { createScope } from "../../Scope" ; export function forOfStatementHandler ( this , node ) { let left = node . left ; const rightClosure = this . createClosure ( node . right ) ; let getBodyClosure = ( ) => { if ( node . body . type == 'BlockStatement' ) { return { needBlock : null , closure : this . createClosure ( node . body ) } ; } else { this . blockDeclareStart ( ) ; let closure = this . createClosure ( node . body ) ; let bodyLex = this . blockDeclareEnd ( ) ; return { needBlock : bodyLex , closure , } ; } } ; let initClosure ; let initLexDecl ; if ( node . left . type === "VariableDeclaration" ) { this . blockDeclareStart ( ) ; initClosure = this . createClosure ( node . left ) ; initLexDecl = this . blockDeclareEnd ( ) ; if ( ! initLexDecl ) { initClosure ( ) ; initClosure = null ; } else { } left = node . left . declarations [ 0 ] . id ; } else { } return pNode => { let labelName ; let result = EmptyStatementReturn ; if ( pNode && pNode . type === "LabeledStatement" ) { labelName = pNode . label . name ; } const Smbl = this . globalScope . data [ 'Symbol' ] ; const MArray = this . globalScope . data [ 'Array' ] ; let prevScope ; let newScope ; if ( initLexDecl ) { newScope = createScope ( this . getCurrentScope ( ) , `BScope(forof-let)` , "block" ) ; newScope . lexDeclared = initLexDecl ; prevScope = this . entryBlockScope ( newScope ) ; } const data = rightClosure ( ) ; if ( data [ storeKey ( Smbl . iterator ) ] && typeof data [ storeKey ( Smbl . iterator ) ] == 'function' ) { let iter = data [ storeKey ( Smbl . iterator ) ] ( ) ; let val = iter . next ( ) ; while ( val && ! val . done ) { let t = loopBody . call ( this , _ => { result = _ ; } , initLexDecl , newScope ! , node , left , labelName , getBodyClosure , val . value ) ; if ( t === 'break' ) { break ; } val = iter . next ( ) ; } } else if ( Array . isArray ( data ) ) { for ( let i = 0 ; i < data . length ; i ++ ) { let t = loopBody . call ( this , _ => { result = _ ; } , initLexDecl , newScope ! , node , left , labelName , getBodyClosure , data [ i ] ) ; if ( t === 'break' ) { break ; } } } else { throw this . createInternalThrowError ( Messages . VariableNotIterableError , '' , node ) ; } if ( initLexDecl ) { this . setCurrentScope ( prevScope ! ) ; } return result ; } ; } function loopBody ( this , setResult , initLexDecl , newScope , node , left , labelName , getBodyClosure , rightVal ) { if ( initLexDecl ) { Object . getOwnPropertyNames ( newScope ! . lexDeclared ) . forEach ( name => { newScope . lexDeclared [ name ] . init = false ; } ) ; this . variableDeclarationHandler ( { type : "VariableDeclaration" , kind : ( node . left as ESTree . VariableDeclaration ) . kind , declarations : [ { type : "VariableDeclarator" , id : ( node . left as ESTree . VariableDeclaration ) . declarations [ 0 ] . id , init : { type : "Literal" , value : rightVal , } } ] } ) ( ) ; } else { this . assignmentExpressionHandler ( { type : "AssignmentExpression" , operator : "=" , left : left as ESTree . Pattern , right : { type : "Literal" , value : rightVal , } , } ) ( ) ; } let bodyClosure = getBodyClosure ( ) ; let bodyPrev ; let bodyScope ; if ( bodyClosure . needBlock ) { bodyScope = createScope ( this . getCurrentScope ( ) , 'BScope(forin-body)' , 'block' ) ; bodyScope . lexDeclared = bodyClosure . needBlock ; bodyPrev = this . entryBlockScope ( bodyScope ) ; } const ret = this . setValue ( bodyClosure . closure ( ) ) ; if ( bodyClosure . needBlock ) { this . setCurrentScope ( bodyPrev ! ) ; } if ( ret === EmptyStatementReturn || ret === Continue ) return 'continue' ; if ( ret === Break ) { return 'break' ; } setResult ( ret ) ; if ( ret instanceof ContinueLabel && ret . value === labelName ) { setResult ( EmptyStatementReturn ) ; return 'continue' ; } if ( ret instanceof Return || ret instanceof BreakLabel || ret instanceof ContinueLabel ) { return 'break' ; } return ; }