OLD | NEW |
| (Empty) |
1 // Copyright (c) 2017, 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 /// Minimal AST used to represent constant and initializer expressions. | |
6 /// | |
7 /// The AST definitions here are kept small by removing anything that we don't | |
8 /// need for the purpose of summarization: | |
9 /// | |
10 /// * A tree representing constants will not contain nodes that are not | |
11 /// allowed. If a parsed program contains a subexpression that is invalid, | |
12 /// we'll represent it with an `Invalid` node. | |
13 /// | |
14 /// * A tree representing initializers will only contain the subset of the | |
15 /// initializer expression that is needed to infer the type of the initialized | |
16 /// variable. For example, function closures, arguments to constructors, and | |
17 /// other similar bits are hidden using `Opaque` nodes. | |
18 library summary.src.expressions; | |
19 | |
20 // We reuse the scanner constants to represent all binary and unary operators. | |
21 import 'visitor.dart'; | |
22 | |
23 export 'visitor.dart'; | |
24 | |
25 /// A cast expression. | |
26 class As extends Expression { | |
27 final Expression exp; | |
28 final TypeRef type; | |
29 As(this.exp, this.type); | |
30 | |
31 bool get isAs => true; | |
32 accept(v) => v.visitAs(this); | |
33 toString() => '$exp as $type'; | |
34 } | |
35 | |
36 /// All binary expressions, including if-null. | |
37 class Binary extends Expression { | |
38 final Expression left; | |
39 final Expression right; | |
40 final int operator; | |
41 Binary(this.left, this.right, this.operator); | |
42 | |
43 bool get isBinary => true; | |
44 accept(v) => v.visitBinary(this); | |
45 toString() => '$left _ $right'; | |
46 } | |
47 | |
48 /// A literal like `false`. | |
49 class BoolLiteral extends Expression { | |
50 final bool value; | |
51 BoolLiteral(this.value); | |
52 | |
53 accept(v) => v.visitBool(this); | |
54 toString() => '$value'; | |
55 } | |
56 | |
57 /// Expressions like `a ? b : c`. | |
58 class Conditional extends Expression { | |
59 final Expression test; | |
60 final Expression trueBranch; | |
61 final Expression falseBranch; | |
62 Conditional(this.test, this.trueBranch, this.falseBranch); | |
63 | |
64 bool get isConditional => true; | |
65 accept(v) => v.visitConditional(this); | |
66 toString() => '$test ? $trueBranch : $falseBranch'; | |
67 } | |
68 | |
69 /// A `const Foo()` creation. | |
70 class ConstCreation extends Expression { | |
71 final ConstructorName constructor; | |
72 | |
73 /// Passed arguments, which can be expressions (if the argument is positional) | |
74 /// or a [NamedArg]. | |
75 final List<Expression> positionalArgs; | |
76 final List<NamedArg> namedArgs; | |
77 ConstCreation(this.constructor, this.positionalArgs, this.namedArgs); | |
78 | |
79 accept(v) => v.visitConstCreation(this); | |
80 } | |
81 | |
82 /// The type and possibly name of a constructor. | |
83 class ConstructorName { | |
84 final TypeRef type; | |
85 final String name; | |
86 ConstructorName(this.type, this.name); | |
87 | |
88 toString() => "ctor: $type.$name"; | |
89 } | |
90 | |
91 /// A literal like `1.2`. | |
92 class DoubleLiteral extends Expression { | |
93 final double value; | |
94 DoubleLiteral(this.value); | |
95 | |
96 accept(v) => v.visitDouble(this); | |
97 toString() => '$value'; | |
98 } | |
99 | |
100 /// Root of all expressions | |
101 abstract class Expression { | |
102 bool get isAs => false; | |
103 bool get isBinary => false; | |
104 bool get isConditional => false; | |
105 bool get isIdentical => false; | |
106 bool get isIs => false; | |
107 bool get isLoad => false; | |
108 bool get isOpaqueOp => false; | |
109 bool get isRef => false; | |
110 bool get isUnary => false; | |
111 | |
112 accept(Visitor v); | |
113 } | |
114 | |
115 /// An identical expression: `identical(a, b)`. | |
116 // TODO(sigmund): consider merging it into binary? | |
117 class Identical extends Expression { | |
118 final Expression left; | |
119 final Expression right; | |
120 Identical(this.left, this.right); | |
121 | |
122 bool get isIdentical => true; | |
123 accept(v) => v.visitIdentical(this); | |
124 toString() => 'identical($left, $right)'; | |
125 } | |
126 | |
127 /// A literal like `1`. | |
128 class IntLiteral extends Expression { | |
129 final int value; | |
130 IntLiteral(this.value); | |
131 | |
132 accept(v) => v.visitInt(this); | |
133 toString() => '$value'; | |
134 } | |
135 | |
136 /// An erroneous expression, typically encapsulates code that is not expected | |
137 /// in a constant context. | |
138 class Invalid extends Expression { | |
139 String hint; | |
140 Invalid({this.hint}); | |
141 accept(v) => v.visitInvalid(this); | |
142 | |
143 toString() => '(err: $hint)'; | |
144 } | |
145 | |
146 /// An instance check expression. | |
147 class Is extends Expression { | |
148 final Expression exp; | |
149 final TypeRef type; | |
150 Is(this.exp, this.type); | |
151 | |
152 bool get isIs => true; | |
153 accept(v) => v.visitIs(this); | |
154 toString() => '$exp is $type'; | |
155 } | |
156 | |
157 /// An entry in a map literal. | |
158 class KeyValuePair { | |
159 final Expression key; | |
160 final Expression value; | |
161 KeyValuePair(this.key, this.value); | |
162 | |
163 toString() => '(p: $key, $value)'; | |
164 } | |
165 | |
166 /// A list literal like: `[1, 2]`. | |
167 class ListLiteral extends Expression { | |
168 final TypeRef elementType; | |
169 final List<Expression> values; | |
170 final bool isConst; | |
171 ListLiteral(this.elementType, this.values, this.isConst); | |
172 | |
173 accept(v) => v.visitList(this); | |
174 toString() => '(list<$elementType>$values)'; | |
175 } | |
176 | |
177 /// A property extraction expression, such as: `(e).foo` | |
178 // TODO(sigmund): consider merging it into binary? | |
179 class Load extends Expression { | |
180 final Expression left; | |
181 final String name; | |
182 Load(this.left, this.name); | |
183 | |
184 bool get isLoad => true; | |
185 accept(v) => v.visitLoad(this); | |
186 toString() => '$left.$name'; | |
187 } | |
188 | |
189 /// A map literal like: `{'a': 2}`. | |
190 class MapLiteral extends Expression { | |
191 final List<TypeRef> types; | |
192 final List<KeyValuePair> values; | |
193 final bool isConst; | |
194 | |
195 MapLiteral(this.types, this.values, this.isConst) { | |
196 assert(types.length <= 2); | |
197 } | |
198 | |
199 accept(v) => v.visitMap(this); | |
200 toString() => '(map<${types.map((t) => "$t").join(", ")}>: $values)'; | |
201 } | |
202 | |
203 /// Representation for a named argument. | |
204 class NamedArg { | |
205 final String name; | |
206 final Expression value; | |
207 NamedArg(this.name, this.value); | |
208 } | |
209 | |
210 /// The `null` literal. | |
211 class NullLiteral extends Expression { | |
212 NullLiteral(); | |
213 | |
214 accept(v) => v.visitNull(this); | |
215 toString() => 'null'; | |
216 } | |
217 | |
218 /// An opaque expression with possibly a known type. | |
219 class Opaque extends Expression { | |
220 final TypeRef type; | |
221 final String hint; | |
222 | |
223 Opaque({this.type, this.hint}); | |
224 | |
225 accept(v) => v.visitOpaque(this); | |
226 | |
227 toString() { | |
228 var sb = new StringBuffer(); | |
229 sb.write('(o:'); | |
230 if (hint != null) sb.write(' $hint'); | |
231 if (type != null) sb.write(' $type'); | |
232 return '$sb)'; | |
233 } | |
234 } | |
235 | |
236 /// Marker that some part of the AST was abstracted away. | |
237 /// | |
238 /// This node does not provide additional information, other than indicating | |
239 /// that the AST does not include the full initializer. For example, | |
240 /// this is in assignments, pre and postfix operators, and cascades to indicate | |
241 /// that we ignored part of those complex expressions. | |
242 class OpaqueOp extends Expression { | |
243 final Expression exp; | |
244 final String hint; | |
245 OpaqueOp(this.exp, {this.hint}); | |
246 | |
247 bool get isOpaqueOp => true; | |
248 accept(v) => v.visitOpaqueOp(this); | |
249 } | |
250 | |
251 /// A name reference. | |
252 class Ref extends Expression { | |
253 final String name; | |
254 final Ref prefix; | |
255 | |
256 Ref(this.name, [this.prefix]) { | |
257 assert(prefixDepth <= 2); | |
258 } | |
259 | |
260 bool get isRef => true; | |
261 | |
262 int get prefixDepth => prefix == null ? 0 : prefix.prefixDepth; | |
263 accept(v) => v.visitRef(this); | |
264 toString() => 'r:${prefix == null ? "" : "$prefix."}$name'; | |
265 } | |
266 | |
267 /// A literal like `"foo"`. | |
268 class StringLiteral extends Expression { | |
269 final String value; | |
270 StringLiteral(this.value); | |
271 | |
272 accept(v) => v.visitString(this); | |
273 toString() => '$value'; | |
274 } | |
275 | |
276 /// A literal like `#foo.bar`. | |
277 class SymbolLiteral extends Expression { | |
278 final String value; | |
279 SymbolLiteral(this.value); | |
280 | |
281 accept(v) => v.visitSymbol(this); | |
282 toString() => '#$value'; | |
283 } | |
284 | |
285 /// A reference to a type (used for opaque nodes, is checks, and as checks). | |
286 /// | |
287 /// Note that types are not nodes in the expression tree. | |
288 class TypeRef { | |
289 final Ref name; | |
290 final List<TypeRef> typeArguments; | |
291 TypeRef(this.name, this.typeArguments); | |
292 | |
293 toString() { | |
294 var args = typeArguments == null ? "" : "<${typeArguments.join(', ')}>"; | |
295 return 't:$name$args'; | |
296 } | |
297 } | |
298 | |
299 /// All unary expressions, such as `-1` or `!b` | |
300 class Unary extends Expression { | |
301 final Expression exp; | |
302 final int operator; | |
303 Unary(this.exp, this.operator); | |
304 | |
305 bool get isUnary => true; | |
306 accept(v) => v.visitUnary(this); | |
307 toString() => '_ $exp'; | |
308 } | |
OLD | NEW |