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