@@ -17,7 +17,14 @@ export interface Frame {
1717 readonly vars : readonly string [ ] ;
1818 readonly fin : boolean ;
1919}
20- export type Stack = readonly Frame [ ] ;
20+ // The evaluation stack as an immutable cons-list (O(1) push/rest, no per-step array slice/spread
21+ // — the array form showed up as ArrayPrototypeSlice in the profile). `null` is the empty stack.
22+ export interface StackCons {
23+ readonly head : Frame ;
24+ readonly tail : Stack ;
25+ }
26+ export type Stack = StackCons | null ;
27+ const cons = ( head : Frame , tail : Stack ) : StackCons => ( { head, tail } ) ;
2128export interface Item {
2229 readonly stack : Stack ;
2330 readonly bnd : Bindings ;
@@ -80,7 +87,7 @@ function isEmbeddedOp(a: Atom): boolean {
8087 return op !== undefined && EMBEDDED . has ( op ) ;
8188}
8289
83- const varsCopy = ( prev : Stack ) : readonly string [ ] => ( prev . length > 0 ? prev [ 0 ] ! . vars : [ ] ) ;
90+ const varsCopy = ( prev : Stack ) : readonly string [ ] => ( prev !== null ? prev . head . vars : [ ] ) ;
8491
8592function isVariableHeaded ( a : Atom ) : boolean {
8693 if ( a . kind === "var" ) return true ;
@@ -101,24 +108,24 @@ function atomToStack(a: Atom, prev: Stack): Stack {
101108 const op = opOf ( a ) ;
102109 const it = a . items ;
103110 if ( op === "chain" && it . length === 4 && it [ 2 ] ! . kind === "var" ) {
104- return atomToStack ( it [ 1 ] ! , [ frame ( a , "chain" , varsCopy ( prev ) ) , ... prev ] ) ;
111+ return atomToStack ( it [ 1 ] ! , cons ( frame ( a , "chain" , varsCopy ( prev ) ) , prev ) ) ;
105112 }
106113 if ( op === "function" && it . length === 2 && it [ 1 ] ! . kind === "expr" ) {
107- return atomToStack ( it [ 1 ] ! , [ frame ( a , "function" , varsCopy ( prev ) ) , ... prev ] ) ;
114+ return atomToStack ( it [ 1 ] ! , cons ( frame ( a , "function" , varsCopy ( prev ) ) , prev ) ) ;
108115 }
109116 if ( op === "unify" && it . length === 5 ) {
110- return [ frame ( a , "none" ) , ... prev ] ;
117+ return cons ( frame ( a , "none" ) , prev ) ;
111118 }
112- if ( op === "chain" ) return [ frame ( errAtom ( a , "chain: malformed" ) , "none" , [ ] , true ) , ... prev ] ;
119+ if ( op === "chain" ) return cons ( frame ( errAtom ( a , "chain: malformed" ) , "none" , [ ] , true ) , prev ) ;
113120 if ( op === "function" )
114- return [ frame ( errAtom ( a , "function: malformed" ) , "none" , [ ] , true ) , ... prev ] ;
115- if ( op === "unify" ) return [ frame ( errAtom ( a , "unify: malformed" ) , "none" , [ ] , true ) , ... prev ] ;
121+ return cons ( frame ( errAtom ( a , "function: malformed" ) , "none" , [ ] , true ) , prev ) ;
122+ if ( op === "unify" ) return cons ( frame ( errAtom ( a , "unify: malformed" ) , "none" , [ ] , true ) , prev ) ;
116123 }
117- return [ frame ( a , "none" , varsCopy ( prev ) ) , ... prev ] ;
124+ return cons ( frame ( a , "none" , varsCopy ( prev ) ) , prev ) ;
118125}
119126
120127function finItem ( st : Stack , a : Atom , b : Bindings ) : Item {
121- return { stack : [ frame ( a , "none" , [ ] , true ) , ... st ] , bnd : b } ;
128+ return { stack : cons ( frame ( a , "none" , [ ] , true ) , st ) , bnd : b } ;
122129}
123130
124131function evalResult ( prev : Stack , r : Atom , b : Bindings ) : Item {
@@ -338,16 +345,17 @@ function unifyOp(prev: Stack, a: Atom, p: Atom, t: Atom, e: Atom, b: Bindings):
338345}
339346
340347// ---------- final-item helpers ----------
341- const isFinal = ( it : Item ) : boolean => it . stack . length === 1 && it . stack [ 0 ] ! . fin ;
348+ const isFinal = ( it : Item ) : boolean =>
349+ it . stack !== null && it . stack . tail === null && it . stack . head . fin ;
342350function finalPair ( it : Item ) : [ Atom , Bindings ] {
343- const f = it . stack [ 0 ] ;
344- return f === undefined ? [ emptyA , [ ] ] : [ instantiate ( it . bnd , f . atom ) , it . bnd ] ;
351+ const f = it . stack ;
352+ return f === null ? [ emptyA , [ ] ] : [ instantiate ( it . bnd , f . head . atom ) , it . bnd ] ;
345353}
346354function exhaustedPair ( it : Item ) : [ Atom , Bindings ] {
347- const f = it . stack [ 0 ] ;
348- return f === undefined
355+ const f = it . stack ;
356+ return f === null
349357 ? [ emptyA , it . bnd ]
350- : [ expr ( [ sym ( "Error" ) , instantiate ( it . bnd , f . atom ) , sym ( "StackOverflow" ) ] ) , it . bnd ] ;
358+ : [ expr ( [ sym ( "Error" ) , instantiate ( it . bnd , f . head . atom ) , sym ( "StackOverflow" ) ] ) , it . bnd ] ;
351359}
352360
353361function resolveAtomFix ( b : Bindings , n : number , a : Atom ) : Atom {
@@ -372,8 +380,8 @@ function restrictBnd(vars: readonly string[], b: Bindings): Bindings {
372380}
373381function scopeVars ( b : Bindings , prev : Stack ) : string [ ] {
374382 const out : string [ ] = [ ] ;
375- for ( const f of prev )
376- for ( const v of atomVars ( instantiate ( b , f . atom ) ) ) if ( ! out . includes ( v ) ) out . push ( v ) ;
383+ for ( let p = prev ; p !== null ; p = p . tail )
384+ for ( const v of atomVars ( instantiate ( b , p . head . atom ) ) ) if ( ! out . includes ( v ) ) out . push ( v ) ;
377385 return out ;
378386}
379387function superposeItem ( prev : Stack , b : Bindings , pair : Atom ) : Item {
@@ -604,29 +612,29 @@ function getDocOf(env: MinEnv, w: World, atom: Atom): Atom {
604612
605613// ---------- the step function ----------
606614function interpretStack1 ( env : MinEnv , fuel : number , st : St , it : Item ) : [ Item [ ] , St ] {
607- if ( it . stack . length === 0 ) return [ [ ] , st ] ;
608- const top = it . stack [ 0 ] ! ;
609- const prev = it . stack . slice ( 1 ) ;
615+ if ( it . stack === null ) return [ [ ] , st ] ;
616+ const top = it . stack . head ;
617+ const prev = it . stack . tail ;
610618 if ( top . fin ) {
611- if ( prev . length === 0 ) return [ [ it ] , st ] ;
612- const pf = prev [ 0 ] ! ;
613- const pprev = prev . slice ( 1 ) ;
619+ if ( prev === null ) return [ [ it ] , st ] ;
620+ const pf = prev . head ;
621+ const pprev = prev . tail ;
614622 const res = instantiate ( it . bnd , top . atom ) ;
615623 if ( pf . ret === "chain" ) {
616624 if ( opOf ( pf . atom ) === "chain" && pf . atom . kind === "expr" && pf . atom . items . length === 4 ) {
617625 const v = pf . atom . items [ 2 ] ! ;
618626 const templ = pf . atom . items [ 3 ] ! ;
619627 const nf = frame ( expr ( [ sym ( "chain" ) , res , v , templ ] ) , pf . ret , pf . vars , false ) ;
620- return [ [ { stack : [ nf , ... pprev ] , bnd : it . bnd } ] , st ] ;
628+ return [ [ { stack : cons ( nf , pprev ) , bnd : it . bnd } ] , st ] ;
621629 }
622630 return [ [ finItem ( pprev , errAtom ( pf . atom , "chain: corrupt frame" ) , it . bnd ) ] , st ] ;
623631 }
624632 if ( pf . ret === "function" ) {
625633 if ( opOf ( res ) === "return" && res . kind === "expr" && res . items . length === 2 )
626634 return [ [ finItem ( pprev , res . items [ 1 ] ! , it . bnd ) ] , st ] ;
627635 if ( isEmbeddedOp ( res ) )
628- return [ [ { stack : atomToStack ( res , [ pf , ... pprev ] ) , bnd : it . bnd } ] , st ] ;
629- const target = pprev . length > 0 ? pprev [ 0 ] ! . atom : res ;
636+ return [ [ { stack : atomToStack ( res , cons ( pf , pprev ) ) , bnd : it . bnd } ] , st ] ;
637+ const target = pprev !== null ? pprev . head . atom : res ;
630638 return [ [ finItem ( pprev , errAtom ( target , "NoReturn" ) , it . bnd ) ] , st ] ;
631639 }
632640 return [ [ ] , st ] ; // Ret.none on a finished non-top frame
@@ -707,7 +715,7 @@ function interpretStack1(env: MinEnv, fuel: number, st: St, it: Item): [Item[],
707715 case "collapse-bind" : {
708716 if ( it2 . length !== 2 ) break ;
709717 const [ atoms , st2 ] = interpretLoop ( env , fuel , st , [
710- { stack : atomToStack ( it2 [ 1 ] ! , [ ] ) , bnd : it . bnd } ,
718+ { stack : atomToStack ( it2 [ 1 ] ! , null ) , bnd : it . bnd } ,
711719 ] ) ;
712720 return [ [ finItem ( prev , expr ( atoms . map ( ( p ) => expr ( [ p [ 0 ] , unitA ] ) ) ) , it . bnd ) ] , st2 ] ;
713721 }
@@ -816,7 +824,7 @@ function interpretStack1(env: MinEnv, fuel: number, st: St, it: Item): [Item[],
816824 break ;
817825 }
818826 if ( isEmbeddedOp ( a ) ) return [ [ finItem ( prev , errAtom ( a , "unsupported minimal op" ) , it . bnd ) ] , st ] ;
819- return [ [ { stack : [ frame ( top . atom , top . ret , top . vars , true ) , ... prev ] , bnd : it . bnd } ] , st ] ;
827+ return [ [ { stack : cons ( frame ( top . atom , top . ret , top . vars , true ) , prev ) , bnd : it . bnd } ] , st ] ;
820828}
821829
822830// space-mutation helpers used by add/remove/import
@@ -1025,7 +1033,7 @@ function mettaEval(
10251033 }
10261034 const wApp = expr ( [ sym ( op ) , ...partAtoms ] ) ;
10271035 const [ pairs , st3 ] = interpretLoop ( env , fuel , cur2 , [
1028- { stack : atomToStack ( expr ( [ sym ( "eval" ) , wApp ] ) , [ ] ) , bnd } ,
1036+ { stack : atomToStack ( expr ( [ sym ( "eval" ) , wApp ] ) , null ) , bnd } ,
10291037 ] ) ;
10301038 cur2 = st3 ;
10311039 for ( const p of pairs ) {
@@ -1051,15 +1059,15 @@ function mettaEval(
10511059 if ( w . kind === "expr" && w . items . length > 0 ) {
10521060 // expression-headed application
10531061 const [ ruleRes , st1 ] = interpretLoop ( env , fuel , st , [
1054- { stack : atomToStack ( expr ( [ sym ( "eval" ) , w ] ) , [ ] ) , bnd } ,
1062+ { stack : atomToStack ( expr ( [ sym ( "eval" ) , w ] ) , null ) , bnd } ,
10551063 ] ) ;
10561064 const reduced = ruleRes . filter ( ( p ) => ! atomEq ( p [ 0 ] , w ) && ! atomEq ( p [ 0 ] , notReducibleA ) ) ;
10571065 if ( reduced . length === 0 ) {
10581066 const [ tupleRes , st2 ] = interpretLoop ( env , fuel , st1 , [
10591067 {
10601068 stack : atomToStack (
10611069 expr ( [ sym ( "eval" ) , expr ( [ sym ( "interpret-tuple" ) , w , sym ( "&self" ) ] ) ] ) ,
1062- [ ] ,
1070+ null ,
10631071 ) ,
10641072 bnd,
10651073 } ,
@@ -1088,7 +1096,7 @@ function mettaEval(
10881096
10891097 // bare symbol / variable / grounded
10901098 const [ pairs , st1 ] = interpretLoop ( env , fuel , st , [
1091- { stack : atomToStack ( expr ( [ sym ( "eval" ) , w ] ) , [ ] ) , bnd } ,
1099+ { stack : atomToStack ( expr ( [ sym ( "eval" ) , w ] ) , null ) , bnd } ,
10921100 ] ) ;
10931101 const out : Array < [ Atom , Bindings ] > = [ ] ;
10941102 let cur = st1 ;
0 commit comments