import Env from './env' ; import readStr , { BlankException } from './reader' ; import evalExp from './eval' ; import ReplCore , { slurp } from './repl-core' ; import { symbolFor as S , MalVal , MalError } from './types' ; import printExp , { printer } from './printer' ; import isNodeJS from 'is-node' ; const normalizeURL = ( ( ) => { if ( isNodeJS ) { const path = require ( 'path' ) ; return ( url , basename ) => { return path . join ( path . dirname ( basename ) , url ) ; } ; } else { return ( url , basename ) => { return new URL ( url , basename ) . href ; } ; } } ) ( ) ; export default class Scope < T > { public env ! : Env ; private inner ! : Scope < any > ; constructor ( private outer = null , private name = 'repl' , private onSetup = null , private cache = false ) { this . setup ( ) ; if ( this . outer === null ) { this . initAsRepl ( ) ; } else { this . outer . inner = this ; } } private initAsRepl ( ) { ReplCore . forEach ( ( [ name , expr ] ) => { this . def ( name , expr ) ; } ) ; this . def ( 'normalize-url' , ( url ) => { const basename = this . var ( '*filename*' ) as string ; return normalizeURL ( url as string , basename ) ; } ) ; this . def ( 'eval' , ( exp ) => { return evalExp ( exp , this . env ) ; } ) ; this . def ( 'import-js-force' , ( url ) => { const basename = this . var ( '*filename*' ) as string ; const absurl = normalizeURL ( url as string , basename ) ; const text = slurp ( absurl ) ; eval ( text ) ; const exp = ( globalThis as any ) [ 'glisp_library' ] ; return evalExp ( exp , this . env ) ; } ) ; let filename ; if ( isNodeJS ) { filename = '/Users/baku/Sites/glisp/repl/index.js' ; } else { filename = new URL ( '.' , document . baseURI ) . href ; } this . def ( '*filename*' , filename ) ; this . readEval ( `(def import-force
				(fn [path]
					(let [url (normalize-url path)]
						(eval (read-string
									(format "(do (def *filename* \\"%s\\") %s \n nil)"
													url
													(slurp url)))))))` ) ; this . readEval ( '(import-force "./lib/core.glisp")' ) ; if ( isNodeJS ) { this . def ( '*filename*' , process . cwd ( ) ) ; } } public setup ( option ? ) { this . env = new Env ( this . outer ?. env ) ; this . env . name = this . name ; if ( this . onSetup && option ) { this . onSetup ( this , option ) ; } if ( this . inner ) { this . inner . env . setOuter ( this . env ) ; } } public REP ( str ) { const ret = this . readEval ( str ) ; if ( ret !== undefined ) { printer . return ( printExp ( ret ) ) ; } } public readEval ( str ) { try { return this . eval ( readStr ( str ) ) ; } catch ( err ) { if ( err instanceof BlankException ) { return null ; } if ( err instanceof MalError ) { printer . error ( err ) ; } else { printer . error ( err . stack ) ; } return undefined ; } } public eval ( exp ) { try { return evalExp ( exp , this . env , this . cache ) ; } catch ( err ) { if ( err instanceof MalError ) { printer . error ( err ) ; } else { printer . error ( err . stack ) ; } return undefined ; } } public def ( name , value ) { this . env . set ( S ( name ) , value ) ; } public pushBinding ( env ) { this . env . pushBinding ( env ) ; } public popBinding ( ) { this . env . popBinding ( ) ; } public var ( name ) { return this . env . get ( S ( name ) ) ; } }