@@ -40,7 +40,8 @@ function parse(expression, categories, areas) {
40
40
* Parses a given list of tokens according to the following grammar.
41
41
*
42
42
* expression -> comparison (logicOperator comparison)*
43
- * comparison -> enumCategory comparator value | numericCategory numericComparator number | boolean | booleanCategory | booleanCategory comparator boolean | 'in_area_' area | value'(' expression ')'
43
+ * comparison -> enumCategory comparator value | numericCategory numericComparator number | boolean | booleanCategory |
44
+ * booleanCategory comparator boolean | 'in_area_' area | 'in_area_' area comparator boolean | value'(' expression ')'
44
45
* logicOperator -> '&&' | '||'
45
46
* comparator -> '==' | '!='
46
47
* numericComparator -> '>' | '<' | '>=' | '<=' | '==' | '!='
@@ -50,7 +51,7 @@ function parse(expression, categories, areas) {
50
51
*
51
52
* Note that we do not care about operator precedence between && and || because our aim is not
52
53
* actually evaluating the expression, but rather checking the validity.
53
- *
54
+ *
54
55
* The categories parameter is an object that maps category names to objects that contain the category type
55
56
* `enum`, `boolean` or `numeric` and a list of possible (string) values (for `enum` only).
56
57
*
@@ -75,8 +76,7 @@ function parseTokens(tokens, categories, areas) {
75
76
if ( v . type === 'enum' ) {
76
77
if ( v . values . length < 1 )
77
78
return error ( `no values given for enum category ${ k } ` ) ;
78
- }
79
- else if ( v . type !== 'boolean' && v . type !== 'numeric' )
79
+ } else if ( v . type !== 'boolean' && v . type !== 'numeric' )
80
80
return error ( `unknown category type: ${ v . type } for category ${ k } ` )
81
81
}
82
82
@@ -156,10 +156,10 @@ function parseBooleanLiteral() {
156
156
157
157
function parseBooleanComparison ( ) {
158
158
// rule: comparison -> booleanCategory
159
- if ( _idx + 1 === _tokens . length ) {
159
+ if ( _idx + 1 === _tokens . length ) {
160
160
_idx ++ ;
161
161
return valid ( ) ;
162
- } else if ( comparisonOperators . indexOf ( _tokens [ _idx + 1 ] ) < 0 ) {
162
+ } else if ( comparisonOperators . indexOf ( _tokens [ _idx + 1 ] ) < 0 ) {
163
163
_idx ++ ;
164
164
return valid ( ) ;
165
165
}
@@ -168,7 +168,7 @@ function parseBooleanComparison() {
168
168
return parseTripleComparison (
169
169
comparisonOperators ,
170
170
( category , operator , value ) => isBoolean ( value ) ,
171
- ( category , operator , value ) => [ 'true' , 'false' ]
171
+ ( category , operator , value ) => [ 'true' , 'false' ]
172
172
) ;
173
173
}
174
174
@@ -180,10 +180,23 @@ function parseArea() {
180
180
}
181
181
const area = token . substring ( `in_area_` . length )
182
182
if ( _areas . indexOf ( area ) < 0 ) {
183
- return error ( `unknown area: '${ area } '` , [ _idx , _idx + 1 ] , _areas . map ( a => 'in_area_' + a ) ) ;
183
+ return error ( `unknown area: '${ area } '` , [ _idx , _idx + 1 ] , _areas . map ( a => 'in_area_' + a ) ) ;
184
184
}
185
- _idx ++ ;
186
- return valid ( ) ;
185
+
186
+ // rule: comparison -> 'in_area_' area
187
+ if ( _idx + 1 === _tokens . length ) {
188
+ _idx ++ ;
189
+ return valid ( ) ;
190
+ } else if ( comparisonOperators . indexOf ( _tokens [ _idx + 1 ] ) < 0 ) {
191
+ _idx ++ ;
192
+ return valid ( ) ;
193
+ }
194
+ // rule: comparison -> 'in_area_' area comparator boolean
195
+ return parseTripleComparison (
196
+ comparisonOperators ,
197
+ ( category , operator , value ) => isBoolean ( value ) ,
198
+ ( category , operator , value ) => [ 'true' , 'false' ]
199
+ ) ;
187
200
}
188
201
189
202
function parseInvalidAreaOperator ( ) {
@@ -192,7 +205,7 @@ function parseInvalidAreaOperator() {
192
205
console . error ( `${ token } is a valid area operator and should have been detected earlier` ) ;
193
206
return ;
194
207
}
195
- return error ( `area names must be prefixed with 'in_area_'` , [ _idx , _idx + 1 ] , _areas . map ( a => 'in_area_' + a ) ) ;
208
+ return error ( `area names must be prefixed with 'in_area_'` , [ _idx , _idx + 1 ] , _areas . map ( a => 'in_area_' + a ) ) ;
196
209
}
197
210
198
211
function parseTripleComparison ( allowedComparators , isValid , getAllowedValues ) {
@@ -265,7 +278,7 @@ function isArea() {
265
278
function isInvalidAreaOperator ( ) {
266
279
const token = _tokens [ _idx ] ;
267
280
// typing something like in_area might be a common error so we provide some support for it
268
- return typeof token === 'string' && ( token . substr ( 0 , 3 ) === 'in_' || _areas . indexOf ( token ) >= 0 ) ;
281
+ return typeof token === 'string' && ( token . substr ( 0 , 3 ) === 'in_' || _areas . indexOf ( token ) >= 0 ) ;
269
282
}
270
283
271
284
function isCategory ( ) {
@@ -293,11 +306,11 @@ function isBoolean(value) {
293
306
}
294
307
295
308
function error ( error , range , completions ) {
296
- return { error, range, completions } ;
309
+ return { error, range, completions} ;
297
310
}
298
311
299
312
function valid ( ) {
300
- return { error : null , range : [ ] , completions : [ ] } ;
313
+ return { error : null , range : [ ] , completions : [ ] } ;
301
314
}
302
315
303
- export { parse , parseTokens } ;
316
+ export { parse , parseTokens } ;
0 commit comments