1- import { GetNodeFromKind , InstructionNode , isNode , Node , NodeKind , ProgramNode } from '@codama/nodes' ;
1+ import {
2+ assertIsNode ,
3+ GetNodeFromKind ,
4+ InstructionNode ,
5+ isNode ,
6+ Node ,
7+ NodeKind ,
8+ ProgramNode ,
9+ REGISTERED_NODE_KINDS ,
10+ } from '@codama/nodes' ;
11+
12+ import { NodePath } from './NodePath' ;
213
314export class NodeStack {
4- private readonly stack : Node [ ] ;
15+ /**
16+ * Contains all the node stacks saved during the traversal.
17+ *
18+ * - The very last stack is the current stack which is being
19+ * used during the traversal.
20+ * - The other stacks can be used to save and restore the
21+ * current stack when jumping to different parts of the tree.
22+ *
23+ * There must at least be one stack in the heap at all times.
24+ */
25+ private readonly heap : [ ...Node [ ] [ ] , Node [ ] ] ;
26+
27+ constructor ( ...heap : readonly [ ...( readonly ( readonly Node [ ] ) [ ] ) , readonly Node [ ] ] | readonly [ ] ) {
28+ this . heap = heap . length === 0 ? [ [ ] ] : ( [ ...heap . map ( nodes => [ ...nodes ] ) ] as [ ...Node [ ] [ ] , Node [ ] ] ) ;
29+ }
530
6- constructor ( stack : Node [ ] = [ ] ) {
7- this . stack = [ ... stack ] ;
31+ public get stack ( ) : Node [ ] {
32+ return this . heap [ this . heap . length - 1 ] ;
833 }
934
1035 public push ( node : Node ) : void {
@@ -19,6 +44,19 @@ export class NodeStack {
1944 return this . isEmpty ( ) ? undefined : this . stack [ this . stack . length - 1 ] ;
2045 }
2146
47+ public pushStack ( newStack : readonly Node [ ] = [ ] ) : void {
48+ this . heap . push ( [ ...newStack ] ) ;
49+ }
50+
51+ public popStack ( ) : readonly Node [ ] {
52+ const oldStack = this . heap . pop ( ) as Node [ ] ;
53+ if ( this . heap . length === 0 ) {
54+ // TODO: Coded error
55+ throw new Error ( 'The heap of stacks can never be empty.' ) ;
56+ }
57+ return [ ...oldStack ] as readonly Node [ ] ;
58+ }
59+
2260 public find < TKind extends NodeKind > ( kind : TKind | TKind [ ] ) : GetNodeFromKind < TKind > | undefined {
2361 for ( let index = this . stack . length - 1 ; index >= 0 ; index -- ) {
2462 const node = this . stack [ index ] ;
@@ -39,12 +77,18 @@ export class NodeStack {
3977 return [ ...this . stack ] ;
4078 }
4179
80+ public getPath < TKind extends NodeKind > ( kind ?: TKind | TKind [ ] ) : NodePath < GetNodeFromKind < TKind > > {
81+ const node = this . peek ( ) ;
82+ assertIsNode ( node , kind ?? REGISTERED_NODE_KINDS ) ;
83+ return [ ...this . stack ] as unknown as NodePath < GetNodeFromKind < TKind > > ;
84+ }
85+
4286 public isEmpty ( ) : boolean {
4387 return this . stack . length === 0 ;
4488 }
4589
4690 public clone ( ) : NodeStack {
47- return new NodeStack ( this . stack ) ;
91+ return new NodeStack ( ... this . heap ) ;
4892 }
4993
5094 public toString ( ) : string {
0 commit comments