import { Map , Record } from 'immutable' ; import { CodeSource , ShValue , SVAddr , SVType } from './sharpValues' ; interface ShEnvProps { readonly addrMap : Map < string , SVAddr > ; } const shEnvDefaults = { addrMap : Map < string , SVAddr > ( ) , } ; export class ShEnv extends Record ( shEnvDefaults ) implements ShEnvProps { constructor ( addrMap ? ) { addrMap ? super ( { addrMap } ) : super ( ) ; } hasId ( id ) { return this . addrMap . has ( id ) ; } getId ( id ) { return this . addrMap . get ( id ) ; } setId ( id , addr ) { return this . set ( 'addrMap' , this . addrMap . set ( id , addr ) ) ; } removeId ( id ) { return this . set ( 'addrMap' , this . addrMap . delete ( id ) ) ; } toString ( ) { let revMap = Map < number , string > ( ) ; this . addrMap . forEach ( ( v , k ) => { revMap = revMap . set ( v . addr , k ) ; } ) ; const revArr = [ ... revMap . keys ( ) ] ; revArr . sort ( ( a , b ) => a - b ) ; return `{\n${ revArr . map ( ( i ) => `  ${ revMap . get ( i ) } => ${ i },` ) . join ( '\n' ) }\n}` ; } addOffset ( offset ) { return new ShEnv ( this . addrMap . mapEntries ( ( [ k , addr ] ) => [ k , addr . addOffset ( offset ) ] ) ) ; } mergeAddr ( env ) { return new ShEnv ( this . addrMap . merge ( env . addrMap ) ) ; } } interface ShHeapProps { readonly addrMax : number ; readonly valMap : Map < number , ShValue > ; } const shHeapDefaults = { addrMax : 0 , valMap : Map < number , ShValue > ( ) , } ; export class ShHeap extends Record ( shHeapDefaults ) implements ShHeapProps { constructor ( ) { super ( ) ; } getVal ( addr ) { if ( typeof addr !== 'number' ) { addr = addr . addr ; } return this . valMap . get ( addr ) ; } getValRecur ( addr ) { let retVal = this . getVal ( addr ) ; while ( retVal && retVal . type === SVType . Addr ) { retVal = this . getVal ( retVal ) ; } return retVal ; } setVal ( addr , value ) { if ( typeof addr !== 'number' ) { addr = addr . addr ; } let heap = this ; if ( heap . addrMax < addr ) { heap = heap . set ( 'addrMax' , addr ) ; } return heap . set ( 'valMap' , heap . valMap . set ( addr , value ) ) ; } malloc ( source ) { const addr = this . addrMax ; return [ SVAddr . create ( addr + 1 , source ) , this . set ( 'addrMax' , addr + 1 ) ] ; } allocNew ( value , source ) { const [ addr , heap ] = this . malloc ( source ) ; return [ addr , heap . setVal ( addr , value ) ] ; } toString ( ) { const keyArr = [ ... this . valMap . keys ( ) ] ; keyArr . sort ( ( a , b ) => a - b ) ; return `{\n${ keyArr . map ( ( i ) => `  ${ i } => ${ this . valMap . get ( i ) ?. toString ( ) },` ) . join ( '\n' ) }\n}` ; } free ( addr ) { if ( typeof addr !== 'number' ) { addr = addr . addr ; } let newHeap = this . set ( 'valMap' , this . valMap . remove ( addr ) ) ; if ( addr === this . addrMax ) { newHeap = this . set ( 'addrMax' , addr - 1 ) ; } return newHeap ; } addOffset ( offset ) { return this . set ( 'addrMax' , this . addrMax + offset ) . set ( 'valMap' , this . valMap . mapEntries ( ( [ k , v ] ) => [ k >= 0 ? k + offset : k , ShValue . addOffset ( v , offset ) ] ) ) ; } filter ( predicate ) { return this . set ( 'valMap' , this . valMap . filter ( predicate ) ) ; } _runGC ( envList ) { const marked = new Set ( ) ; let heap = this ; function markVal ( value ) { switch ( value . type ) { case SVType . Addr : mark ( value ) ; break ; case SVType . Object : value . attrs . forEach ( ( v ) => markVal ( v ) ) ; value . indices . forEach ( ( v ) => markVal ( v ) ) ; value . keyValues . forEach ( ( v ) => markVal ( v ) ) ; break ; case SVType . Func : value . defaults . forEach ( ( v ) => markVal ( v ) ) ; value . funcEnv ?. addrMap . forEach ( ( addr ) => mark ( addr ) ) ; break ; default : break ; } } function mark ( addr ) { if ( typeof addr !== 'number' ) { addr = addr . addr ; } if ( marked . has ( addr ) ) { return ; } else { marked . add ( addr ) ; } const val = heap . getVal ( addr ) ; if ( ! val ) { return ; } markVal ( val ) ; } envList . forEach ( ( env ) => { env . addrMap . forEach ( ( addr ) => mark ( addr ) ) ; } ) ; heap = heap . set ( 'valMap' , heap . valMap . filter ( ( _ , k ) => k < 0 || marked . has ( k ) ) ) ; return heap ; } }