import NodeVisitor from '~/ast/NodeVisitor' ; import { Def } from '~/ast' ; import { ModuleScope } from '~/analyzer' ; import { Context , CommonContext } from '~/module/context' ; import { Loader } from '~/module/loader' ; import * as ast from '~/ast' ; import { Compiler } from '../compiler' ; export default class Resolver extends NodeVisitor { compiler : Compiler | null = null ; loader : Loader | null ; submoduleNames : string [ ] = [ ] ; constructor ( ) { super ( ) ; this . loader = null ; } async init ( ) { await super . init ( ) ; this . submoduleNames = [ ] ; } async resolve ( context ) { if ( this . compiler == null ) { throw new Error ( 'compiler가 초기화되지 않았습니다' ) ; } let moduleHash = context . hash ( ) ; { if ( this . compiler . astMap [ moduleHash ] ) return this . compiler . astMap [ moduleHash ] ; } await this . init ( ) ; if ( this . loader == null ) { throw new Error ( 'Resolver가 올바르게 초기화되지 않았습니다' ) ; } let astRoot = await this . loader . get ( context ) ; this . compiler . astMap [ moduleHash ] = astRoot ; astRoot . hash = moduleHash ; { let moduleScope = new ModuleScope ( ) ; for ( let statement of astRoot . statements ) { if ( statement instanceof Def ) { moduleScope . addDef ( statement ) ; } } astRoot . moduleScope = moduleScope ; } { await this . visit ( astRoot ) ; for ( let submoduleName of this . submoduleNames ) { let submoduleResolver = new Resolver ( ) ; submoduleResolver . compiler = this . compiler ; submoduleResolver . loader = this . loader ; let submoduleContext = new CommonContext ( submoduleName ) ; submoduleContext . from = context ; let submoduleHash = submoduleContext . hash ( ) ; let submoduleAstRoot = await submoduleResolver . resolve ( submoduleContext ) ; this . compiler . astMap [ submoduleHash ] = submoduleAstRoot ; astRoot . modules [ submoduleName ] = submoduleHash ; this . compiler . addModuleDependency ( moduleHash , submoduleHash ) ; } } return astRoot ; } async visitCallLike ( node ) { for ( let expression of node . expressions ) { if ( expression == null ) continue ; await this . visit ( expression ) ; } } async visitModuleCallLike ( node ) { this . submoduleNames . push ( node . target . value ) ; for ( let expression of node . expressions ) { if ( expression == null ) continue ; await this . visit ( expression ) ; } } async visitCall ( node ) { return await this . visitCallLike ( node ) ; } async visitModuleCall ( node ) { return await this . visitModuleCallLike ( node ) ; } async visitCallBind ( node ) { return await this . visitCallLike ( node ) ; } async visitModuleCallBind ( node ) { return await this . visitModuleCallLike ( node ) ; } } ;