@@ -3,9 +3,9 @@ library angular.core.parser.dynamic_parser_impl;
3
3
import 'package:angular/core/parser/parser.dart' show ParserBackend;
4
4
import 'package:angular/core/parser/lexer.dart' ;
5
5
import 'package:angular/core/parser/syntax.dart' ;
6
+ import 'package:angular/core/parser/characters.dart' ;
6
7
7
8
class DynamicParserImpl {
8
- static Token EOF = new Token (- 1 , null );
9
9
final ParserBackend backend;
10
10
final String input;
11
11
final List <Token > tokens;
@@ -15,26 +15,28 @@ class DynamicParserImpl {
15
15
: this .input = input, tokens = lexer.call (input);
16
16
17
17
Token get peek {
18
- return (index < tokens.length) ? tokens[index] : EOF ;
18
+ return (index < tokens.length) ? tokens[index] : Token . EOF ;
19
19
}
20
20
21
21
parseChain () {
22
22
bool isChain = false ;
23
- while (optional ( ';' )) {
23
+ while (optionalCharacter ( $SEMICOLON )) {
24
24
isChain = true ;
25
25
}
26
26
List expressions = [];
27
27
while (index < tokens.length) {
28
- if (peek.text == ')' || peek.text == '}' || peek.text == ']' ) {
29
- error ('Unconsumed token ${peek .text }' );
28
+ if (peek.isCharacter ($RPAREN ) ||
29
+ peek.isCharacter ($RBRACE ) ||
30
+ peek.isCharacter ($RBRACKET )) {
31
+ error ('Unconsumed token $peek ' );
30
32
}
31
33
var expr = parseFilter ();
32
34
expressions.add (expr);
33
- while (optional ( ';' )) {
35
+ while (optionalCharacter ( $SEMICOLON )) {
34
36
isChain = true ;
35
37
}
36
38
if (isChain && expr is Filter ) {
37
- error ('cannot have a filter in a chain' );
39
+ error ('Cannot have a filter in a chain' );
38
40
}
39
41
}
40
42
return (expressions.length == 1 )
@@ -44,11 +46,10 @@ class DynamicParserImpl {
44
46
45
47
parseFilter () {
46
48
var result = parseExpression ();
47
- while (optional ('|' )) {
48
- String name = peek.text; // TODO(kasperl): Restrict to identifier?
49
- advance ();
49
+ while (optionalOperator ('|' )) {
50
+ String name = expectIdentifierOrKeyword ();
50
51
List arguments = [];
51
- while (optional ( ':' )) {
52
+ while (optionalCharacter ( $COLON )) {
52
53
// TODO(kasperl): Is this really supposed to be expressions?
53
54
arguments.add (parseExpression ());
54
55
}
@@ -60,13 +61,13 @@ class DynamicParserImpl {
60
61
parseExpression () {
61
62
int start = peek.index;
62
63
var result = parseConditional ();
63
- while (peek.text == '=' ) {
64
+ while (peek.isOperator ( '=' ) ) {
64
65
if (! backend.isAssignable (result)) {
65
66
int end = (index < tokens.length) ? peek.index : input.length;
66
67
String expression = input.substring (start, end);
67
68
error ('Expression $expression is not assignable' );
68
69
}
69
- expect ('=' );
70
+ expectOperator ('=' );
70
71
result = backend.newAssign (result, parseConditional ());
71
72
}
72
73
return result;
@@ -75,9 +76,9 @@ class DynamicParserImpl {
75
76
parseConditional () {
76
77
int start = peek.index;
77
78
var result = parseLogicalOr ();
78
- if (optional ('?' )) {
79
+ if (optionalOperator ('?' )) {
79
80
var yes = parseExpression ();
80
- if (! optional ( ':' )) {
81
+ if (! optionalCharacter ( $COLON )) {
81
82
int end = (index < tokens.length) ? peek.index : input.length;
82
83
String expression = input.substring (start, end);
83
84
error ('Conditional expression $expression requires all 3 expressions' );
@@ -91,7 +92,7 @@ class DynamicParserImpl {
91
92
parseLogicalOr () {
92
93
// '||'
93
94
var result = parseLogicalAnd ();
94
- while (optional ('||' )) {
95
+ while (optionalOperator ('||' )) {
95
96
result = backend.newBinaryLogicalOr (result, parseLogicalAnd ());
96
97
}
97
98
return result;
@@ -100,7 +101,7 @@ class DynamicParserImpl {
100
101
parseLogicalAnd () {
101
102
// '&&'
102
103
var result = parseEquality ();
103
- while (optional ('&&' )) {
104
+ while (optionalOperator ('&&' )) {
104
105
result = backend.newBinaryLogicalAnd (result, parseEquality ());
105
106
}
106
107
return result;
@@ -110,9 +111,9 @@ class DynamicParserImpl {
110
111
// '==','!='
111
112
var result = parseRelational ();
112
113
while (true ) {
113
- if (optional ('==' )) {
114
+ if (optionalOperator ('==' )) {
114
115
result = backend.newBinaryEqual (result, parseRelational ());
115
- } else if (optional ('!=' )) {
116
+ } else if (optionalOperator ('!=' )) {
116
117
result = backend.newBinaryNotEqual (result, parseRelational ());
117
118
} else {
118
119
return result;
@@ -124,13 +125,13 @@ class DynamicParserImpl {
124
125
// '<', '>', '<=', '>='
125
126
var result = parseAdditive ();
126
127
while (true ) {
127
- if (optional ('<' )) {
128
+ if (optionalOperator ('<' )) {
128
129
result = backend.newBinaryLessThan (result, parseAdditive ());
129
- } else if (optional ('>' )) {
130
+ } else if (optionalOperator ('>' )) {
130
131
result = backend.newBinaryGreaterThan (result, parseAdditive ());
131
- } else if (optional ('<=' )) {
132
+ } else if (optionalOperator ('<=' )) {
132
133
result = backend.newBinaryLessThanEqual (result, parseAdditive ());
133
- } else if (optional ('>=' )) {
134
+ } else if (optionalOperator ('>=' )) {
134
135
result = backend.newBinaryGreaterThanEqual (result, parseAdditive ());
135
136
} else {
136
137
return result;
@@ -142,9 +143,9 @@ class DynamicParserImpl {
142
143
// '+', '-'
143
144
var result = parseMultiplicative ();
144
145
while (true ) {
145
- if (optional ('+' )) {
146
+ if (optionalOperator ('+' )) {
146
147
result = backend.newBinaryPlus (result, parseMultiplicative ());
147
- } else if (optional ('-' )) {
148
+ } else if (optionalOperator ('-' )) {
148
149
result = backend.newBinaryMinus (result, parseMultiplicative ());
149
150
} else {
150
151
return result;
@@ -156,13 +157,13 @@ class DynamicParserImpl {
156
157
// '*', '%', '/', '~/'
157
158
var result = parsePrefix ();
158
159
while (true ) {
159
- if (optional ('*' )) {
160
+ if (optionalOperator ('*' )) {
160
161
result = backend.newBinaryMultiply (result, parsePrefix ());
161
- } else if (optional ('%' )) {
162
+ } else if (optionalOperator ('%' )) {
162
163
result = backend.newBinaryModulo (result, parsePrefix ());
163
- } else if (optional ('/' )) {
164
+ } else if (optionalOperator ('/' )) {
164
165
result = backend.newBinaryDivide (result, parsePrefix ());
165
- } else if (optional ('~/' )) {
166
+ } else if (optionalOperator ('~/' )) {
166
167
result = backend.newBinaryTruncatingDivide (result, parsePrefix ());
167
168
} else {
168
169
return result;
@@ -171,12 +172,12 @@ class DynamicParserImpl {
171
172
}
172
173
173
174
parsePrefix () {
174
- if (optional ('+' )) {
175
+ if (optionalOperator ('+' )) {
175
176
// TODO(kasperl): This is different than the original parser.
176
177
return backend.newPrefixPlus (parsePrefix ());
177
- } else if (optional ('-' )) {
178
+ } else if (optionalOperator ('-' )) {
178
179
return backend.newPrefixMinus (parsePrefix ());
179
- } else if (optional ('!' )) {
180
+ } else if (optionalOperator ('!' )) {
180
181
return backend.newPrefixNot (parsePrefix ());
181
182
} else {
182
183
return parseAccessOrCallMember ();
@@ -186,24 +187,22 @@ class DynamicParserImpl {
186
187
parseAccessOrCallMember () {
187
188
var result = parsePrimary ();
188
189
while (true ) {
189
- if (optional ('.' )) {
190
- // TODO(kasperl): Check that this is an identifier. Are keywords okay?
191
- String name = peek.text;
192
- advance ();
193
- if (optional ('(' )) {
194
- List arguments = parseExpressionList (')' );
195
- expect (')' );
190
+ if (optionalCharacter ($PERIOD )) {
191
+ String name = expectIdentifierOrKeyword ();
192
+ if (optionalCharacter ($LPAREN )) {
193
+ List arguments = parseExpressionList ($RPAREN );
194
+ expectCharacter ($RPAREN );
196
195
result = backend.newCallMember (result, name, arguments);
197
196
} else {
198
197
result = backend.newAccessMember (result, name);
199
198
}
200
- } else if (optional ( '[' )) {
199
+ } else if (optionalCharacter ( $LBRACKET )) {
201
200
var key = parseExpression ();
202
- expect ( ']' );
201
+ expectCharacter ( $RBRACKET );
203
202
result = backend.newAccessKeyed (result, key);
204
- } else if (optional ( '(' )) {
205
- List arguments = parseExpressionList (')' );
206
- expect ( ')' );
203
+ } else if (optionalCharacter ( $LPAREN )) {
204
+ List arguments = parseExpressionList ($RPAREN );
205
+ expectCharacter ( $RPAREN );
207
206
result = backend.newCallFunction (result, arguments);
208
207
} else {
209
208
return result;
@@ -212,90 +211,120 @@ class DynamicParserImpl {
212
211
}
213
212
214
213
parsePrimary () {
215
- if (optional ( '(' )) {
214
+ if (optionalCharacter ( $LPAREN )) {
216
215
var result = parseExpression ();
217
- expect ( ')' );
216
+ expectCharacter ( $RPAREN );
218
217
return result;
219
- } else if (optional ('null' ) || optional ('undefined' )) {
218
+ } else if (peek.isKeywordNull || peek.isKeywordUndefined) {
219
+ advance ();
220
220
return backend.newLiteralNull ();
221
- } else if (optional ('true' )) {
221
+ } else if (peek.isKeywordTrue) {
222
+ advance ();
222
223
return backend.newLiteralBoolean (true );
223
- } else if (optional ('false' )) {
224
+ } else if (peek.isKeywordFalse) {
225
+ advance ();
224
226
return backend.newLiteralBoolean (false );
225
- } else if (optional ( '[' )) {
226
- List elements = parseExpressionList (']' );
227
- expect ( ']' );
227
+ } else if (optionalCharacter ( $LBRACKET )) {
228
+ List elements = parseExpressionList ($RBRACKET );
229
+ expectCharacter ( $RBRACKET );
228
230
return backend.newLiteralArray (elements);
229
- } else if (peek.text == '{' ) {
231
+ } else if (peek.isCharacter ( $LBRACE ) ) {
230
232
return parseObject ();
231
- } else if (peek.key != null ) {
233
+ } else if (peek.isIdentifier ) {
232
234
return parseAccessOrCallScope ();
233
- } else if (peek.value != null ) {
234
- var value = peek.value;
235
+ } else if (peek.isNumber) {
236
+ num value = peek.toNumber ();
237
+ advance ();
238
+ return backend.newLiteralNumber (value);
239
+ } else if (peek.isString) {
240
+ String value = peek.toString ();
235
241
advance ();
236
- return (value is num )
237
- ? backend.newLiteralNumber (value)
238
- : backend.newLiteralString (value);
242
+ return backend.newLiteralString (value);
239
243
} else if (index >= tokens.length) {
240
244
throw 'Unexpected end of expression: $input ' ;
241
245
} else {
242
- error ('Unexpected token ${ peek . text } ' );
246
+ error ('Unexpected token $peek ' );
243
247
}
244
248
}
245
249
246
250
parseAccessOrCallScope () {
247
- String name = peek.key;
248
- advance ();
249
- if (! optional ('(' )) return backend.newAccessScope (name);
250
- List arguments = parseExpressionList (')' );
251
- expect (')' );
251
+ String name = expectIdentifierOrKeyword ();
252
+ if (! optionalCharacter ($LPAREN )) return backend.newAccessScope (name);
253
+ List arguments = parseExpressionList ($RPAREN );
254
+ expectCharacter ($RPAREN );
252
255
return backend.newCallScope (name, arguments);
253
256
}
254
257
255
258
parseObject () {
256
259
List <String > keys = [];
257
260
List values = [];
258
- expect ( '{' );
259
- if (peek.text != '}' ) {
261
+ expectCharacter ( $LBRACE );
262
+ if (! optionalCharacter ( $RBRACE ) ) {
260
263
do {
261
- // TODO(kasperl): Stricter checking. Only allow identifiers
262
- // and strings as keys. Maybe also keywords?
263
- var value = peek.value;
264
- keys.add (value is String ? value : peek.text);
265
- advance ();
266
- expect (':' );
264
+ String key = expectIdentifierOrKeywordOrString ();
265
+ keys.add (key);
266
+ expectCharacter ($COLON );
267
267
values.add (parseExpression ());
268
- } while (optional (',' ));
268
+ } while (optionalCharacter ($COMMA ));
269
+ expectCharacter ($RBRACE );
269
270
}
270
- expect ('}' );
271
271
return backend.newLiteralObject (keys, values);
272
272
}
273
273
274
- List parseExpressionList (String terminator) {
274
+ List parseExpressionList (int terminator) {
275
275
List result = [];
276
- if (peek.text != terminator) {
276
+ if (! peek.isCharacter ( terminator) ) {
277
277
do {
278
278
result.add (parseExpression ());
279
- } while (optional ( ',' ));
279
+ } while (optionalCharacter ( $COMMA ));
280
280
}
281
281
return result;
282
282
}
283
283
284
- bool optional (text ) {
285
- if (peek.text == text ) {
284
+ bool optionalCharacter ( int code ) {
285
+ if (peek.isCharacter (code) ) {
286
286
advance ();
287
287
return true ;
288
288
} else {
289
289
return false ;
290
290
}
291
291
}
292
292
293
- void expect (text ) {
294
- if (peek.text == text ) {
293
+ bool optionalOperator ( String operator ) {
294
+ if (peek.isOperator ( operator ) ) {
295
295
advance ();
296
+ return true ;
296
297
} else {
297
- error ('Missing expected $text ' );
298
+ return false ;
299
+ }
300
+ }
301
+
302
+ void expectCharacter (int code) {
303
+ if (optionalCharacter (code)) return ;
304
+ error ('Missing expected ${new String .fromCharCode (code )}' );
305
+ }
306
+
307
+ void expectOperator (String operator ) {
308
+ if (optionalOperator (operator )) return ;
309
+ error ('Missing expected operator $operator ' );
310
+ }
311
+
312
+ String expectIdentifierOrKeyword () {
313
+ if (! peek.isIdentifier && ! peek.isKeyword) {
314
+ error ('Unexpected token $peek , expected identifier or keyword' );
298
315
}
316
+ String result = peek.toString ();
317
+ advance ();
318
+ return result;
319
+ }
320
+
321
+ String expectIdentifierOrKeywordOrString () {
322
+ if (! peek.isIdentifier && ! peek.isKeyword && ! peek.isString) {
323
+ error ('Unexpected token $peek , expected identifier, keyword, or string' );
324
+ }
325
+ String result = peek.toString ();
326
+ advance ();
327
+ return result;
299
328
}
300
329
301
330
void advance () {
0 commit comments