@@ -9,6 +9,7 @@ export class Eval {
99 /** Simple dotted path regex */
1010 private static readonly simplePathRegex =
1111 / ^ [ a - z A - Z _ $ ] [ a - z A - Z 0 - 9 _ $ ] * ( \. [ a - z A - Z _ $ ] [ a - z A - Z 0 - 9 _ $ ] * ) * $ /
12+
1213 /**
1314 * Evaluate expression in scope
1415 * @description Tokenizes, parses, and evaluates expression
@@ -31,66 +32,74 @@ export class Eval {
3132 parser . assertEnd ( )
3233 return Eval . evalNode ( astNode , scope )
3334 }
34- private static evalNode ( node : Types . ExprNode , scope : Record < string , unknown > ) : unknown {
35- if ( node . type === 'literal' ) {
36- return node . value
35+
36+ /**
37+ * Evaluate single AST node in scope.
38+ * @description Recursively evaluates literal, ident, member, ops.
39+ * @param exprNode - Expression AST node
40+ * @param scope - Scope data for identifiers
41+ * @returns Evaluated value
42+ */
43+ private static evalNode ( exprNode : Types . ExprNode , scope : Record < string , unknown > ) : unknown {
44+ if ( exprNode . type === 'literal' ) {
45+ return exprNode . value
3746 }
38- if ( node . type === 'ident' ) {
39- if ( node . name === 'true' ) {
47+ if ( exprNode . type === 'ident' ) {
48+ if ( exprNode . name === 'true' ) {
4049 return true
4150 }
42- if ( node . name === 'false' ) {
51+ if ( exprNode . name === 'false' ) {
4352 return false
4453 }
45- if ( node . name === 'null' ) {
54+ if ( exprNode . name === 'null' ) {
4655 return null
4756 }
48- if ( node . name === 'undefined' ) {
57+ if ( exprNode . name === 'undefined' ) {
4958 return undefined
5059 }
51- return scope [ node . name ]
60+ return scope [ exprNode . name ]
5261 }
53- if ( node . type === 'member' ) {
54- const objectValue = Eval . evalNode ( node . object , scope )
62+ if ( exprNode . type === 'member' ) {
63+ const objectValue = Eval . evalNode ( exprNode . object , scope )
5564 if ( objectValue === null || objectValue === undefined ) {
5665 return undefined
5766 }
5867 if ( typeof objectValue !== 'object' ) {
5968 return undefined
6069 }
61- return ( objectValue as Record < string , unknown > ) [ node . property ]
70+ return ( objectValue as Record < string , unknown > ) [ exprNode . property ]
6271 }
63- if ( node . type === 'unary' ) {
64- const argValue = Eval . evalNode ( node . arg , scope )
65- if ( node . op === '!' ) {
72+ if ( exprNode . type === 'unary' ) {
73+ const argValue = Eval . evalNode ( exprNode . arg , scope )
74+ if ( exprNode . op === '!' ) {
6675 return ! argValue
6776 }
68- if ( node . op === '+' ) {
77+ if ( exprNode . op === '+' ) {
6978 return typeof argValue === 'number' ? argValue : Number ( argValue )
7079 }
71- if ( node . op === '-' ) {
80+ if ( exprNode . op === '-' ) {
7281 return - ( typeof argValue === 'number' ? argValue : Number ( argValue ) )
7382 }
7483 return undefined
7584 }
76- if ( node . type === 'binary' ) {
77- if ( node . op === '&&' ) {
78- const leftValue = Eval . evalNode ( node . left , scope )
79- return leftValue ? Eval . evalNode ( node . right , scope ) : leftValue
85+ if ( exprNode . type === 'binary' ) {
86+ if ( exprNode . op === '&&' ) {
87+ const leftValue = Eval . evalNode ( exprNode . left , scope )
88+ return leftValue ? Eval . evalNode ( exprNode . right , scope ) : leftValue
8089 }
81- if ( node . op === '||' ) {
82- const leftValue = Eval . evalNode ( node . left , scope )
83- return leftValue ? leftValue : Eval . evalNode ( node . right , scope )
90+ if ( exprNode . op === '||' ) {
91+ const leftValue = Eval . evalNode ( exprNode . left , scope )
92+ return leftValue ? leftValue : Eval . evalNode ( exprNode . right , scope )
8493 }
85- if ( node . op === '??' ) {
86- const leftValue = Eval . evalNode ( node . left , scope )
94+ if ( exprNode . op === '??' ) {
95+ const leftValue = Eval . evalNode ( exprNode . left , scope )
8796 return leftValue === null || leftValue === undefined
88- ? Eval . evalNode ( node . right , scope )
97+ ? Eval . evalNode ( exprNode . right , scope )
8998 : leftValue
9099 }
91- const leftValue = Eval . evalNode ( node . left , scope )
92- const rightValue = Eval . evalNode ( node . right , scope )
93- switch ( node . op ) {
100+ const leftValue = Eval . evalNode ( exprNode . left , scope )
101+ const rightValue = Eval . evalNode ( exprNode . right , scope )
102+ switch ( exprNode . op ) {
94103 case '===' :
95104 return leftValue === rightValue
96105 case '!==' :
@@ -121,11 +130,11 @@ export class Eval {
121130 return undefined
122131 }
123132 }
124- if ( node . type === 'ternary' ) {
125- const testValue = Eval . evalNode ( node . test , scope )
133+ if ( exprNode . type === 'ternary' ) {
134+ const testValue = Eval . evalNode ( exprNode . test , scope )
126135 return testValue
127- ? Eval . evalNode ( node . consequent , scope )
128- : Eval . evalNode ( node . alternate , scope )
136+ ? Eval . evalNode ( exprNode . consequent , scope )
137+ : Eval . evalNode ( exprNode . alternate , scope )
129138 }
130139 return undefined
131140 }
0 commit comments