11/**
2- |--------------------------------------------------
32 | This traverses the AST step by step. Each step only evaluates one "atomic"
43 | statement, like an assignment statement or a function call statement. The
54 | stepping follows the semantics of the program. The order of statements
65 | executed with stepEval is the same as the order of statements executed with
76 | normal eval. To use it, you pass in the AST and an index / location into
8- | the AST. It evaluates the first atomic element following that index and
9- | returns the result along with the index for the next atomic element in the
10- | AST.
7+ | the AST. It evaluates the first atomic element AT that index and returns
8+ | the result along with the index of the NEXT atomic element in the AST to
9+ | evaluate.
10+
11+ | A tree location is a a list of integers. The absolute index of the root
12+ | node is [] or [0]. They are equivalent. The absolute index of the root
13+ | node's first child is [0, 0], the second child is [0, 1], etc. Sometimes an
14+ | index is expressed relative to a position in the tree. Assume the current
15+ | position is a block. The index of the block's first statement is [x, 0]
16+ | where x is the position of the block relative to its parent. If the current
17+ | context is a block that is the second child of its parent, the index for
18+ | the block's third child is [1, 2]. In keeping with the equivalence of []
19+ | and [0] for the root node, the index for the block's first child can be
20+ | expressed as [x, 0] or just [x]. Based on these rules, its also the case
21+ | that the first (bottom-left most statement) of the entire tree is []. This
22+ | is useful for pointing to the start of the program without knowing the
23+ | structure of the tree. The "real" index of the start will eventually be
24+ | unfolded as [0, 0, ..., 0] as stepEval runs.
25+
26+ | Why do we need to pass the index relative to the parent to every stepEval
27+ | method? It's true that it is not necessary at all to step through that
28+ | function, but it is a compact way for a stepEval method to communicate when
29+ | done with its done with a segment of the tree. For instance, if a stepEval
30+ | is passed [4, 3] as a location and returns [5], its easy to see that we've
31+ | finished with the subtree rooted at [4] and have moved on to the sibling of
32+ | our tree (located at [5]). It could also work for each function to return a
33+ | separate boolean to say "I'm done", but they are not significantly
34+ | different.
35+
36+ | stepEvalBlock(block, [], ns) evaluates the first item of the block and
37+ | returns the result of that expression along with the index of the next
38+ | expression to evaluate. So does stepEvalBlock(block, [x], ns), and
39+ | stepEvalBlock(block, [x, 0], ns). The next index can be either [x, 1] or
40+ | [x+1] depending on the length of the block. If the block has zero length,
41+ | any location argument will evaluate nothing, step out of the block, and
42+ | return [x+1].
43+
1144 |--------------------------------------------------
1245*/
1346
@@ -57,8 +90,18 @@ function stepEvalTimes(args, loc, env) {
5790 throw new Error ( 'Invalid "times" statement.' ) ;
5891 }
5992
93+ if ( loc . length == 0 ) {
94+ console . log ( "First stepEvalTimes call" ) ;
95+ console . log ( "args" , args ) ;
96+ }
97+
6098 let result , childPath ;
99+
61100 let index = loc [ 0 ] || 0 ;
101+
102+ // upon entry, the loc is [] or [0]. The loc for the items in the times
103+ // statement's block is [1, x] where 1 indicates that the block is this time
104+ // statement's second child. x is the index into the block.
62105 if ( loc . slice ( 1 ) . length != 0 ) {
63106 childPath = loc . slice ( 1 ) ;
64107 } else {
@@ -76,16 +119,19 @@ function stepEvalTimes(args, loc, env) {
76119
77120 [ result , newLoc ] = stepEvalAST ( body , childPath , env ) ;
78121
122+ console . log ( "FROM" , childPath ) ;
123+ console . log ( "TO" , newLoc ) ;
124+
79125 // if reached end of block
80- if ( newLoc [ 0 ] >= index + 1 ) {
126+ if ( newLoc [ 0 ] > 1 ) {
81127 iter += 1 ;
82128
83- if ( iter > times ) {
129+ if ( iter >= times ) {
84130 // if passed through loop enough times, move outside of loop
85131 newLoc = [ index + 1 ] ;
86132 } else {
87133 // otherwise, move to the beginning of loop
88- newLoc = [ index , 0 ] ;
134+ newLoc = [ index , 1 , 0 ] ;
89135 }
90136 } else {
91137 newLoc . unshift ( index ) ;
@@ -96,9 +142,9 @@ function stepEvalTimes(args, loc, env) {
96142 [ result , newLoc ] = stepEvalAST ( body , childPath , env ) ;
97143
98144 // if reached end of block
99- if ( newLoc [ 0 ] >= index + 1 ) {
145+ if ( newLoc [ 0 ] > 1 ) {
100146 // move to beginning of loop
101- newLoc = [ index , 0 ] ;
147+ newLoc = [ index , 1 , 0 ] ;
102148 } else {
103149 newLoc . unshift ( index ) ;
104150 }
0 commit comments