import { getSuperEnv , GetValue } from "./environment" ; import { NotImplementedException , toException } from "./exceptions" ; import { bindArgs , callInterceptor } from "./metaes" ; import { CallExpression , EvalNode , TaggedTemplateExpression } from "./nodeTypes" ; import { ASTNode , Continuation , Environment , ErrorContinuation , Evaluate , EvaluationConfig , MetaesException , PartialErrorContinuation } from "./types" ; export const at = < T > ( { loc , range } , rest ) => < const > { loc , range , ... rest } ; export const declare = ( name , value ) => < const > { type : "SetValue" , name , value , isDeclaration : true } ; export const get = ( name ) => < const > { type : "GetValue" , name } ; export const set = ( name , value ) => < const > { type : "SetValue" , name , value , isDeclaration : false } ; export const apply = ( fn , thisValue , args = [ ] , e ) => < const > { type : "Apply" , fn , thisValue , args , e } ; export const getProperty = ( object , property ) => < const > { type : "GetProperty" , object , property } ; export const setProperty = ( object , property , value , operator ) => < const > { type : "SetProperty" , object , property , value , operator } ; export const applyDynamic = ( { name , args } , c , cerr , env , config ) => evaluate ( get ( name ) , bindArgs ( args , c , cerr ) , cerr , env , config ) ; export const getDynamic = ( { name } , c , cerr , env , config ) => evaluate ( get ( name ) , c , cerr , env , config ) ; const setHelper = ( object , key , value ) => ( ( object [ key ] = value ) , object ) ; export const getDynamicMany = ( ) => ( names , c , cerr , env , config ) => visitArray ( names , ( name , c , cerr ) => getDynamic ( { name } , c , cerr , env , config ) , ( values ) => c ( values . reduce ( ( previous , current , index ) => setHelper ( previous , names [ index ] , current ) , { } ) ) , cerr ) ; export const createDynamicApplication = ( name ) => ( args , ... rest ) => applyDynamic ( { name , args } , ... rest ) ; export const superi = ( name ) => ( e , c , cerr , env , config ) => GetValue ( { name } , bindArgs ( e , c , cerr , env , config ) , cerr , getSuperEnv ( name , config . interpreters ) ! ) ; export function defaultScheduler ( fn ) { fn ( ) ; } export function getTrampolineScheduler ( ) { const tasks = [ ] ; let running = false ; function run ( ) { if ( running ) { return ; } running = true ; while ( tasks . length ) { tasks . pop ( ) ! ( ) ; } running = false ; } return function ( fn ) { tasks . push ( fn ) ; if ( ! running ) { run ( ) ; } } ; } export const evaluate = ( e , c , cerr , env , config ) => GetValue ( { name : e . type } , function ( interpreter ) { callInterceptor ( "enter" , config , e , env ) ; const schedule = config . schedule || defaultScheduler ; schedule ( function run ( ) { interpreter ( e , function _c ( value ) { schedule ( function exit ( ) { callInterceptor ( "exit" , config , e , env , value ) ; c ( value ) ; } ) ; } , function _cerr ( exception ) { exception = toException ( exception ) ; if ( ! exception . location ) { exception . location = e ; } if ( ! exception . script ) { exception . script = config . script ; } callInterceptor ( "exit" , config , e , env , exception ) ; cerr ( < MetaesException > exception ) ; } , env , config ) ; } ) ; } , function ( ) { const exception = NotImplementedException ( `"${ e . type }" node type interpreter is not defined yet.` , e ) ; callInterceptor ( "exit" , config , e , env , exception ) ; cerr ( < MetaesException > exception ) ; } , config . interpreters ) ; type Visitor < T > = ( element : T , c : Continuation , cerr : PartialErrorContinuation ) => void ; export const visitArray = < T > ( items , fn , c , cerr ) => { if ( items . length === 0 ) { c ( [ ] ) ; } else if ( items . length === 1 ) { fn ( items [ 0 ] , ( value ) => c ( [ value ] ) , cerr ) ; } else { const schedule = getTrampolineScheduler ( ) ; const visited = new Set ( ) ; function loop ( index , accumulated ) { if ( index < items . length ) { fn ( items [ index ] , function onNextItem ( value ) { if ( visited . has ( index ) ) { accumulated = accumulated . slice ( 0 , index ) ; } accumulated . push ( value ) ; visited . add ( index ) ; schedule ( ( ) => loop ( index + 1 , accumulated ) ) ; } , cerr ) ; } else { c ( accumulated ) ; } } schedule ( ( ) => loop ( 0 , [ ] ) ) ; } } ; export const evaluateArray = ( array , c , cerr , env , config ) => visitArray ( array , ( e , c , cerr ) => evaluate ( e , c , cerr , env , config ) , c , cerr ) ;