Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(154)

Side by Side Diff: packages/polymer_expressions/lib/parser.dart

Issue 2312183003: Removed Polymer from Observatory deps (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library polymer_expressions.parser;
6
7 import 'tokenizer.dart';
8 export 'tokenizer.dart' show ParseException;
9 import 'expression.dart';
10
11 const _UNARY_OPERATORS = const <String>['+', '-', '!'];
12 const _BINARY_OPERATORS = const <String>['+', '-', '*', '/', '%', '^', '==',
13 '!=', '>', '<', '>=', '<=', '||', '&&', '&', '===', '!==', '|'];
14
15 Expression parse(String expr) => new Parser(expr).parse();
16
17 class Parser {
18 final AstFactory _astFactory;
19 final Tokenizer _tokenizer;
20 List<Token> _tokens;
21 Iterator _iterator;
22 Token get _token => _iterator.current;
23
24 Parser(String input, {AstFactory astFactory})
25 : _tokenizer = new Tokenizer(input),
26 _astFactory = (astFactory == null) ? new AstFactory() : astFactory;
27
28 Expression parse() {
29 _tokens = _tokenizer.tokenize();
30 _iterator = _tokens.iterator;
31 _advance();
32 return _parseExpression();
33 }
34
35 _advance([int kind, String value]) {
36 if ((kind != null && (_token == null || _token.kind != kind))
37 || (value != null && (_token == null || _token.value != value))) {
38 throw new ParseException("Expected kind $kind ($value): $_token");
39 }
40 _iterator.moveNext();
41 }
42
43 Expression _parseExpression() {
44 if (_token == null) return _astFactory.empty();
45 var expr = _parseUnary();
46 return (expr == null) ? null : _parsePrecedence(expr, 0);
47 }
48
49 // _parsePrecedence and _parseBinary implement the precedence climbing
50 // algorithm as described in:
51 // http://en.wikipedia.org/wiki/Operator-precedence_parser#Precedence_climbing _method
52 Expression _parsePrecedence(Expression left, int precedence) {
53 assert(left != null);
54 while (_token != null) {
55 if (_token.kind == GROUPER_TOKEN) {
56 if (_token.value == '(') {
57 var args = _parseArguments();
58 assert(args != null);
59 left = _astFactory.invoke(left, null, args);
60 } else if (_token.value == '[') {
61 var indexExpr = _parseIndex();
62 left = _astFactory.index(left, indexExpr);
63 } else {
64 break;
65 }
66 } else if (_token.kind == DOT_TOKEN) {
67 _advance();
68 var right = _parseUnary();
69 left = _makeInvokeOrGetter(left, right);
70 } else if (_token.kind == KEYWORD_TOKEN) {
71 if (_token.value == 'in') {
72 left = _parseInExpression(left);
73 } else if (_token.value == 'as') {
74 left = _parseAsExpression(left);
75 } else {
76 break;
77 }
78 } else if (_token.kind == OPERATOR_TOKEN
79 && _token.precedence >= precedence) {
80 left = _token.value == '?' ? _parseTernary(left) : _parseBinary(left);
81 } else {
82 break;
83 }
84 }
85 return left;
86 }
87
88 // invoke or getter
89 Expression _makeInvokeOrGetter(left, right) {
90 if (right is Identifier) {
91 return _astFactory.getter(left, right.value);
92 } else if (right is Invoke && right.receiver is Identifier) {
93 Identifier method = right.receiver;
94 return _astFactory.invoke(left, method.value, right.arguments);
95 } else {
96 throw new ParseException("expected identifier: $right");
97 }
98 }
99
100 Expression _parseBinary(left) {
101 var op = _token;
102 if (!_BINARY_OPERATORS.contains(op.value)) {
103 throw new ParseException("unknown operator: ${op.value}");
104 }
105 _advance();
106 var right = _parseUnary();
107 while (_token != null
108 && (_token.kind == OPERATOR_TOKEN
109 || _token.kind == DOT_TOKEN
110 || _token.kind == GROUPER_TOKEN)
111 && _token.precedence > op.precedence) {
112 right = _parsePrecedence(right, _token.precedence);
113 }
114 return _astFactory.binary(left, op.value, right);
115 }
116
117 Expression _parseUnary() {
118 if (_token.kind == OPERATOR_TOKEN) {
119 var value = _token.value;
120 if (value == '+' || value == '-') {
121 _advance();
122 if (_token.kind == INTEGER_TOKEN) {
123 return _parseInteger(value);
124 } else if (_token.kind == DECIMAL_TOKEN) {
125 return _parseDecimal(value);
126 } else {
127 var expr = _parsePrecedence(_parsePrimary(), POSTFIX_PRECEDENCE);
128 return _astFactory.unary(value, expr);
129 }
130 } else if (value == '!') {
131 _advance();
132 var expr = _parsePrecedence(_parsePrimary(), POSTFIX_PRECEDENCE);
133 return _astFactory.unary(value, expr);
134 } else {
135 throw new ParseException("unexpected token: $value");
136 }
137 }
138 return _parsePrimary();
139 }
140
141 Expression _parseTernary(condition) {
142 _advance(OPERATOR_TOKEN, '?');
143 var trueExpr = _parseExpression();
144 _advance(COLON_TOKEN);
145 var falseExpr = _parseExpression();
146 return _astFactory.ternary(condition, trueExpr, falseExpr);
147 }
148
149 Expression _parsePrimary() {
150 var kind = _token.kind;
151 switch (kind) {
152 case KEYWORD_TOKEN:
153 var keyword = _token.value;
154 if (keyword == 'this') {
155 _advance();
156 // TODO(justin): return keyword node
157 return _astFactory.identifier('this');
158 } else if (KEYWORDS.contains(keyword)) {
159 throw new ParseException('unexpected keyword: $keyword');
160 }
161 throw new ParseException('unrecognized keyword: $keyword');
162 case IDENTIFIER_TOKEN:
163 return _parseInvokeOrIdentifier();
164 case STRING_TOKEN:
165 return _parseString();
166 case INTEGER_TOKEN:
167 return _parseInteger();
168 case DECIMAL_TOKEN:
169 return _parseDecimal();
170 case GROUPER_TOKEN:
171 if (_token.value == '(') {
172 return _parseParenthesized();
173 } else if (_token.value == '{') {
174 return _parseMapLiteral();
175 } else if (_token.value == '[') {
176 return _parseListLiteral();
177 }
178 return null;
179 case COLON_TOKEN:
180 throw new ParseException('unexpected token ":"');
181 default:
182 return null;
183 }
184 }
185
186 ListLiteral _parseListLiteral() {
187 var items = [];
188 do {
189 _advance();
190 if (_token.kind == GROUPER_TOKEN && _token.value == ']') {
191 break;
192 }
193 items.add(_parseExpression());
194 } while(_token != null && _token.value == ',');
195 _advance(GROUPER_TOKEN, ']');
196 return new ListLiteral(items);
197 }
198
199 MapLiteral _parseMapLiteral() {
200 var entries = [];
201 do {
202 _advance();
203 if (_token.kind == GROUPER_TOKEN && _token.value == '}') {
204 break;
205 }
206 entries.add(_parseMapLiteralEntry());
207 } while(_token != null && _token.value == ',');
208 _advance(GROUPER_TOKEN, '}');
209 return new MapLiteral(entries);
210 }
211
212 MapLiteralEntry _parseMapLiteralEntry() {
213 var key = _parseString();
214 _advance(COLON_TOKEN, ':');
215 var value = _parseExpression();
216 return _astFactory.mapLiteralEntry(key, value);
217 }
218
219 InExpression _parseInExpression(Expression left) {
220 assert(_token.value == 'in');
221 if (left is! Identifier) {
222 throw new ParseException(
223 "in... statements must start with an identifier");
224 }
225 _advance();
226 var right = _parseExpression();
227 return _astFactory.inExpr(left, right);
228 }
229
230 AsExpression _parseAsExpression(Expression left) {
231 assert(_token.value == 'as');
232 _advance();
233 var right = _parseExpression();
234 if (right is! Identifier) {
235 throw new ParseException(
236 "'as' statements must end with an identifier");
237 }
238 return _astFactory.asExpr(left, right);
239 }
240
241 Expression _parseInvokeOrIdentifier() {
242 if (_token.value == 'true') {
243 _advance();
244 return _astFactory.literal(true);
245 }
246 if (_token.value == 'false') {
247 _advance();
248 return _astFactory.literal(false);
249 }
250 if (_token.value == 'null') {
251 _advance();
252 return _astFactory.literal(null);
253 }
254 var identifier = _parseIdentifier();
255 var args = _parseArguments();
256 if (args == null) {
257 return identifier;
258 } else {
259 return _astFactory.invoke(identifier, null, args);
260 }
261 }
262
263 Identifier _parseIdentifier() {
264 if (_token.kind != IDENTIFIER_TOKEN) {
265 throw new ParseException("expected identifier: $_token.value");
266 }
267 var value = _token.value;
268 _advance();
269 return _astFactory.identifier(value);
270 }
271
272 List<Expression> _parseArguments() {
273 if (_token != null && _token.kind == GROUPER_TOKEN && _token.value == '(') {
274 var args = [];
275 do {
276 _advance();
277 if (_token.kind == GROUPER_TOKEN && _token.value == ')') {
278 break;
279 }
280 var expr = _parseExpression();
281 args.add(expr);
282 } while(_token != null && _token.value == ',');
283 _advance(GROUPER_TOKEN, ')');
284 return args;
285 }
286 return null;
287 }
288
289 Expression _parseIndex() {
290 if (_token != null && _token.kind == GROUPER_TOKEN && _token.value == '[') {
291 _advance();
292 var expr = _parseExpression();
293 _advance(GROUPER_TOKEN, ']');
294 return expr;
295 }
296 return null;
297 }
298
299 ParenthesizedExpression _parseParenthesized() {
300 _advance();
301 var expr = _parseExpression();
302 _advance(GROUPER_TOKEN, ')');
303 return _astFactory.parenthesized(expr);
304 }
305
306 Literal<String> _parseString() {
307 var value = _astFactory.literal(_token.value);
308 _advance();
309 return value;
310 }
311
312 Literal<int> _parseInteger([String prefix = '']) {
313 var value = _astFactory.literal(int.parse('$prefix${_token.value}'));
314 _advance();
315 return value;
316 }
317
318 Literal<double> _parseDecimal([String prefix = '']) {
319 var value = _astFactory.literal(double.parse('$prefix${_token.value}'));
320 _advance();
321 return value;
322 }
323
324 }
OLDNEW
« no previous file with comments | « packages/polymer_expressions/lib/filter.dart ('k') | packages/polymer_expressions/lib/polymer_expressions.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698