@@ -154,44 +154,33 @@ Lexer.prototype = {
154
154
lex : function ( text ) {
155
155
this . text = text ;
156
156
this . index = 0 ;
157
- this . ch = undefined ;
158
157
this . tokens = [ ] ;
159
158
160
- while ( this . index < this . text . length ) {
161
- this . ch = this . text . charAt ( this . index ) ;
162
- if ( this . is ( '"\'' ) ) {
163
- this . readString ( this . ch ) ;
164
- } else if ( this . isNumber ( this . ch ) || this . is ( '.' ) && this . isNumber ( this . peek ( ) ) ) {
159
+ var length = this . text . length ;
160
+
161
+ while ( this . index < length ) {
162
+ var ch = this . text . charAt ( this . index ) ;
163
+ if ( ch === '"' || ch === "'" ) {
164
+ this . readString ( ch ) ;
165
+ } else if ( this . isNumber ( ch ) || ( this . index < length - 1 ) && ch === '.' && this . isNumber ( this . peek ( ) ) ) {
165
166
this . readNumber ( ) ;
166
- } else if ( this . isIdent ( this . ch ) ) {
167
+ } else if ( this . isIdent ( ch ) ) {
167
168
this . readIdent ( ) ;
168
- } else if ( this . is ( '(){}[].,;:?' ) ) {
169
- this . tokens . push ( {
170
- index : this . index ,
171
- text : this . ch
172
- } ) ;
169
+ } else if ( '(){}[].,;:?' . indexOf ( ch ) !== - 1 ) {
170
+ this . tokens . push ( { index : this . index , text : ch } ) ;
173
171
this . index ++ ;
174
- } else if ( this . isWhitespace ( this . ch ) ) {
172
+ } else if ( this . isWhitespace ( ch ) ) {
175
173
this . index ++ ;
176
174
} else {
177
- var ch2 = this . ch + this . peek ( ) ;
175
+ var ch2 = ch + this . peek ( ) ;
178
176
var ch3 = ch2 + this . peek ( 2 ) ;
179
- var fn = OPERATORS [ this . ch ] ;
180
- var fn2 = OPERATORS [ ch2 ] ;
181
- var fn3 = OPERATORS [ ch3 ] ;
182
- if ( fn3 ) {
183
- this . tokens . push ( { index : this . index , text : ch3 , fn : fn3 } ) ;
184
- this . index += 3 ;
185
- } else if ( fn2 ) {
186
- this . tokens . push ( { index : this . index , text : ch2 , fn : fn2 } ) ;
187
- this . index += 2 ;
188
- } else if ( fn ) {
189
- this . tokens . push ( {
190
- index : this . index ,
191
- text : this . ch ,
192
- fn : fn
193
- } ) ;
194
- this . index += 1 ;
177
+ var op1 = OPERATORS [ ch ] ;
178
+ var op2 = OPERATORS [ ch2 ] ;
179
+ var op3 = OPERATORS [ ch3 ] ;
180
+ if ( op1 || op2 || op3 ) {
181
+ var token = op3 ? ch3 : ( op2 ? ch2 : ch ) ;
182
+ this . tokens . push ( { index : this . index , text : token , operator : true } ) ;
183
+ this . index += token . length ;
195
184
} else {
196
185
this . throwError ( 'Unexpected next character ' , this . index , this . index + 1 ) ;
197
186
}
@@ -200,10 +189,6 @@ Lexer.prototype = {
200
189
return this . tokens ;
201
190
} ,
202
191
203
- is : function ( chars ) {
204
- return chars . indexOf ( this . ch ) !== - 1 ;
205
- } ,
206
-
207
192
peek : function ( i ) {
208
193
var num = i || 1 ;
209
194
return ( this . index + num < this . text . length ) ? this . text . charAt ( this . index + num ) : false ;
@@ -263,79 +248,28 @@ Lexer.prototype = {
263
248
}
264
249
this . index ++ ;
265
250
}
266
- number = 1 * number ;
267
251
this . tokens . push ( {
268
252
index : start ,
269
253
text : number ,
270
254
constant : true ,
271
- fn : function ( ) { return number ; }
255
+ value : Number ( number )
272
256
} ) ;
273
257
} ,
274
258
275
259
readIdent : function ( ) {
276
- var expression = this . text ;
277
-
278
- var ident = '' ;
279
260
var start = this . index ;
280
-
281
- var lastDot , peekIndex , methodName , ch ;
282
-
283
261
while ( this . index < this . text . length ) {
284
- ch = this . text . charAt ( this . index ) ;
285
- if ( ch === '.' || this . isIdent ( ch ) || this . isNumber ( ch ) ) {
286
- if ( ch === '.' ) lastDot = this . index ;
287
- ident += ch ;
288
- } else {
262
+ var ch = this . text . charAt ( this . index ) ;
263
+ if ( ! ( this . isIdent ( ch ) || this . isNumber ( ch ) ) ) {
289
264
break ;
290
265
}
291
266
this . index ++ ;
292
267
}
293
-
294
- //check if the identifier ends with . and if so move back one char
295
- if ( lastDot && ident [ ident . length - 1 ] === '.' ) {
296
- this . index -- ;
297
- ident = ident . slice ( 0 , - 1 ) ;
298
- lastDot = ident . lastIndexOf ( '.' ) ;
299
- if ( lastDot === - 1 ) {
300
- lastDot = undefined ;
301
- }
302
- }
303
-
304
- //check if this is not a method invocation and if it is back out to last dot
305
- if ( lastDot ) {
306
- peekIndex = this . index ;
307
- while ( peekIndex < this . text . length ) {
308
- ch = this . text . charAt ( peekIndex ) ;
309
- if ( ch === '(' ) {
310
- methodName = ident . substr ( lastDot - start + 1 ) ;
311
- ident = ident . substr ( 0 , lastDot - start ) ;
312
- this . index = peekIndex ;
313
- break ;
314
- }
315
- if ( this . isWhitespace ( ch ) ) {
316
- peekIndex ++ ;
317
- } else {
318
- break ;
319
- }
320
- }
321
- }
322
-
323
268
this . tokens . push ( {
324
269
index : start ,
325
- text : ident ,
326
- fn : CONSTANTS [ ident ] || getterFn ( ident , this . options , expression )
270
+ text : this . text . slice ( start , this . index ) ,
271
+ identifier : true
327
272
} ) ;
328
-
329
- if ( methodName ) {
330
- this . tokens . push ( {
331
- index : lastDot ,
332
- text : '.'
333
- } ) ;
334
- this . tokens . push ( {
335
- index : lastDot + 1 ,
336
- text : methodName
337
- } ) ;
338
- }
339
273
} ,
340
274
341
275
readString : function ( quote ) {
@@ -366,9 +300,8 @@ Lexer.prototype = {
366
300
this . tokens . push ( {
367
301
index : start ,
368
302
text : rawString ,
369
- string : string ,
370
303
constant : true ,
371
- fn : function ( ) { return string ; }
304
+ value : string
372
305
} ) ;
373
306
return ;
374
307
} else {
@@ -429,16 +362,12 @@ Parser.prototype = {
429
362
primary = this . arrayDeclaration ( ) ;
430
363
} else if ( this . expect ( '{' ) ) {
431
364
primary = this . object ( ) ;
365
+ } else if ( this . peek ( ) . identifier ) {
366
+ primary = this . identifier ( ) ;
367
+ } else if ( this . peek ( ) . constant ) {
368
+ primary = this . constant ( ) ;
432
369
} else {
433
- var token = this . expect ( ) ;
434
- primary = token . fn ;
435
- if ( ! primary ) {
436
- this . throwError ( 'not a primary expression' , token ) ;
437
- }
438
- if ( token . constant ) {
439
- primary . constant = true ;
440
- primary . literal = true ;
441
- }
370
+ this . throwError ( 'not a primary expression' , this . peek ( ) ) ;
442
371
}
443
372
444
373
var next , context ;
@@ -472,8 +401,11 @@ Parser.prototype = {
472
401
} ,
473
402
474
403
peek : function ( e1 , e2 , e3 , e4 ) {
475
- if ( this . tokens . length > 0 ) {
476
- var token = this . tokens [ 0 ] ;
404
+ return this . peekAhead ( 0 , e1 , e2 , e3 , e4 ) ;
405
+ } ,
406
+ peekAhead : function ( i , e1 , e2 , e3 , e4 ) {
407
+ if ( this . tokens . length > i ) {
408
+ var token = this . tokens [ i ] ;
477
409
var t = token . text ;
478
410
if ( t === e1 || t === e2 || t === e3 || t === e4 ||
479
411
( ! e1 && ! e2 && ! e3 && ! e4 ) ) {
@@ -493,12 +425,19 @@ Parser.prototype = {
493
425
} ,
494
426
495
427
consume : function ( e1 ) {
496
- if ( ! this . expect ( e1 ) ) {
428
+ if ( this . tokens . length === 0 ) {
429
+ throw $parseMinErr ( 'ueoe' , 'Unexpected end of expression: {0}' , this . text ) ;
430
+ }
431
+
432
+ var token = this . expect ( e1 ) ;
433
+ if ( ! token ) {
497
434
this . throwError ( 'is unexpected, expecting [' + e1 + ']' , this . peek ( ) ) ;
498
435
}
436
+ return token ;
499
437
} ,
500
438
501
- unaryFn : function ( fn , right ) {
439
+ unaryFn : function ( op , right ) {
440
+ var fn = OPERATORS [ op ] ;
502
441
return extend ( function $parseUnaryFn ( self , locals ) {
503
442
return fn ( self , locals , right ) ;
504
443
} , {
@@ -507,7 +446,8 @@ Parser.prototype = {
507
446
} ) ;
508
447
} ,
509
448
510
- binaryFn : function ( left , fn , right , isBranching ) {
449
+ binaryFn : function ( left , op , right , isBranching ) {
450
+ var fn = OPERATORS [ op ] ;
511
451
return extend ( function $parseBinaryFn ( self , locals ) {
512
452
return fn ( self , locals , left , right ) ;
513
453
} , {
@@ -516,6 +456,28 @@ Parser.prototype = {
516
456
} ) ;
517
457
} ,
518
458
459
+ identifier : function ( ) {
460
+ var id = this . consume ( ) . text ;
461
+
462
+ //Continue reading each `.identifier` unless it is a method invocation
463
+ while ( this . peekAhead ( 1 ) . identifier && ! this . peekAhead ( 2 , '(' ) && this . expect ( '.' ) ) {
464
+ id += '.' + this . consume ( ) . text ;
465
+ }
466
+
467
+ return CONSTANTS [ id ] || getterFn ( id , this . options , this . text ) ;
468
+ } ,
469
+
470
+ constant : function ( ) {
471
+ var value = this . consume ( ) . value ;
472
+
473
+ return extend ( function $parseConstant ( ) {
474
+ return value ;
475
+ } , {
476
+ constant : true ,
477
+ literal : true
478
+ } ) ;
479
+ } ,
480
+
519
481
statements : function ( ) {
520
482
var statements = [ ] ;
521
483
while ( true ) {
@@ -547,8 +509,7 @@ Parser.prototype = {
547
509
} ,
548
510
549
511
filter : function ( inputFn ) {
550
- var token = this . expect ( ) ;
551
- var fn = this . $filter ( token . text ) ;
512
+ var fn = this . $filter ( this . consume ( ) . text ) ;
552
513
var argsFn ;
553
514
var args ;
554
515
@@ -632,7 +593,7 @@ Parser.prototype = {
632
593
var left = this . logicalAND ( ) ;
633
594
var token ;
634
595
while ( ( token = this . expect ( '||' ) ) ) {
635
- left = this . binaryFn ( left , token . fn , this . logicalAND ( ) , true ) ;
596
+ left = this . binaryFn ( left , token . text , this . logicalAND ( ) , true ) ;
636
597
}
637
598
return left ;
638
599
} ,
@@ -641,7 +602,7 @@ Parser.prototype = {
641
602
var left = this . equality ( ) ;
642
603
var token ;
643
604
if ( ( token = this . expect ( '&&' ) ) ) {
644
- left = this . binaryFn ( left , token . fn , this . logicalAND ( ) , true ) ;
605
+ left = this . binaryFn ( left , token . text , this . logicalAND ( ) , true ) ;
645
606
}
646
607
return left ;
647
608
} ,
@@ -650,7 +611,7 @@ Parser.prototype = {
650
611
var left = this . relational ( ) ;
651
612
var token ;
652
613
if ( ( token = this . expect ( '==' , '!=' , '===' , '!==' ) ) ) {
653
- left = this . binaryFn ( left , token . fn , this . equality ( ) ) ;
614
+ left = this . binaryFn ( left , token . text , this . equality ( ) ) ;
654
615
}
655
616
return left ;
656
617
} ,
@@ -659,7 +620,7 @@ Parser.prototype = {
659
620
var left = this . additive ( ) ;
660
621
var token ;
661
622
if ( ( token = this . expect ( '<' , '>' , '<=' , '>=' ) ) ) {
662
- left = this . binaryFn ( left , token . fn , this . relational ( ) ) ;
623
+ left = this . binaryFn ( left , token . text , this . relational ( ) ) ;
663
624
}
664
625
return left ;
665
626
} ,
@@ -668,7 +629,7 @@ Parser.prototype = {
668
629
var left = this . multiplicative ( ) ;
669
630
var token ;
670
631
while ( ( token = this . expect ( '+' , '-' ) ) ) {
671
- left = this . binaryFn ( left , token . fn , this . multiplicative ( ) ) ;
632
+ left = this . binaryFn ( left , token . text , this . multiplicative ( ) ) ;
672
633
}
673
634
return left ;
674
635
} ,
@@ -677,7 +638,7 @@ Parser.prototype = {
677
638
var left = this . unary ( ) ;
678
639
var token ;
679
640
while ( ( token = this . expect ( '*' , '/' , '%' ) ) ) {
680
- left = this . binaryFn ( left , token . fn , this . unary ( ) ) ;
641
+ left = this . binaryFn ( left , token . text , this . unary ( ) ) ;
681
642
}
682
643
return left ;
683
644
} ,
@@ -687,17 +648,17 @@ Parser.prototype = {
687
648
if ( this . expect ( '+' ) ) {
688
649
return this . primary ( ) ;
689
650
} else if ( ( token = this . expect ( '-' ) ) ) {
690
- return this . binaryFn ( Parser . ZERO , token . fn , this . unary ( ) ) ;
651
+ return this . binaryFn ( Parser . ZERO , token . text , this . unary ( ) ) ;
691
652
} else if ( ( token = this . expect ( '!' ) ) ) {
692
- return this . unaryFn ( token . fn , this . unary ( ) ) ;
653
+ return this . unaryFn ( token . text , this . unary ( ) ) ;
693
654
} else {
694
655
return this . primary ( ) ;
695
656
}
696
657
} ,
697
658
698
659
fieldAccess : function ( object ) {
699
660
var expression = this . text ;
700
- var field = this . expect ( ) . text ;
661
+ var field = this . consume ( ) . text ;
701
662
var getter = getterFn ( field , this . options , expression ) ;
702
663
703
664
return extend ( function $parseFieldAccess ( scope , locals , self ) {
@@ -782,8 +743,7 @@ Parser.prototype = {
782
743
// Support trailing commas per ES5.1.
783
744
break ;
784
745
}
785
- var elementFn = this . expression ( ) ;
786
- elementFns . push ( elementFn ) ;
746
+ elementFns . push ( this . expression ( ) ) ;
787
747
} while ( this . expect ( ',' ) ) ;
788
748
}
789
749
this . consume ( ']' ) ;
@@ -809,11 +769,10 @@ Parser.prototype = {
809
769
// Support trailing commas per ES5.1.
810
770
break ;
811
771
}
812
- var token = this . expect ( ) ;
813
- keys . push ( token . string || token . text ) ;
772
+ var token = this . consume ( ) ;
773
+ keys . push ( ( 'value' in token ) ? token . value : token . text ) ;
814
774
this . consume ( ':' ) ;
815
- var value = this . expression ( ) ;
816
- valueFns . push ( value ) ;
775
+ valueFns . push ( this . expression ( ) ) ;
817
776
} while ( this . expect ( ',' ) ) ;
818
777
}
819
778
this . consume ( '}' ) ;
0 commit comments