OLD | NEW |
| (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.expression; | |
6 | |
7 import 'visitor.dart'; | |
8 | |
9 // Helper functions for building expression trees programmatically | |
10 | |
11 EmptyExpression empty() => const EmptyExpression(); | |
12 Literal literal(v) => new Literal(v); | |
13 ListLiteral listLiteral(List<Expression> items) => new ListLiteral(items); | |
14 MapLiteral mapLiteral(List<MapLiteralEntry> entries) => new MapLiteral(entries); | |
15 MapLiteralEntry mapLiteralEntry(Literal key, Expression value) => | |
16 new MapLiteralEntry(key, value); | |
17 Identifier ident(String v) => new Identifier(v); | |
18 ParenthesizedExpression paren(Expression e) => new ParenthesizedExpression(e); | |
19 UnaryOperator unary(String op, Expression e) => new UnaryOperator(op, e); | |
20 BinaryOperator binary(Expression l, String op, Expression r) => | |
21 new BinaryOperator(l, op, r); | |
22 Getter getter(Expression e, String m) => new Getter(e, m); | |
23 Index index(Expression e, Expression a) => new Index(e, a); | |
24 Invoke invoke(Expression e, String m, List<Expression> a) => | |
25 new Invoke(e, m, a); | |
26 InExpression inExpr(Expression l, Expression r) => new InExpression(l, r); | |
27 AsExpression asExpr(Expression l, Expression r) => new AsExpression(l, r); | |
28 TernaryOperator ternary(Expression c, Expression t, Expression f) => | |
29 new TernaryOperator(c, t, f); | |
30 | |
31 class AstFactory { | |
32 EmptyExpression empty() => const EmptyExpression(); | |
33 | |
34 Literal literal(v) => new Literal(v); | |
35 | |
36 MapLiteral mapLiteral(List<MapLiteralEntry> entries) => | |
37 new MapLiteral(entries); | |
38 | |
39 MapLiteralEntry mapLiteralEntry(Literal key, Expression value) => | |
40 new MapLiteralEntry(key, value); | |
41 | |
42 Identifier identifier(String v) => new Identifier(v); | |
43 | |
44 ParenthesizedExpression parenthesized(Expression e) => | |
45 new ParenthesizedExpression(e); | |
46 | |
47 UnaryOperator unary(String op, Expression e) => new UnaryOperator(op, e); | |
48 | |
49 BinaryOperator binary(Expression l, String op, Expression r) => | |
50 new BinaryOperator(l, op, r); | |
51 | |
52 TernaryOperator ternary(Expression c, Expression t, Expression f) => | |
53 new TernaryOperator(c, t, f); | |
54 | |
55 Getter getter(Expression g, String n) => new Getter(g, n); | |
56 | |
57 Index index(Expression e, Expression a) => new Index(e, a); | |
58 | |
59 Invoke invoke(Expression e, String m, List<Expression> a) => | |
60 new Invoke(e, m, a); | |
61 | |
62 InExpression inExpr(Expression l, Expression r) => new InExpression(l, r); | |
63 | |
64 AsExpression asExpr(Expression l, Expression r) => new AsExpression(l, r); | |
65 } | |
66 | |
67 /// Base class for all expressions | |
68 abstract class Expression { | |
69 const Expression(); | |
70 accept(Visitor v); | |
71 } | |
72 | |
73 abstract class HasIdentifier { | |
74 String get identifier; | |
75 Expression get expr; | |
76 } | |
77 | |
78 class EmptyExpression extends Expression { | |
79 const EmptyExpression(); | |
80 accept(Visitor v) => v.visitEmptyExpression(this); | |
81 } | |
82 | |
83 class Literal<T> extends Expression { | |
84 final T value; | |
85 | |
86 Literal(this.value); | |
87 | |
88 accept(Visitor v) => v.visitLiteral(this); | |
89 | |
90 String toString() => (value is String) ? '"$value"' : '$value'; | |
91 | |
92 bool operator ==(o) => o is Literal<T> && o.value == value; | |
93 | |
94 int get hashCode => value.hashCode; | |
95 } | |
96 | |
97 class ListLiteral extends Expression { | |
98 final List<Expression> items; | |
99 | |
100 ListLiteral(this.items); | |
101 | |
102 accept(Visitor v) => v.visitListLiteral(this); | |
103 | |
104 String toString() => "$items"; | |
105 | |
106 bool operator ==(o) => o is ListLiteral && _listEquals(o.items, items); | |
107 | |
108 int get hashCode => _hashList(items); | |
109 } | |
110 | |
111 class MapLiteral extends Expression { | |
112 final List<MapLiteralEntry> entries; | |
113 | |
114 MapLiteral(this.entries); | |
115 | |
116 accept(Visitor v) => v.visitMapLiteral(this); | |
117 | |
118 String toString() => "{$entries}"; | |
119 | |
120 bool operator ==(o) => o is MapLiteral && _listEquals(o.entries, entries); | |
121 | |
122 int get hashCode => _hashList(entries); | |
123 } | |
124 | |
125 class MapLiteralEntry extends Expression { | |
126 final Literal key; | |
127 final Expression entryValue; | |
128 | |
129 MapLiteralEntry(this.key, this.entryValue); | |
130 | |
131 accept(Visitor v) => v.visitMapLiteralEntry(this); | |
132 | |
133 String toString() => "$key: $entryValue"; | |
134 | |
135 bool operator ==(o) => o is MapLiteralEntry && o.key == key | |
136 && o.entryValue == entryValue; | |
137 | |
138 int get hashCode => _JenkinsSmiHash.hash2(key.hashCode, entryValue.hashCode); | |
139 } | |
140 | |
141 class ParenthesizedExpression extends Expression { | |
142 final Expression child; | |
143 | |
144 ParenthesizedExpression(this.child); | |
145 | |
146 accept(Visitor v) => v.visitParenthesizedExpression(this); | |
147 | |
148 String toString() => '($child)'; | |
149 | |
150 bool operator ==(o) => o is ParenthesizedExpression && o.child == child; | |
151 | |
152 int get hashCode => child.hashCode; | |
153 } | |
154 | |
155 class Identifier extends Expression { | |
156 final String value; | |
157 | |
158 Identifier(this.value); | |
159 | |
160 accept(Visitor v) => v.visitIdentifier(this); | |
161 | |
162 String toString() => value; | |
163 | |
164 bool operator ==(o) => o is Identifier && o.value == value; | |
165 | |
166 int get hashCode => value.hashCode; | |
167 } | |
168 | |
169 class UnaryOperator extends Expression { | |
170 final String operator; | |
171 final Expression child; | |
172 | |
173 UnaryOperator(this.operator, this.child); | |
174 | |
175 accept(Visitor v) => v.visitUnaryOperator(this); | |
176 | |
177 String toString() => '$operator $child'; | |
178 | |
179 bool operator ==(o) => o is UnaryOperator && o.operator == operator | |
180 && o.child == child; | |
181 | |
182 int get hashCode => _JenkinsSmiHash.hash2(operator.hashCode, child.hashCode); | |
183 } | |
184 | |
185 class BinaryOperator extends Expression { | |
186 final String operator; | |
187 final Expression left; | |
188 final Expression right; | |
189 | |
190 BinaryOperator(this.left, this.operator, this.right); | |
191 | |
192 accept(Visitor v) => v.visitBinaryOperator(this); | |
193 | |
194 String toString() => '($left $operator $right)'; | |
195 | |
196 bool operator ==(o) => o is BinaryOperator && o.operator == operator | |
197 && o.left == left && o.right == right; | |
198 | |
199 int get hashCode => _JenkinsSmiHash.hash3(operator.hashCode, left.hashCode, | |
200 right.hashCode); | |
201 } | |
202 | |
203 class TernaryOperator extends Expression { | |
204 final Expression condition; | |
205 final Expression trueExpr; | |
206 final Expression falseExpr; | |
207 | |
208 TernaryOperator(this.condition, this.trueExpr, this.falseExpr); | |
209 | |
210 accept(Visitor v) => v.visitTernaryOperator(this); | |
211 | |
212 String toString() => '($condition ? $trueExpr : $falseExpr)'; | |
213 | |
214 bool operator ==(o) => o is TernaryOperator | |
215 && o.condition == condition | |
216 && o.trueExpr == trueExpr | |
217 && o.falseExpr == falseExpr; | |
218 | |
219 int get hashCode => _JenkinsSmiHash.hash3(condition.hashCode, | |
220 trueExpr.hashCode, falseExpr.hashCode); | |
221 } | |
222 | |
223 class InExpression extends Expression implements HasIdentifier { | |
224 final Identifier left; | |
225 final Expression right; | |
226 | |
227 InExpression(this.left, this.right); | |
228 | |
229 accept(Visitor v) => v.visitInExpression(this); | |
230 | |
231 String get identifier => left.value; | |
232 | |
233 Expression get expr => right; | |
234 | |
235 String toString() => '($left in $right)'; | |
236 | |
237 bool operator ==(o) => o is InExpression && o.left == left | |
238 && o.right == right; | |
239 | |
240 int get hashCode => _JenkinsSmiHash.hash2(left.hashCode, right.hashCode); | |
241 } | |
242 | |
243 class AsExpression extends Expression implements HasIdentifier { | |
244 final Expression left; | |
245 final Identifier right; | |
246 | |
247 AsExpression(this.left, this.right); | |
248 | |
249 accept(Visitor v) => v.visitAsExpression(this); | |
250 | |
251 String get identifier => right.value; | |
252 | |
253 Expression get expr => left; | |
254 | |
255 String toString() => '($left as $right)'; | |
256 | |
257 bool operator ==(o) => o is AsExpression && o.left == left | |
258 && o.right == right; | |
259 | |
260 int get hashCode => _JenkinsSmiHash.hash2(left.hashCode, right.hashCode); | |
261 } | |
262 | |
263 class Index extends Expression { | |
264 final Expression receiver; | |
265 final Expression argument; | |
266 | |
267 Index(this.receiver, this.argument); | |
268 | |
269 accept(Visitor v) => v.visitIndex(this); | |
270 | |
271 String toString() => '$receiver[$argument]'; | |
272 | |
273 bool operator ==(o) => | |
274 o is Index | |
275 && o.receiver == receiver | |
276 && o.argument == argument; | |
277 | |
278 int get hashCode => | |
279 _JenkinsSmiHash.hash2(receiver.hashCode, argument.hashCode); | |
280 } | |
281 | |
282 class Getter extends Expression { | |
283 final Expression receiver; | |
284 final String name; | |
285 | |
286 Getter(this.receiver, this.name); | |
287 | |
288 accept(Visitor v) => v.visitGetter(this); | |
289 | |
290 String toString() => '$receiver.$name'; | |
291 | |
292 bool operator ==(o) => | |
293 o is Getter | |
294 && o.receiver == receiver | |
295 && o.name == name; | |
296 | |
297 int get hashCode => _JenkinsSmiHash.hash2(receiver.hashCode, name.hashCode); | |
298 | |
299 } | |
300 | |
301 /** | |
302 * Represents a function or method invocation. If [method] is null, then | |
303 * [receiver] is an expression that should evaluate to a function. If [method] | |
304 * is not null, then [receiver] is an expression that should evaluate to an | |
305 * object that has an appropriate method. | |
306 */ | |
307 class Invoke extends Expression { | |
308 final Expression receiver; | |
309 final String method; | |
310 final List<Expression> arguments; | |
311 | |
312 Invoke(this.receiver, this.method, this.arguments) { | |
313 assert(arguments != null); | |
314 } | |
315 | |
316 accept(Visitor v) => v.visitInvoke(this); | |
317 | |
318 String toString() => '$receiver.$method($arguments)'; | |
319 | |
320 bool operator ==(o) => | |
321 o is Invoke | |
322 && o.receiver == receiver | |
323 && o.method == method | |
324 && _listEquals(o.arguments, arguments); | |
325 | |
326 int get hashCode => _JenkinsSmiHash.hash3(receiver.hashCode, method.hashCode, | |
327 _hashList(arguments)); | |
328 } | |
329 | |
330 bool _listEquals(List a, List b) { | |
331 if (a == b) return true; | |
332 if (a == null || b == null) return false; | |
333 if (a.length != b.length) return false; | |
334 for (int i = 0; i < a.length; i++) { | |
335 if (a[i] != b[i]) return false; | |
336 } | |
337 return true; | |
338 } | |
339 | |
340 int _hashList(List l) { | |
341 var hash = l.fold(0, | |
342 (h, item) => _JenkinsSmiHash.combine(h, item.hashCode)); | |
343 return _JenkinsSmiHash.finish(hash); | |
344 } | |
345 | |
346 class _JenkinsSmiHash { | |
347 // TODO: Bug 11617- This class should be optimized and standardized elsewhere. | |
348 | |
349 static int combine(int hash, int value) { | |
350 hash = 0x1fffffff & (hash + value); | |
351 hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); | |
352 return hash ^ (hash >> 6); | |
353 } | |
354 | |
355 static int finish(int hash) { | |
356 hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); | |
357 hash = hash ^ (hash >> 11); | |
358 return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); | |
359 } | |
360 | |
361 static int hash2(int a, int b) => finish(combine(combine(0, a), b)); | |
362 | |
363 static int hash3(int a, int b, int c) => | |
364 finish(combine(combine(combine(0, a), b), c)); | |
365 | |
366 static int hash4(int a, int b, int c, int d) => | |
367 finish(combine(combine(combine(combine(0, a), b), c), d)); | |
368 } | |
OLD | NEW |