| 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);
|
| +}
|
|
|