import { intrinsic } from './../names' ; import { EvaluateMid } from "../types" ; import { getEnvironmentBy , GetValue } from "../environment" ; import { at , declare , evaluate , get , getTrampolineScheduler , superi , visitArray } from "../evaluate" ; import { LocatedException , NotImplementedException } from "../exceptions" ; import { bindArgs , metaesEvalModule } from "../metaes" ; import * as NodeTypes from "../nodeTypes" ; import { ASTNode , Continuation , Environment , ErrorContinuation , Interpreter , Interpreters , MetaesException , NodeLoc , Script } from "../types" ; export const modulesEnv = { [ intrinsic . GetImportBindingValue ] ( value , c , cerr , env , config ) { evaluate ( at ( value , get ( intrinsic . ImportModule ) ) , bindArgs ( value . modulePath , ( mod ) => c ( mod [ value . name ] ) , cerr ) , cerr , env , config ) ; } , [ intrinsic . ExportBinding ] ( { name , value , e } , c , cerr , env , config ) { const exportEnv = getEnvironmentBy ( env , ( env ) => env [ intrinsic . ExportEnvironment ] ) ; if ( exportEnv ) { evaluate ( declare ( name , value ) , c , cerr , exportEnv , config ) ; } else { cerr ( LocatedException ( `Couldn't export declaration, no environment with '${ intrinsic . ExportEnvironment }' property found.` , e . declaration ) ) ; } } } ; export const Identifier = ( e , c , cerr , env , config ) => superi ( "Identifier" ) ( e , ( value ) => { value instanceof ImportBinding ? evaluate ( at ( e , get ( intrinsic . GetImportBindingValue ) ) , bindArgs ( value , c , cerr , env , config ) , cerr , env , config ) : c ( value ) ; } , ( exception ) => { exception . location = e ; cerr ( exception ) ; } , env , config ) ; export const ExportNamedDeclaration = ( e , c , cerr , env , config ) => evaluate ( e . declaration , ( value ) => { let toExport ; let name ; switch ( e . declaration . type ) { case "FunctionDeclaration" : case "ClassDeclaration" : name = e . declaration . id . name ; toExport = value ; break ; case "VariableDeclaration" : { switch ( e . declaration . declarations [ 0 ] . id . type ) { case "Identifier" : name = e . declaration . declarations [ 0 ] . id . name ; toExport = value [ 0 ] ; break ; default : return cerr ( NotImplementedException ( `'${ e . declaration . declarations [ 0 ] . id . type }' declaration id type is not supported.` , e . declaration ) ) ; } break ; } default : return cerr ( NotImplementedException ( `'${ e . declaration [ "type" ] }' declaration type export is not supported.` , e . declaration ) ) ; } evaluate ( get ( intrinsic . ExportBinding ) , bindArgs ( { name , value : toExport , e : e . declaration } , c , cerr , env , config ) , cerr , env , config ) ; } , cerr , env , config ) ; export const ExportDefaultDeclaration = ( e , c , cerr , env , config ) => evaluate ( e . declaration , ( value ) => evaluate ( get ( intrinsic . ExportBinding ) , bindArgs ( { name : "default" , value , e : e . declaration } , c , cerr , env , config ) , cerr , env , config ) , cerr , env , config ) ; export class ImportBinding implements ASTNode { type = "ImportBinding" ; loc ? : NodeLoc ; range ? : [ number , number ] ; constructor ( public name , public modulePath , location ? ) { if ( location ) { const { loc , range } = location ; Object . assign ( this , { loc , range } ) ; } } } export const ImportDeclaration = ( e , c , cerr , env , config ) => visitArray ( e . specifiers , ( specifier , c , cerr ) => { const modulePath = < string > e . source . value ; switch ( specifier . type ) { case "ImportNamespaceSpecifier" : case "ImportDefaultSpecifier" : evaluate ( declare ( specifier . local . name , new ImportBinding ( "default" , modulePath , specifier ) ) , c , cerr , env , config ) ; break ; case "ImportSpecifier" : evaluate ( declare ( specifier . local . name , new ImportBinding ( specifier . imported . name , modulePath , specifier ) ) , c , cerr , env , config ) ; break ; default : cerr ( NotImplementedException ( `${ specifier [ "type" ] } import specifier is not supported yet.` , specifier ) ) ; break ; } } , c , cerr ) ; export function createModulesImporter ( globalEnv ) { const _ = ( name ) => ( arg , c , cerr ) => GetValue ( { name } , bindArgs ( arg , c , cerr ) , cerr , globalEnv ) ; const loadedModules = { } ; const loadingModules = { } ; const resolveModule = ( url ) => ( mod ) => { const results = loadingModules [ url ] ; loadedModules [ url ] = mod ; delete loadingModules [ url ] ; results . forEach ( ( { c } ) => c ( mod ) ) ; } ; const rejectModule = ( url ) => ( exception ) => { const results = loadingModules [ url ] ; delete loadingModules [ url ] ; results . forEach ( ( { cerr } ) => cerr ( exception ) ) ; } ; const importer = ( base ) : EvaluateMid < { [ key ] : any ; } , string > => ( url , c , cerr ) => { if ( loadedModules [ url ] ) { c ( loadedModules [ url ] ) ; } else if ( loadingModules [ url ] ) { loadingModules [ url ] . push ( { c , cerr } ) ; } else { loadingModules [ url ] = [ { c , cerr } ] ; _ ( intrinsic . URLToScript ) ( [ url , base ] , ( result ) => { if ( "module" in result ) { resolveModule ( url ) ( result . module ) ; } else { const { script , resolvedPath } = result ; metaesEvalModule ( script , resolveModule ( url ) , rejectModule ( url ) , { values : { [ intrinsic . ImportModule ] : importer ( resolvedPath ) } , prev : globalEnv } , { script , schedule : getTrampolineScheduler ( ) } ) ; } } , rejectModule ( url ) ) ; } } ; return importer ; } export default { ExportNamedDeclaration , ExportDefaultDeclaration , ImportDeclaration , Identifier } ;