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

Side by Side Diff: pkg/polymer_expression/lib/parser.dart

Issue 22950008: move fancy_syntax into Dart SVN (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: more readme edits Created 7 years, 4 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 | Annotate | Revision Log
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_expression.parser;
6
7 import 'tokenizer.dart';
8 import 'expression.dart';
9
10 const _UNARY_OPERATORS = const ['+', '-', '!'];
11
12 Expression parse(String expr) => new Parser(expr).parse();
13
14 class Parser {
15 final AstFactory _astFactory;
16 final Tokenizer _tokenizer;
17 List<Token> _tokens;
18 Iterator _iterator;
19 Token _token;
20
21 Parser(String input, {AstFactory astFactory})
22 : _tokenizer = new Tokenizer(input),
23 _astFactory = (astFactory == null) ? new AstFactory() : astFactory;
24
25 Expression parse() {
26 _tokens = _tokenizer.tokenize();
27 _iterator = _tokens.iterator;
28 _advance();
29 return _parseExpression();
30 }
31
32 _advance([int kind, String value]) {
33 if ((kind != null && _token.kind != kind)
34 || (value != null && _token.value != value)) {
35 throw new ParseException("Expected $value: $_token");
36 }
37 _token = _iterator.moveNext() ? _iterator.current : null;
38 }
39
40 Expression _parseExpression() {
41 if (_token == null) return _astFactory.empty();
42 var expr = _parseUnary();
43 return (expr == null) ? null : _parsePrecedence(expr, 0);
44 }
45
46 // _parsePrecedence and _parseBinary implement the precedence climbing
47 // algorithm as described in:
48 // http://en.wikipedia.org/wiki/Operator-precedence_parser#Precedence_climbing _method
49 Expression _parsePrecedence(Expression left, int precedence) {
50 assert(left != null);
51 while (_token != null) {
52 if (_token.kind == GROUPER_TOKEN) {
53 if (_token.value == '(') {
54 var args = _parseArguments();
55 left = _astFactory.invoke(left, null, args);
56 } else if (_token.value == '[') {
57 var indexExpr = _parseIndex();
58 var args = indexExpr == null ? [] : [indexExpr];
59 left = _astFactory.invoke(left, '[]', args);
60 } else {
61 break;
62 }
63 } else if (_token.kind == DOT_TOKEN) {
64 _advance();
65 var right = _parseUnary();
66 left = _makeInvoke(left, right);
67 } else if (_token.kind == KEYWORD_TOKEN && _token.value == 'in') {
68 left = _parseComprehension(left);
69 } else if (_token.kind == OPERATOR_TOKEN
70 && _token.precedence >= precedence) {
71 left = _parseBinary(left);
72 } else {
73 break;
74 }
75 }
76 return left;
77 }
78
79 Invoke _makeInvoke(left, right) {
80 if (right is Identifier) {
81 return _astFactory.invoke(left, right.value);
82 } else if (right is Invoke && right.receiver is Identifier) {
83 Identifier method = right.receiver;
84 return _astFactory.invoke(left, method.value, right.arguments);
85 } else {
86 throw new ParseException("expected identifier: $right");
87 }
88 }
89
90 Expression _parseBinary(left) {
91 var op = _token;
92 _advance();
93 var right = _parseUnary();
94 while (_token != null
95 && (_token.kind == OPERATOR_TOKEN
96 || _token.kind == DOT_TOKEN
97 || _token.kind == GROUPER_TOKEN)
98 && _token.precedence > op.precedence) {
99 right = _parsePrecedence(right, _token.precedence);
100 }
101 return _astFactory.binary(left, op.value, right);
102 }
103
104 Expression _parseUnary() {
105 if (_token.kind == OPERATOR_TOKEN) {
106 var value = _token.value;
107 if (value == '+' || value == '-') {
108 _advance();
109 if (_token.kind == INTEGER_TOKEN) {
110 return _parseInteger(value);
111 } else if (_token.kind == DECIMAL_TOKEN) {
112 return _parseDecimal(value);
113 } else {
114 var expr = _parsePrecedence(_parsePrimary(), POSTFIX_PRECEDENCE);
115 return _astFactory.unary(value, expr);
116 }
117 } else if (value == '!') {
118 _advance();
119 var expr = _parsePrecedence(_parsePrimary(), POSTFIX_PRECEDENCE);
120 return _astFactory.unary(value, expr);
121 }
122 }
123 return _parsePrimary();
124 }
125
126 Expression _parsePrimary() {
127 var kind = _token.kind;
128 switch (kind) {
129 case KEYWORD_TOKEN:
130 var keyword = _token.value;
131 if (keyword == 'this') {
132 _advance();
133 // TODO(justin): return keyword node
134 return _astFactory.identifier('this');
135 } else if (keyword == 'in') {
136 return null;
137 } else {
138 throw new ArgumentError('unrecognized keyword: $keyword');
139 }
140 break;
141 case IDENTIFIER_TOKEN:
142 return _parseInvokeOrIdentifier();
143 break;
144 case STRING_TOKEN:
145 return _parseString();
146 break;
147 case INTEGER_TOKEN:
148 return _parseInteger();
149 break;
150 case DECIMAL_TOKEN:
151 return _parseDecimal();
152 break;
153 case GROUPER_TOKEN:
154 if (_token.value == '(') {
155 return _parseParenthesized();
156 } else if (_token.value == '{') {
157 return _parseMapLiteral();
158 }
159 return null;
160 break;
161 default:
162 return null;
163 }
164 }
165
166 MapLiteral _parseMapLiteral() {
167 var entries = [];
168 do {
169 _advance();
170 if (_token.kind == GROUPER_TOKEN && _token.value == '}') {
171 break;
172 }
173 entries.add(_parseMapLiteralEntry());
174 } while(_token != null && _token.value == ',');
175 _advance(GROUPER_TOKEN, '}');
176 return new MapLiteral(entries);
177 }
178
179 MapLiteralEntry _parseMapLiteralEntry() {
180 var key = _parseString();
181 _advance(COLON_TOKEN, ':');
182 var value = _parseExpression();
183 return _astFactory.mapLiteralEntry(key, value);
184 }
185
186 InExpression _parseComprehension(Expression left) {
187 assert(_token.value == 'in');
188 if (left is! Identifier) {
189 throw new ParseException(
190 "in... statements must start with an identifier");
191 }
192 _advance();
193 var right = _parseExpression();
194 return _astFactory.inExpr(left, right);
195 }
196
197 Expression _parseInvokeOrIdentifier() {
198 if (_token.value == 'true') {
199 _advance();
200 return _astFactory.literal(true);
201 }
202 if (_token.value == 'false') {
203 _advance();
204 return _astFactory.literal(false);
205 }
206 var identifier = _parseIdentifier();
207 var args = _parseArguments();
208 if (args == null) {
209 return identifier;
210 } else {
211 return _astFactory.invoke(identifier, null, args);
212 }
213 }
214
215 Invoke _parseInvoke() {
216 var identifier = _parseIdentifier();
217 var args = _parseArguments();
218 return _astFactory.invoke(null, identifier, args);
219 }
220
221 Identifier _parseIdentifier() {
222 if (_token.kind != IDENTIFIER_TOKEN) {
223 throw new ParseException("expected identifier: $_token.value");
224 }
225 var value = _token.value;
226 _advance();
227 return _astFactory.identifier(value);
228 }
229
230 List<Expression> _parseArguments() {
231 if (_token != null && _token.kind == GROUPER_TOKEN && _token.value == '(') {
232 var args = [];
233 do {
234 _advance();
235 if (_token.kind == GROUPER_TOKEN && _token.value == ')') {
236 break;
237 }
238 var expr = _parseExpression();
239 args.add(expr);
240 } while(_token != null && _token.value == ',');
241 _advance(GROUPER_TOKEN, ')');
242 return args;
243 }
244 return null;
245 }
246
247 Expression _parseIndex() {
248 if (_token != null && _token.kind == GROUPER_TOKEN && _token.value == '[') {
249 _advance();
250 var expr = _parseExpression();
251 _advance(GROUPER_TOKEN, ']');
252 return expr;
253 }
254 return null;
255 }
256
257 ParenthesizedExpression _parseParenthesized() {
258 _advance();
259 var expr = _parseExpression();
260 _advance(GROUPER_TOKEN, ')');
261 return _astFactory.parenthesized(expr);
262 }
263
264 Literal<String> _parseString() {
265 var value = _astFactory.literal(_token.value);
266 _advance();
267 return value;
268 }
269
270 Literal<int> _parseInteger([String prefix = '']) {
271 var value = _astFactory.literal(int.parse('$prefix${_token.value}'));
272 _advance();
273 return value;
274 }
275
276 Literal<double> _parseDecimal([String prefix = '']) {
277 var value = _astFactory.literal(double.parse('$prefix${_token.value}'));
278 _advance();
279 return value;
280 }
281
282 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698