11'use strict' ;
22
3+ const async = require ( 'async' ) ;
4+ const fs = require ( 'fs' ) ;
35const RuntimeError = require ( './error/Runtime' ) ;
46
7+ const Parser = require ( './Parser' ) ;
8+ const Lexer = require ( './Lexer' ) ;
9+
10+ // credit: http://stackoverflow.com/a/3886106/124861
11+ function isFloat ( n ) {
12+ return Number ( n ) === n && n % 1 !== 0 ;
13+ }
14+
15+ function floatEqual ( a , b , epsilon = Number . EPSILON ) {
16+ if ( a === b ) {
17+ return true ;
18+ }
19+
20+ if ( isNaN ( a ) || isNaN ( b ) || ! isFinite ( a ) || ! isFinite ( b ) ) {
21+ return false ;
22+ }
23+
24+ const diff = Math . abs ( a - b ) ;
25+ return diff < epsilon ? true : diff <= Math . max ( Math . abs ( a ) , Math . abs ( b ) ) * epsilon ;
26+ }
27+
528const {
629 OPERATOR_EQUALS ,
730 OPERATOR_NOT_EQUALS ,
@@ -15,7 +38,6 @@ const {
1538 OPERATOR_GREATER_EQUAL_THAN ,
1639 OPERATOR_LESS_EQUAL_THAN ,
1740
18- PARSER_TYPE_ROOT ,
1941 PARSER_TYPE_TEXT_LITERAL ,
2042 PARSER_TYPE_INCLUDE ,
2143 PARSER_TYPE_VALUE ,
@@ -26,43 +48,64 @@ const {
2648} = require ( './constants' ) ;
2749
2850class Runner {
29- constructor ( ast , input ) {
30- this . ast = ast ;
31- this . input = input ;
51+ constructor ( ) {
52+ this . astCache = { } ;
3253 this . result = [ ] ;
3354 }
3455
35- invoke ( ) {
36- this . invokeRoot ( this . ast ) ;
56+ invoke ( ast , input , cb ) {
57+ this . result = [ ] ;
58+ this . input = input ;
59+ this . loadSources ( ast . sources , ( err ) => {
60+ return err ? cb ( err ) : cb ( null , this . invokeStatements ( ast . statements ) ) ;
61+ } ) ;
62+ }
63+
64+ loadSources ( sources , cb ) {
65+ const tasks = { } ;
66+
67+ for ( const value of sources ) {
68+ const path = value . type === PARSER_TYPE_VARIABLE ? this . getValueFromVariable ( value . name ) : value . value ;
69+ tasks [ path ] = fs . readFile . bind ( fs , path ) ;
70+ }
71+
72+ async . parallel ( tasks , ( err , files ) => {
73+ if ( err ) {
74+ return cb ( err ) ;
75+ }
76+ for ( const f in files ) {
77+ this . astCache [ f ] = new Parser ( new Lexer ( files [ f ] ) ) . generateAST ( ) ;
78+ }
79+ return cb ( ) ;
80+ } ) ;
3781 }
3882
39- invokeRoot ( ast ) {
40- for ( const statement in ast . statements ) {
83+ invokeStatements ( statements ) {
84+ for ( const statement of statements ) {
4185 if ( statement . type === PARSER_TYPE_TEXT_LITERAL ) {
4286 this . result . push ( statement . value ) ;
4387 }
4488 else if ( statement . type === PARSER_TYPE_INCLUDE ) {
4589 this . invokeInclude ( statement ) ;
4690 }
47- else ( statement . type === PARSER_TYPE_BRANCH ) {
91+ else if ( statement . type === PARSER_TYPE_BRANCH ) {
4892 this . invokeBranch ( statement ) ;
4993 }
94+ throw new RuntimeError ( `Unexpected statement: ${ statement } ` ) ;
5095 }
5196 }
5297
5398 invokeInclude ( statement ) {
54- const path = statement . value ;
5599
56- if ( typeof path !== string ) {
57- throw new RuntimeError ( 'Non string type passed to include.' )
58- }
59- // TODO: include other file
100+ if ( )
101+
102+ this . invoke ( ast ) ;
60103 }
61104
62105 invokeBranch ( statement ) {
63106 for ( const branch of statement . branches ) {
64- if ( this . evaluateExpression ( branch . condition ) ) {
65-
107+ if ( branch . condition === undefined || this . evaluateExpression ( branch . condition ) ) {
108+ return this . invokeStatements ( branch . consequent . statements ) ;
66109 }
67110 }
68111 }
@@ -78,38 +121,65 @@ class Runner {
78121 return expression . value ;
79122 }
80123 else if ( expression . type === PARSER_TYPE_VARIABLE ) {
81- return this . getValueFromVariable ( expression . value ) ;
124+ return this . getValueFromVariable ( expression . name ) ;
82125 }
83126 }
84127
85128 evaluateBinaryExpression ( expression ) {
129+ const leftValue = this . evaluateExpression ( expression . left ) ;
130+ const rightValue = this . evaluateExpression ( expression . right ) ;
131+
86132 if ( expression . operator === OPERATOR_EQUALS ) {
87- return this . evaluateExpression ( expression . left ) == this . evaluateExpression ( expression . right ) ;
133+ return this . evaluateEquals ( leftValue , rightValue ) ;
88134 }
89135
90136 if ( expression . operator === OPERATOR_NOT_EQUALS ) {
91- return this . evaluateExpression ( expression . left ) != this . evaluateExpression ( expression . right ) ;
137+ return ! this . evaluateEquals ( leftValue , rightValue ) ;
92138 }
93139
94140 if ( expression . operator === OPERATOR_STRICT_EQUALS ) {
95- return this . evaluateExpression ( expression . left ) === this . evaluateExpression ( expression . right ) ;
141+ return this . evaluateEquals ( leftValue , rightValue , true ) ;
96142 }
97143
98144 if ( expression . operator === OPERATOR_STRICT_NOT_EQUALS ) {
99- return this . evaluateExpression ( expression . left ) !== this . evaluateExpression ( expression . right ) ;
145+ return ! this . evaluateEquals ( leftValue , rightValue , true ) ;
146+ }
147+
148+ if ( expression . operator === OPERATOR_GREATER_EQUAL_THAN ) {
149+ return leftValue > rightValue || this . evaluateEquals ( leftValue , rightValue ) ;
150+ }
151+
152+ if ( expression . operator === OPERATOR_LESS_EQUAL_THAN ) {
153+ return leftValue < rightValue || this . evaluateEquals ( leftValue , rightValue ) ;
154+ }
155+
156+ if ( expression . operator === OPERATOR_GREATER_THAN ) {
157+ return leftValue > rightValue ;
158+ }
159+
160+ if ( expression . operator === OPERATOR_LESS_THAN ) {
161+ return leftValue > rightValue ;
100162 }
101163
102164 if ( expression . operator === OPERATOR_AND ) {
103- return this . evaluateExpression ( expression . left ) && this . evaluateExpression ( expression . right ) ;
165+ return leftValue && rightValue ;
104166 }
105167
106168 if ( expression . operator === OPERATOR_OR ) {
107- return this . evaluateExpression ( expression . left ) || this . evaluateExpression ( expression . right ) ;
169+ return leftValue || rightValue ;
108170 }
109171
110172 throw new RuntimeError ( `Unknown operator: ${ expression . operator } ` ) ;
111173 }
112174
175+ evaluateEquals ( leftValue , rightValue , strict = false ) {
176+ if ( isFloat ( leftValue ) && isFloat ( rightValue ) ) {
177+ return floatEqual ( leftValue , rightValue ) ;
178+ }
179+
180+ return strict ? leftValue === rightValue : leftValue == rightValue ;
181+ }
182+
113183 evaluateUnaryExpression ( expression ) {
114184 if ( expression . operator === OPERATOR_NOT ) {
115185 return ! this . evaluateExpression ( expression . expression ) ;
@@ -126,3 +196,5 @@ class Runner {
126196 }
127197
128198}
199+
200+ module . exports = Runner ;
0 commit comments