Index: pkg/analyzer/lib/src/summary/fasta/expressions.dart |
diff --git a/pkg/analyzer/lib/src/summary/fasta/expressions.dart b/pkg/analyzer/lib/src/summary/fasta/expressions.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..81b9e503c27b6994b72458a2f5ceaacd095f91e5 |
--- /dev/null |
+++ b/pkg/analyzer/lib/src/summary/fasta/expressions.dart |
@@ -0,0 +1,306 @@ |
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+/// Minimal AST used to represent constant and initializer expressions. |
+/// |
+/// The AST definitions here are kept small by removing anything that we don't |
+/// need for the purpose of summarization: |
+/// |
+/// * A tree representing constants will not contain nodes that are not |
+/// allowed. If a parsed program contains a subexpression that is invalid, |
+/// we'll represent it with an `Invalid` node. |
+/// |
+/// * A tree representing initializers will only contain the subset of the |
+/// initializer expression that is needed to infer the type of the initialized |
+/// variable. For example, function closures, arguments to constructors, and |
+/// other similar bits are hidden using `Opaque` nodes. |
+library summary.src.expressions; |
+ |
+// We reuse the scanner constants to represent all binary and unary operators. |
+import 'visitor.dart'; |
+export 'visitor.dart'; |
+ |
+/// A reference to a type (used for opaque nodes, is checks, and as checks). |
+/// |
+/// Note that types are not nodes in the expression tree. |
+class TypeRef { |
+ final Ref name; |
+ final List<TypeRef> typeArguments; |
+ TypeRef(this.name, this.typeArguments); |
+ |
+ toString() { |
+ var args = typeArguments == null ? "" : "<${typeArguments.join(', ')}>"; |
+ return 't:$name$args'; |
+ } |
+} |
+ |
+/// Root of all expressions |
+abstract class Expression { |
+ bool get isRef => false; |
+ bool get isBinary => false; |
+ bool get isUnary => false; |
+ bool get isConditional => false; |
+ bool get isLoad => false; |
+ bool get isIdentical => false; |
+ bool get isAs => false; |
+ bool get isIs => false; |
+ bool get isOpaqueOp => false; |
+ |
+ accept(Visitor v); |
+} |
+ |
+/// A name reference. |
+class Ref extends Expression { |
+ final String name; |
+ final Ref prefix; |
+ |
+ int get prefixDepth => prefix == null ? 0 : prefix.prefixDepth; |
+ |
+ Ref(this.name, [this.prefix]) { |
+ assert(prefixDepth <= 2); |
+ } |
+ |
+ toString() => 'r:${prefix == null ? "" : "$prefix."}$name'; |
+ bool get isRef => true; |
+ accept(v) => v.visitRef(this); |
+} |
+ |
+/// A literal like `"foo"`. |
+class StringLiteral extends Expression { |
+ final String value; |
+ StringLiteral(this.value); |
+ |
+ toString() => '$value'; |
+ accept(v) => v.visitString(this); |
+} |
+ |
+/// A literal like `#foo.bar`. |
+class SymbolLiteral extends Expression { |
+ final String value; |
+ SymbolLiteral(this.value); |
+ |
+ accept(v) => v.visitSymbol(this); |
+ toString() => '#$value'; |
+} |
+ |
+/// A literal like `1`. |
+class IntLiteral extends Expression { |
+ final int value; |
+ IntLiteral(this.value); |
+ |
+ toString() => '$value'; |
+ accept(v) => v.visitInt(this); |
+} |
+ |
+/// A literal like `1.2`. |
+class DoubleLiteral extends Expression { |
+ final double value; |
+ DoubleLiteral(this.value); |
+ |
+ toString() => '$value'; |
+ accept(v) => v.visitDouble(this); |
+} |
+ |
+/// A literal like `false`. |
+class BoolLiteral extends Expression { |
+ final bool value; |
+ BoolLiteral(this.value); |
+ |
+ toString() => '$value'; |
+ accept(v) => v.visitBool(this); |
+} |
+ |
+/// The `null` literal. |
+class NullLiteral extends Expression { |
+ NullLiteral(); |
+ |
+ toString() => 'null'; |
+ accept(v) => v.visitNull(this); |
+} |
+ |
+/// A list literal like: `[1, 2]`. |
+class ListLiteral extends Expression { |
+ final TypeRef elementType; |
+ final List<Expression> values; |
+ final bool isConst; |
+ ListLiteral(this.elementType, this.values, this.isConst); |
+ |
+ toString() => '(list<$elementType>$values)'; |
+ accept(v) => v.visitList(this); |
+} |
+ |
+/// An entry in a map literal. |
+class KeyValuePair { |
+ final Expression key; |
+ final Expression value; |
+ KeyValuePair(this.key, this.value); |
+ |
+ toString() => '(p: $key, $value)'; |
+} |
+ |
+/// A map literal like: `{'a': 2}`. |
+class MapLiteral extends Expression { |
+ final List<TypeRef> types; |
+ final List<KeyValuePair> values; |
+ final bool isConst; |
+ |
+ MapLiteral(this.types, this.values, this.isConst) { |
+ assert(types.length <= 2); |
+ } |
+ |
+ toString() => '(map<${types.map((t) => "$t").join(", ")}>: $values)'; |
+ accept(v) => v.visitMap(this); |
+} |
+ |
+/// Expressions like `a ? b : c`. |
+class Conditional extends Expression { |
+ final Expression test; |
+ final Expression trueBranch; |
+ final Expression falseBranch; |
+ Conditional(this.test, this.trueBranch, this.falseBranch); |
+ |
+ bool get isConditional => true; |
+ toString() => '$test ? $trueBranch : $falseBranch'; |
+ accept(v) => v.visitConditional(this); |
+} |
+ |
+/// All binary expressions, including if-null. |
+class Binary extends Expression { |
+ final Expression left; |
+ final Expression right; |
+ final int operator; |
+ Binary(this.left, this.right, this.operator); |
+ |
+ bool get isBinary => true; |
+ toString() => '$left _ $right'; |
+ accept(v) => v.visitBinary(this); |
+} |
+ |
+/// An identical expression: `identical(a, b)`. |
+// TODO(sigmund): consider merging it into binary? |
+class Identical extends Expression { |
+ final Expression left; |
+ final Expression right; |
+ Identical(this.left, this.right); |
+ |
+ bool get isIdentical => true; |
+ toString() => 'identical($left, $right)'; |
+ accept(v) => v.visitIdentical(this); |
+} |
+ |
+/// A property extraction expression, such as: `(e).foo` |
+// TODO(sigmund): consider merging it into binary? |
+class Load extends Expression { |
+ final Expression left; |
+ final String name; |
+ Load(this.left, this.name); |
+ |
+ bool get isLoad => true; |
+ toString() => '$left.$name'; |
+ accept(v) => v.visitLoad(this); |
+} |
+ |
+/// All unary expressions, such as `-1` or `!b` |
+class Unary extends Expression { |
+ final Expression exp; |
+ final int operator; |
+ Unary(this.exp, this.operator); |
+ |
+ bool get isUnary => true; |
+ toString() => '_ $exp'; |
+ accept(v) => v.visitUnary(this); |
+} |
+ |
+/// A cast expression. |
+class As extends Expression { |
+ final Expression exp; |
+ final TypeRef type; |
+ As(this.exp, this.type); |
+ |
+ bool get isAs => true; |
+ accept(v) => v.visitAs(this); |
+ toString() => '$exp as $type'; |
+} |
+ |
+/// An instance check expression. |
+class Is extends Expression { |
+ final Expression exp; |
+ final TypeRef type; |
+ Is(this.exp, this.type); |
+ |
+ bool get isIs => true; |
+ accept(v) => v.visitIs(this); |
+ toString() => '$exp is $type'; |
+} |
+ |
+/// An erroneous expression, typically encapsulates code that is not expected |
+/// in a constant context. |
+class Invalid extends Expression { |
+ String hint; |
+ Invalid({this.hint}); |
+ accept(v) => v.visitInvalid(this); |
+ |
+ toString() => '(err: $hint)'; |
+} |
+ |
+/// Representation for a named argument. |
+class NamedArg { |
+ final String name; |
+ final Expression value; |
+ NamedArg(this.name, this.value); |
+} |
+ |
+/// The type and possibly name of a constructor. |
+class ConstructorName { |
+ final TypeRef type; |
+ final String name; |
+ ConstructorName(this.type, this.name); |
+ |
+ toString() => "ctor: $type.$name"; |
+} |
+ |
+/// A `const Foo()` creation. |
+class ConstCreation extends Expression { |
+ final ConstructorName constructor; |
+ |
+ /// Passed arguments, which can be expressions (if the argument is positional) |
+ /// or a [NamedArg]. |
+ final List<Expression> positionalArgs; |
+ final List<NamedArg> namedArgs; |
+ ConstCreation(this.constructor, this.positionalArgs, this.namedArgs); |
+ |
+ accept(v) => v.visitConstCreation(this); |
+} |
+ |
+/// An opaque expression with possibly a known type. |
+class Opaque extends Expression { |
+ final TypeRef type; |
+ final String hint; |
+ |
+ Opaque({this.type, this.hint}); |
+ |
+ toString() { |
+ var sb = new StringBuffer(); |
+ sb.write('(o:'); |
+ if (hint != null) sb.write(' $hint'); |
+ if (type != null) sb.write(' $type'); |
+ return '$sb)'; |
+ } |
+ accept(v) => v.visitOpaque(this); |
+} |
+ |
+/// Marker that some part of the AST was abstracted away. |
+/// |
+/// This node does not provide additional information, other than indicating |
+/// that the AST does not include the full initializer. For example, |
+/// this is in assignments, pre and postfix operators, and cascades to indicate |
+/// that we ignored part of those complex expressions. |
+class OpaqueOp extends Expression { |
+ final Expression exp; |
+ final String hint; |
+ OpaqueOp(this.exp, {this.hint}); |
+ |
+ bool get isOpaqueOp => true; |
+ accept(v) => v.visitOpaqueOp(this); |
+} |