| // Copyright (c) 2014, 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. |
| |
| library dart2js.constants.expressions; |
| |
| import '../constants/constant_system.dart'; |
| import '../dart2jslib.dart' show assertDebugMode, Compiler; |
| import '../dart_types.dart'; |
| import '../elements/elements.dart' show |
| ConstructorElement, |
| Element, |
| FieldElement, |
| FunctionElement, |
| PrefixElement, |
| VariableElement; |
| import '../resolution/operators.dart'; |
| import '../tree/tree.dart' show DartString; |
| import '../universe/universe.dart' show CallStructure; |
| import 'values.dart'; |
| |
| enum ConstantExpressionKind { |
| BINARY, |
| BOOL, |
| BOOL_FROM_ENVIRONMENT, |
| CONCATENATE, |
| CONDITIONAL, |
| CONSTRUCTED, |
| DEFERRED, |
| DOUBLE, |
| ERRONEOUS, |
| FUNCTION, |
| IDENTICAL, |
| INT, |
| INT_FROM_ENVIRONMENT, |
| LIST, |
| MAP, |
| NULL, |
| STRING, |
| STRING_FROM_ENVIRONMENT, |
| SYMBOL, |
| TYPE, |
| UNARY, |
| VARIABLE, |
| |
| POSITIONAL_REFERENCE, |
| NAMED_REFERENCE, |
| } |
| |
| /// Environment used for evaluating constant expressions. |
| abstract class Environment { |
| // TODO(johnniwinther): Replace this with [CoreTypes] and maybe [Backend]. |
| Compiler get compiler; |
| |
| /// Read environments string passed in using the '-Dname=value' option. |
| String readFromEnvironment(String name); |
| } |
| |
| /// The normalized arguments passed to a const constructor computed from the |
| /// actual [arguments] and the [defaultValues] of the called construrctor. |
| class NormalizedArguments { |
| final Map<dynamic/*int|String*/, ConstantExpression> defaultValues; |
| final CallStructure callStructure; |
| final List<ConstantExpression> arguments; |
| |
| NormalizedArguments(this.defaultValues, this.callStructure, this.arguments); |
| |
| /// Returns the normalized named argument [name]. |
| ConstantExpression getNamedArgument(String name) { |
| int index = callStructure.namedArguments.indexOf(name); |
| if (index == -1) { |
| // The named argument is not provided. |
| return defaultValues[name]; |
| } |
| return arguments[index + callStructure.positionalArgumentCount]; |
| } |
| |
| /// Returns the normalized [index]th positional argument. |
| ConstantExpression getPositionalArgument(int index) { |
| if (index >= callStructure.positionalArgumentCount) { |
| // The positional argument is not provided. |
| return defaultValues[index]; |
| } |
| return arguments[index]; |
| } |
| } |
| |
| enum ConstantConstructorKind { |
| GENERATIVE, |
| REDIRECTING_GENERATIVE, |
| REDIRECTING_FACTORY, |
| } |
| |
| /// Definition of a constant constructor. |
| abstract class ConstantConstructor { |
| ConstantConstructorKind get kind; |
| |
| /// Computes the type of the instance created in a const constructor |
| /// invocation with type [newType]. |
| InterfaceType computeInstanceType(InterfaceType newType); |
| |
| /// Computes the constant expressions of the fields of the created instance |
| /// in a const constructor invocation with [arguments]. |
| Map<FieldElement, ConstantExpression> computeInstanceFields( |
| List<ConstantExpression> arguments, |
| CallStructure callStructure); |
| } |
| |
| /// A generative constant constructor. |
| class GenerativeConstantConstructor implements ConstantConstructor{ |
| final InterfaceType type; |
| final Map<dynamic/*int|String*/, ConstantExpression> defaultValues; |
| final Map<FieldElement, ConstantExpression> fieldMap; |
| final ConstructedConstantExpression superConstructorInvocation; |
| |
| GenerativeConstantConstructor( |
| this.type, |
| this.defaultValues, |
| this.fieldMap, |
| this.superConstructorInvocation); |
| |
| ConstantConstructorKind get kind => ConstantConstructorKind.GENERATIVE; |
| |
| InterfaceType computeInstanceType(InterfaceType newType) { |
| return type.substByContext(newType); |
| } |
| |
| Map<FieldElement, ConstantExpression> computeInstanceFields( |
| List<ConstantExpression> arguments, |
| CallStructure callStructure) { |
| NormalizedArguments args = new NormalizedArguments( |
| defaultValues, callStructure, arguments); |
| Map<FieldElement, ConstantExpression> appliedFieldMap = |
| applyFields(args, superConstructorInvocation); |
| fieldMap.forEach((FieldElement field, ConstantExpression constant) { |
| appliedFieldMap[field] = constant.apply(args); |
| }); |
| return appliedFieldMap; |
| } |
| |
| String toString() { |
| StringBuffer sb = new StringBuffer(); |
| sb.write("{'type': $type"); |
| defaultValues.forEach((key, ConstantExpression expression) { |
| sb.write(",\n 'default:${key}': ${expression.getText()}"); |
| }); |
| fieldMap.forEach((FieldElement field, ConstantExpression expression) { |
| sb.write(",\n 'field:${field}': ${expression.getText()}"); |
| }); |
| if (superConstructorInvocation != null) { |
| sb.write(",\n 'constructor: ${superConstructorInvocation.getText()}"); |
| } |
| sb.write("}"); |
| return sb.toString(); |
| } |
| |
| /// Creates the field-to-constant map from applying [args] to |
| /// [constructorInvocation]. If [constructorInvocation] is `null`, an empty |
| /// map is created. |
| static Map<FieldElement, ConstantExpression> applyFields( |
| NormalizedArguments args, |
| ConstructedConstantExpression constructorInvocation) { |
| Map<FieldElement, ConstantExpression> appliedFieldMap = |
| <FieldElement, ConstantExpression>{}; |
| if (constructorInvocation != null) { |
| Map<FieldElement, ConstantExpression> fieldMap = |
| constructorInvocation.computeInstanceFields(); |
| fieldMap.forEach((FieldElement field, ConstantExpression constant) { |
| appliedFieldMap[field] = constant.apply(args); |
| }); |
| } |
| return appliedFieldMap; |
| } |
| } |
| |
| /// A redirecting generative constant constructor. |
| class RedirectingGenerativeConstantConstructor implements ConstantConstructor { |
| final Map<dynamic/*int|String*/, ConstantExpression> defaultValues; |
| final ConstructedConstantExpression thisConstructorInvocation; |
| |
| RedirectingGenerativeConstantConstructor( |
| this.defaultValues, |
| this.thisConstructorInvocation); |
| |
| ConstantConstructorKind get kind { |
| return ConstantConstructorKind.REDIRECTING_GENERATIVE; |
| } |
| |
| InterfaceType computeInstanceType(InterfaceType newType) { |
| return thisConstructorInvocation.computeInstanceType() |
| .substByContext(newType); |
| } |
| |
| Map<FieldElement, ConstantExpression> computeInstanceFields( |
| List<ConstantExpression> arguments, |
| CallStructure callStructure) { |
| NormalizedArguments args = |
| new NormalizedArguments(defaultValues, callStructure, arguments); |
| Map<FieldElement, ConstantExpression> appliedFieldMap = |
| GenerativeConstantConstructor.applyFields( |
| args, thisConstructorInvocation); |
| return appliedFieldMap; |
| } |
| |
| String toString() { |
| StringBuffer sb = new StringBuffer(); |
| sb.write("{'type': ${thisConstructorInvocation.type}"); |
| defaultValues.forEach((key, ConstantExpression expression) { |
| sb.write(",\n 'default:${key}': ${expression.getText()}"); |
| }); |
| sb.write(",\n 'constructor': ${thisConstructorInvocation.getText()}"); |
| sb.write("}"); |
| return sb.toString(); |
| } |
| } |
| |
| /// A redirecting factory constant constructor. |
| class RedirectingFactoryConstantConstructor implements ConstantConstructor { |
| final ConstructedConstantExpression targetConstructorInvocation; |
| |
| RedirectingFactoryConstantConstructor(this.targetConstructorInvocation); |
| |
| ConstantConstructorKind get kind { |
| return ConstantConstructorKind.REDIRECTING_FACTORY; |
| } |
| |
| InterfaceType computeInstanceType(InterfaceType newType) { |
| return targetConstructorInvocation.computeInstanceType() |
| .substByContext(newType); |
| } |
| |
| Map<FieldElement, ConstantExpression> computeInstanceFields( |
| List<ConstantExpression> arguments, |
| CallStructure callStructure) { |
| ConstantConstructor constantConstructor = |
| targetConstructorInvocation.target.constantConstructor; |
| return constantConstructor.computeInstanceFields(arguments, callStructure); |
| } |
| |
| String toString() { |
| StringBuffer sb = new StringBuffer(); |
| sb.write("{"); |
| sb.write("'constructor': ${targetConstructorInvocation.getText()}"); |
| sb.write("}"); |
| return sb.toString(); |
| } |
| } |
| |
| /// An expression that is a compile-time constant. |
| /// |
| /// Whereas [ConstantValue] represent a compile-time value, a |
| /// [ConstantExpression] represents an expression for creating a constant. |
| /// |
| /// There is no one-to-one mapping between [ConstantExpression] and |
| /// [ConstantValue], because different expressions can denote the same constant. |
| /// For instance, multiple `const` constructors may be used to create the same |
| /// object, and different `const` variables may hold the same value. |
| abstract class ConstantExpression { |
| int _hashCode; |
| |
| ConstantExpressionKind get kind; |
| |
| /// Returns the value of this constant expression. |
| // TODO(johnniwinther): Replace this with an evaluation method that takes |
| // a constant system and an environment. |
| ConstantValue get value; |
| |
| // TODO(johnniwinther): Unify precedence handled between constants, front-end |
| // and back-end. |
| int get precedence => 16; |
| |
| accept(ConstantExpressionVisitor visitor, [context]); |
| |
| /// Substitute free variables using arguments. |
| ConstantExpression apply(NormalizedArguments arguments) => this; |
| |
| /// Compute the [ConstantValue] for this expression using the [environment] |
| /// and the [constantSystem]. |
| ConstantValue evaluate(Environment environment, |
| ConstantSystem constantSystem); |
| |
| String getText() { |
| ConstExpPrinter printer = new ConstExpPrinter(); |
| accept(printer); |
| return printer.toString(); |
| } |
| |
| int _computeHashCode(); |
| |
| int get hashCode { |
| if (_hashCode == null) { |
| _hashCode = _computeHashCode(); |
| } |
| return _hashCode; |
| } |
| |
| bool _equals(ConstantExpression other); |
| |
| bool operator ==(other) { |
| if (identical(this, other)) return true; |
| if (other is! ConstantExpression) return false; |
| if (kind != other.kind) return false; |
| if (hashCode != other.hashCode) return false; |
| return _equals(other); |
| } |
| |
| String toString() { |
| assertDebugMode('Use ConstantExpression.getText() instead of ' |
| 'ConstantExpression.toString()'); |
| return getText(); |
| } |
| } |
| |
| /// A synthetic constant used to recover from errors. |
| class ErroneousConstantExpression extends ConstantExpression { |
| final PrimitiveConstantValue value = new NullConstantValue(); |
| |
| ConstantExpressionKind get kind => ConstantExpressionKind.ERRONEOUS; |
| |
| accept(ConstantExpressionVisitor visitor, [context]) { |
| // Do nothing. This is an error. |
| } |
| |
| @override |
| ConstantValue evaluate(Environment environment, |
| ConstantSystem constantSystem) { |
| // TODO(johnniwinther): Use non-constant values for errors. |
| return value; |
| } |
| |
| @override |
| int _computeHashCode() => 13; |
| |
| @override |
| bool _equals(ErroneousConstantExpression other) => true; |
| } |
| |
| /// A boolean, int, double, string, or null constant. |
| abstract class PrimitiveConstantExpression extends ConstantExpression { |
| final PrimitiveConstantValue value; |
| |
| PrimitiveConstantExpression(this.value); |
| |
| /// The primitive value of this contant expression. |
| get primitiveValue; |
| } |
| |
| /// Boolean literal constant. |
| class BoolConstantExpression extends PrimitiveConstantExpression { |
| final bool primitiveValue; |
| |
| BoolConstantExpression(this.primitiveValue, |
| PrimitiveConstantValue value) : super(value); |
| |
| ConstantExpressionKind get kind => ConstantExpressionKind.BOOL; |
| |
| accept(ConstantExpressionVisitor visitor, [context]) { |
| return visitor.visitBool(this, context); |
| } |
| |
| @override |
| ConstantValue evaluate(Environment environment, |
| ConstantSystem constantSystem) { |
| return constantSystem.createBool(primitiveValue); |
| } |
| |
| @override |
| int _computeHashCode() => 13 * primitiveValue.hashCode; |
| |
| @override |
| bool _equals(BoolConstantExpression other) { |
| return primitiveValue == other.primitiveValue; |
| } |
| } |
| |
| /// Integer literal constant. |
| class IntConstantExpression extends PrimitiveConstantExpression { |
| final int primitiveValue; |
| |
| IntConstantExpression(this.primitiveValue, |
| PrimitiveConstantValue value) : super(value); |
| |
| ConstantExpressionKind get kind => ConstantExpressionKind.INT; |
| |
| accept(ConstantExpressionVisitor visitor, [context]) { |
| return visitor.visitInt(this, context); |
| } |
| |
| @override |
| ConstantValue evaluate(Environment environment, |
| ConstantSystem constantSystem) { |
| return constantSystem.createInt(primitiveValue); |
| } |
| |
| @override |
| int _computeHashCode() => 17 * primitiveValue.hashCode; |
| |
| @override |
| bool _equals(IntConstantExpression other) { |
| return primitiveValue == other.primitiveValue; |
| } |
| } |
| |
| /// Double literal constant. |
| class DoubleConstantExpression extends PrimitiveConstantExpression { |
| final double primitiveValue; |
| |
| DoubleConstantExpression(this.primitiveValue, |
| PrimitiveConstantValue value) : super(value); |
| |
| ConstantExpressionKind get kind => ConstantExpressionKind.DOUBLE; |
| |
| accept(ConstantExpressionVisitor visitor, [context]) { |
| return visitor.visitDouble(this, context); |
| } |
| |
| @override |
| ConstantValue evaluate(Environment environment, |
| ConstantSystem constantSystem) { |
| return constantSystem.createDouble(primitiveValue); |
| } |
| |
| @override |
| int _computeHashCode() => 19 * primitiveValue.hashCode; |
| |
| @override |
| bool _equals(DoubleConstantExpression other) { |
| return primitiveValue == other.primitiveValue; |
| } |
| } |
| |
| /// String literal constant. |
| class StringConstantExpression extends PrimitiveConstantExpression { |
| final String primitiveValue; |
| |
| StringConstantExpression(this.primitiveValue, |
| PrimitiveConstantValue value) : super(value); |
| |
| ConstantExpressionKind get kind => ConstantExpressionKind.STRING; |
| |
| accept(ConstantExpressionVisitor visitor, [context]) { |
| return visitor.visitString(this, context); |
| } |
| |
| @override |
| ConstantValue evaluate(Environment environment, |
| ConstantSystem constantSystem) { |
| return constantSystem.createString(new DartString.literal(primitiveValue)); |
| } |
| |
| @override |
| int _computeHashCode() => 23 * primitiveValue.hashCode; |
| |
| @override |
| bool _equals(StringConstantExpression other) { |
| return primitiveValue == other.primitiveValue; |
| } |
| } |
| |
| /// Null literal constant. |
| class NullConstantExpression extends PrimitiveConstantExpression { |
| NullConstantExpression(PrimitiveConstantValue value) : super(value); |
| |
| ConstantExpressionKind get kind => ConstantExpressionKind.NULL; |
| |
| accept(ConstantExpressionVisitor visitor, [context]) { |
| return visitor.visitNull(this, context); |
| } |
| |
| @override |
| ConstantValue evaluate(Environment environment, |
| ConstantSystem constantSystem) { |
| return constantSystem.createNull(); |
| } |
| |
| get primitiveValue => null; |
| |
| @override |
| int _computeHashCode() => 29; |
| |
| @override |
| bool _equals(NullConstantExpression other) => true; |
| } |
| |
| /// Literal list constant. |
| class ListConstantExpression extends ConstantExpression { |
| final ListConstantValue value; |
| final InterfaceType type; |
| final List<ConstantExpression> values; |
| |
| ListConstantExpression(this.value, this.type, this.values); |
| |
| ConstantExpressionKind get kind => ConstantExpressionKind.LIST; |
| |
| accept(ConstantExpressionVisitor visitor, [context]) { |
| return visitor.visitList(this, context); |
| } |
| |
| @override |
| ConstantValue evaluate(Environment environment, |
| ConstantSystem constantSystem) { |
| return constantSystem.createList(type, |
| values.map((v) => v.evaluate(environment, constantSystem)).toList()); |
| } |
| |
| ConstantExpression apply(NormalizedArguments arguments) { |
| return new ListConstantExpression(null, type, |
| values.map((v) => v.apply(arguments)).toList()); |
| } |
| |
| @override |
| int _computeHashCode() { |
| int hashCode = 13 * type.hashCode + 17 * values.length; |
| for (ConstantExpression value in values) { |
| hashCode ^= 19 * value.hashCode; |
| } |
| return hashCode; |
| } |
| |
| @override |
| bool _equals(ListConstantExpression other) { |
| if (type != other.type) return false; |
| if (values.length != other.values.length) return false; |
| for (int i = 0; i < values.length; i++) { |
| if (values[i] != other.values[i]) return false; |
| } |
| return true; |
| } |
| } |
| |
| /// Literal map constant. |
| class MapConstantExpression extends ConstantExpression { |
| final MapConstantValue value; |
| final InterfaceType type; |
| final List<ConstantExpression> keys; |
| final List<ConstantExpression> values; |
| |
| MapConstantExpression(this.value, this.type, this.keys, this.values); |
| |
| ConstantExpressionKind get kind => ConstantExpressionKind.MAP; |
| |
| accept(ConstantExpressionVisitor visitor, [context]) { |
| return visitor.visitMap(this, context); |
| } |
| |
| @override |
| ConstantValue evaluate(Environment environment, |
| ConstantSystem constantSystem) { |
| return constantSystem.createMap(environment.compiler, |
| type, |
| keys.map((k) => k.evaluate(environment, constantSystem)).toList(), |
| values.map((v) => v.evaluate(environment, constantSystem)).toList()); |
| } |
| |
| ConstantExpression apply(NormalizedArguments arguments) { |
| return new MapConstantExpression(null, type, |
| keys.map((k) => k.apply(arguments)).toList(), |
| values.map((v) => v.apply(arguments)).toList()); |
| } |
| |
| @override |
| int _computeHashCode() { |
| int hashCode = 13 * type.hashCode + 17 * values.length; |
| for (ConstantExpression value in values) { |
| hashCode ^= 19 * value.hashCode; |
| } |
| return hashCode; |
| } |
| |
| @override |
| bool _equals(MapConstantExpression other) { |
| if (type != other.type) return false; |
| if (values.length != other.values.length) return false; |
| for (int i = 0; i < values.length; i++) { |
| if (keys[i] != other.keys[i]) return false; |
| if (values[i] != other.values[i]) return false; |
| } |
| return true; |
| } |
| } |
| |
| /// Invocation of a const constructor. |
| class ConstructedConstantExpression extends ConstantExpression { |
| final ConstantValue value; |
| final InterfaceType type; |
| final ConstructorElement target; |
| final CallStructure callStructure; |
| final List<ConstantExpression> arguments; |
| |
| ConstructedConstantExpression( |
| this.value, |
| this.type, |
| this.target, |
| this.callStructure, |
| this.arguments) { |
| assert(type.element == target.enclosingClass); |
| assert(!arguments.contains(null)); |
| } |
| |
| ConstantExpressionKind get kind => ConstantExpressionKind.CONSTRUCTED; |
| |
| accept(ConstantExpressionVisitor visitor, [context]) { |
| return visitor.visitConstructed(this, context); |
| } |
| |
| Map<FieldElement, ConstantExpression> computeInstanceFields() { |
| return target.constantConstructor.computeInstanceFields( |
| arguments, callStructure); |
| } |
| |
| InterfaceType computeInstanceType() { |
| return target.constantConstructor.computeInstanceType(type); |
| } |
| |
| ConstructedConstantExpression apply(NormalizedArguments arguments) { |
| return new ConstructedConstantExpression(null, |
| type, target, callStructure, |
| this.arguments.map((a) => a.apply(arguments)).toList()); |
| } |
| |
| @override |
| ConstantValue evaluate(Environment environment, |
| ConstantSystem constantSystem) { |
| Map<FieldElement, ConstantValue> fieldValues = |
| <FieldElement, ConstantValue>{}; |
| computeInstanceFields().forEach( |
| (FieldElement field, ConstantExpression constant) { |
| fieldValues[field] = constant.evaluate(environment, constantSystem); |
| }); |
| return new ConstructedConstantValue(computeInstanceType(), fieldValues); |
| } |
| |
| @override |
| int _computeHashCode() { |
| int hashCode = |
| 13 * type.hashCode + |
| 17 * target.hashCode + |
| 19 * callStructure.hashCode; |
| for (ConstantExpression value in arguments) { |
| hashCode ^= 23 * value.hashCode; |
| } |
| return hashCode; |
| } |
| |
| @override |
| bool _equals(ConstructedConstantExpression other) { |
| if (type != other.type) return false; |
| if (target != other.target) return false; |
| if (callStructure != other.callStructure) return false; |
| for (int i = 0; i < arguments.length; i++) { |
| if (arguments[i] != other.arguments[i]) return false; |
| } |
| return true; |
| } |
| } |
| |
| /// String literal with juxtaposition and/or interpolations. |
| class ConcatenateConstantExpression extends ConstantExpression { |
| final StringConstantValue value; |
| final List<ConstantExpression> expressions; |
| |
| ConcatenateConstantExpression(this.value, this.expressions); |
| |
| ConstantExpressionKind get kind => ConstantExpressionKind.CONCATENATE; |
| |
| accept(ConstantExpressionVisitor visitor, [context]) { |
| return visitor.visitConcatenate(this, context); |
| } |
| |
| ConstantExpression apply(NormalizedArguments arguments) { |
| return new ConcatenateConstantExpression(null, |
| expressions.map((a) => a.apply(arguments)).toList()); |
| } |
| |
| @override |
| ConstantValue evaluate(Environment environment, |
| ConstantSystem constantSystem) { |
| DartString accumulator; |
| for (ConstantExpression expression in expressions) { |
| ConstantValue value = expression.evaluate(environment, constantSystem); |
| DartString valueString; |
| if (value.isNum || value.isBool) { |
| PrimitiveConstantValue primitive = value; |
| valueString = |
| new DartString.literal(primitive.primitiveValue.toString()); |
| } else if (value.isString) { |
| PrimitiveConstantValue primitive = value; |
| valueString = primitive.primitiveValue; |
| } else { |
| // TODO(johnniwinther): Specialize message to indicated that the problem |
| // is not constness but the types of the const expressions. |
| return new NonConstantValue(); |
| } |
| if (accumulator == null) { |
| accumulator = valueString; |
| } else { |
| accumulator = new DartString.concat(accumulator, valueString); |
| } |
| } |
| return constantSystem.createString(accumulator); |
| } |
| |
| @override |
| int _computeHashCode() { |
| int hashCode = 17 * expressions.length; |
| for (ConstantExpression value in expressions) { |
| hashCode ^= 19 * value.hashCode; |
| } |
| return hashCode; |
| } |
| |
| @override |
| bool _equals(ConcatenateConstantExpression other) { |
| if (expressions.length != other.expressions.length) return false; |
| for (int i = 0; i < expressions.length; i++) { |
| if (expressions[i] != other.expressions[i]) return false; |
| } |
| return true; |
| } |
| } |
| |
| /// Symbol literal. |
| class SymbolConstantExpression extends ConstantExpression { |
| final ConstructedConstantValue value; |
| final String name; |
| |
| SymbolConstantExpression(this.value, this.name); |
| |
| ConstantExpressionKind get kind => ConstantExpressionKind.SYMBOL; |
| |
| accept(ConstantExpressionVisitor visitor, [context]) { |
| return visitor.visitSymbol(this, context); |
| } |
| |
| @override |
| int _computeHashCode() => 13 * name.hashCode; |
| |
| @override |
| bool _equals(SymbolConstantExpression other) { |
| return name == other.name; |
| } |
| |
| @override |
| ConstantValue evaluate(Environment environment, |
| ConstantSystem constantSystem) { |
| // TODO(johnniwinther): Implement this. |
| throw new UnsupportedError('SymbolConstantExpression.evaluate'); |
| } |
| } |
| |
| /// Type literal. |
| class TypeConstantExpression extends ConstantExpression { |
| final TypeConstantValue value; |
| /// Either [DynamicType] or a raw [GenericType]. |
| final DartType type; |
| |
| TypeConstantExpression(this.value, this.type) { |
| assert(type is GenericType || type is DynamicType); |
| } |
| |
| ConstantExpressionKind get kind => ConstantExpressionKind.TYPE; |
| |
| accept(ConstantExpressionVisitor visitor, [context]) { |
| return visitor.visitType(this, context); |
| } |
| |
| @override |
| ConstantValue evaluate(Environment environment, |
| ConstantSystem constantSystem) { |
| return constantSystem.createType(environment.compiler, type); |
| } |
| |
| @override |
| int _computeHashCode() => 13 * type.hashCode; |
| |
| @override |
| bool _equals(TypeConstantExpression other) { |
| return type == other.type; |
| } |
| } |
| |
| /// Reference to a constant local, top-level, or static variable. |
| class VariableConstantExpression extends ConstantExpression { |
| final ConstantValue value; |
| final VariableElement element; |
| |
| VariableConstantExpression(this.value, this.element); |
| |
| ConstantExpressionKind get kind => ConstantExpressionKind.VARIABLE; |
| |
| accept(ConstantExpressionVisitor visitor, [context]) { |
| return visitor.visitVariable(this, context); |
| } |
| |
| @override |
| ConstantValue evaluate(Environment environment, |
| ConstantSystem constantSystem) { |
| return element.constant.evaluate(environment, constantSystem); |
| } |
| |
| @override |
| int _computeHashCode() => 13 * element.hashCode; |
| |
| @override |
| bool _equals(VariableConstantExpression other) { |
| return element == other.element; |
| } |
| } |
| |
| /// Reference to a top-level or static function. |
| class FunctionConstantExpression extends ConstantExpression { |
| final FunctionConstantValue value; |
| final FunctionElement element; |
| |
| FunctionConstantExpression(this.value, this.element); |
| |
| ConstantExpressionKind get kind => ConstantExpressionKind.FUNCTION; |
| |
| accept(ConstantExpressionVisitor visitor, [context]) { |
| return visitor.visitFunction(this, context); |
| } |
| |
| @override |
| ConstantValue evaluate(Environment environment, |
| ConstantSystem constantSystem) { |
| return new FunctionConstantValue(element); |
| } |
| |
| @override |
| int _computeHashCode() => 13 * element.hashCode; |
| |
| @override |
| bool _equals(FunctionConstantExpression other) { |
| return element == other.element; |
| } |
| } |
| |
| /// A constant binary expression like `a * b`. |
| class BinaryConstantExpression extends ConstantExpression { |
| final ConstantValue value; |
| final ConstantExpression left; |
| final BinaryOperator operator; |
| final ConstantExpression right; |
| |
| BinaryConstantExpression(this.value, this.left, this.operator, this.right) { |
| assert(PRECEDENCE_MAP[operator.kind] != null); |
| } |
| |
| ConstantExpressionKind get kind => ConstantExpressionKind.BINARY; |
| |
| accept(ConstantExpressionVisitor visitor, [context]) { |
| return visitor.visitBinary(this, context); |
| } |
| |
| @override |
| ConstantValue evaluate(Environment environment, |
| ConstantSystem constantSystem) { |
| return constantSystem.lookupBinary(operator).fold( |
| left.evaluate(environment, constantSystem), |
| right.evaluate(environment, constantSystem)); |
| } |
| |
| ConstantExpression apply(NormalizedArguments arguments) { |
| return new BinaryConstantExpression( |
| value, |
| left.apply(arguments), |
| operator, |
| right.apply(arguments)); |
| } |
| |
| int get precedence => PRECEDENCE_MAP[operator.kind]; |
| |
| @override |
| int _computeHashCode() { |
| return 13 * operator.hashCode + |
| 17 * left.hashCode + |
| 19 * right.hashCode; |
| } |
| |
| @override |
| bool _equals(BinaryConstantExpression other) { |
| return operator == other.operator && |
| left == other.left && |
| right == other.right; |
| } |
| |
| static const Map<BinaryOperatorKind, int> PRECEDENCE_MAP = const { |
| BinaryOperatorKind.EQ: 6, |
| BinaryOperatorKind.NOT_EQ: 6, |
| BinaryOperatorKind.LOGICAL_AND: 5, |
| BinaryOperatorKind.LOGICAL_OR: 4, |
| BinaryOperatorKind.XOR: 9, |
| BinaryOperatorKind.AND: 10, |
| BinaryOperatorKind.OR: 8, |
| BinaryOperatorKind.SHR: 11, |
| BinaryOperatorKind.SHL: 11, |
| BinaryOperatorKind.ADD: 12, |
| BinaryOperatorKind.SUB: 12, |
| BinaryOperatorKind.MUL: 13, |
| BinaryOperatorKind.DIV: 13, |
| BinaryOperatorKind.IDIV: 13, |
| BinaryOperatorKind.GT: 7, |
| BinaryOperatorKind.LT: 7, |
| BinaryOperatorKind.GTEQ: 7, |
| BinaryOperatorKind.LTEQ: 7, |
| BinaryOperatorKind.MOD: 13, |
| }; |
| } |
| |
| /// A constant identical invocation like `identical(a, b)`. |
| class IdenticalConstantExpression extends ConstantExpression { |
| final ConstantValue value; |
| final ConstantExpression left; |
| final ConstantExpression right; |
| |
| IdenticalConstantExpression(this.value, this.left, this.right); |
| |
| ConstantExpressionKind get kind => ConstantExpressionKind.IDENTICAL; |
| |
| accept(ConstantExpressionVisitor visitor, [context]) { |
| return visitor.visitIdentical(this, context); |
| } |
| |
| @override |
| ConstantValue evaluate(Environment environment, |
| ConstantSystem constantSystem) { |
| return constantSystem.identity.fold( |
| left.evaluate(environment, constantSystem), |
| right.evaluate(environment, constantSystem)); |
| } |
| |
| ConstantExpression apply(NormalizedArguments arguments) { |
| return new IdenticalConstantExpression( |
| value, |
| left.apply(arguments), |
| right.apply(arguments)); |
| } |
| |
| int get precedence => 15; |
| |
| @override |
| int _computeHashCode() { |
| return 17 * left.hashCode + |
| 19 * right.hashCode; |
| } |
| |
| @override |
| bool _equals(IdenticalConstantExpression other) { |
| return left == other.left && |
| right == other.right; |
| } |
| } |
| |
| /// A unary constant expression like `-a`. |
| class UnaryConstantExpression extends ConstantExpression { |
| final ConstantValue value; |
| final UnaryOperator operator; |
| final ConstantExpression expression; |
| |
| UnaryConstantExpression(this.value, this.operator, this.expression) { |
| assert(PRECEDENCE_MAP[operator.kind] != null); |
| } |
| |
| ConstantExpressionKind get kind => ConstantExpressionKind.UNARY; |
| |
| accept(ConstantExpressionVisitor visitor, [context]) { |
| return visitor.visitUnary(this, context); |
| } |
| |
| @override |
| ConstantValue evaluate(Environment environment, |
| ConstantSystem constantSystem) { |
| return constantSystem.lookupUnary(operator).fold( |
| expression.evaluate(environment, constantSystem)); |
| } |
| |
| ConstantExpression apply(NormalizedArguments arguments) { |
| return new UnaryConstantExpression( |
| value, |
| operator, |
| expression.apply(arguments)); |
| } |
| |
| int get precedence => PRECEDENCE_MAP[operator.kind]; |
| |
| @override |
| int _computeHashCode() { |
| return 13 * operator.hashCode + |
| 17 * expression.hashCode; |
| } |
| |
| @override |
| bool _equals(UnaryConstantExpression other) { |
| return operator == other.operator && |
| expression == other.expression; |
| } |
| |
| static const Map<UnaryOperatorKind, int> PRECEDENCE_MAP = const { |
| UnaryOperatorKind.NOT: 14, |
| UnaryOperatorKind.COMPLEMENT: 14, |
| UnaryOperatorKind.NEGATE: 14, |
| }; |
| } |
| |
| /// A constant conditional expression like `a ? b : c`. |
| class ConditionalConstantExpression extends ConstantExpression { |
| final ConstantValue value; |
| final ConstantExpression condition; |
| final ConstantExpression trueExp; |
| final ConstantExpression falseExp; |
| |
| ConditionalConstantExpression(this.value, |
| this.condition, |
| this.trueExp, |
| this.falseExp); |
| |
| ConstantExpressionKind get kind => ConstantExpressionKind.CONDITIONAL; |
| |
| accept(ConstantExpressionVisitor visitor, [context]) { |
| return visitor.visitConditional(this, context); |
| } |
| |
| ConstantExpression apply(NormalizedArguments arguments) { |
| return new ConditionalConstantExpression( |
| value, |
| condition.apply(arguments), |
| trueExp.apply(arguments), |
| falseExp.apply(arguments)); |
| } |
| |
| int get precedence => 3; |
| |
| @override |
| int _computeHashCode() { |
| return 13 * condition.hashCode + |
| 17 * trueExp.hashCode + |
| 19 * falseExp.hashCode; |
| } |
| |
| @override |
| bool _equals(ConditionalConstantExpression other) { |
| return condition == other.condition && |
| trueExp == other.trueExp && |
| falseExp == other.falseExp; |
| } |
| |
| @override |
| ConstantValue evaluate(Environment environment, |
| ConstantSystem constantSystem) { |
| ConstantValue conditionValue = |
| condition.evaluate(environment, constantSystem); |
| ConstantValue trueValue = |
| trueExp.evaluate(environment, constantSystem); |
| ConstantValue falseValue = |
| falseExp.evaluate(environment, constantSystem); |
| if (conditionValue.isTrue) { |
| return trueValue; |
| } else if (conditionValue.isFalse) { |
| return falseValue; |
| } else { |
| return new NonConstantValue(); |
| } |
| } |
| } |
| |
| /// A reference to a position parameter. |
| class PositionalArgumentReference extends ConstantExpression { |
| final int index; |
| |
| PositionalArgumentReference(this.index); |
| |
| ConstantExpressionKind get kind { |
| return ConstantExpressionKind.POSITIONAL_REFERENCE; |
| } |
| |
| accept(ConstantExpressionVisitor visitor, [context]) { |
| return visitor.visitPositional(this, context); |
| } |
| |
| ConstantValue get value { |
| throw new UnsupportedError('PositionalArgumentReference.value'); |
| } |
| |
| ConstantExpression apply(NormalizedArguments arguments) { |
| return arguments.getPositionalArgument(index); |
| } |
| |
| @override |
| int _computeHashCode() => 13 * index.hashCode; |
| |
| @override |
| bool _equals(PositionalArgumentReference other) => index == other.index; |
| |
| @override |
| ConstantValue evaluate(Environment environment, |
| ConstantSystem constantSystem) { |
| throw new UnsupportedError('PositionalArgumentReference.evaluate'); |
| } |
| } |
| |
| /// A reference to a named parameter. |
| class NamedArgumentReference extends ConstantExpression { |
| final String name; |
| |
| NamedArgumentReference(this.name); |
| |
| ConstantExpressionKind get kind { |
| return ConstantExpressionKind.NAMED_REFERENCE; |
| } |
| |
| accept(ConstantExpressionVisitor visitor, [context]) { |
| return visitor.visitNamed(this, context); |
| } |
| |
| ConstantValue get value { |
| throw new UnsupportedError('NamedArgumentReference.value'); |
| } |
| |
| ConstantExpression apply(NormalizedArguments arguments) { |
| return arguments.getNamedArgument(name); |
| } |
| |
| @override |
| int _computeHashCode() => 13 * name.hashCode; |
| |
| @override |
| bool _equals(NamedArgumentReference other) => name == other.name; |
| |
| @override |
| ConstantValue evaluate(Environment environment, |
| ConstantSystem constantSystem) { |
| throw new UnsupportedError('NamedArgumentReference.evaluate'); |
| } |
| } |
| |
| abstract class FromEnvironmentConstantExpression extends ConstantExpression { |
| final ConstantValue value; |
| final String name; |
| final ConstantExpression defaultValue; |
| |
| FromEnvironmentConstantExpression(this.value, this.name, this.defaultValue); |
| |
| @override |
| int _computeHashCode() { |
| return 13 * name.hashCode + |
| 17 * defaultValue.hashCode; |
| } |
| |
| @override |
| bool _equals(FromEnvironmentConstantExpression other) { |
| return name == other.name && |
| defaultValue == other.defaultValue; |
| } |
| } |
| |
| /// A `const bool.fromEnvironment` constant. |
| class BoolFromEnvironmentConstantExpression |
| extends FromEnvironmentConstantExpression { |
| |
| BoolFromEnvironmentConstantExpression( |
| ConstantValue value, |
| String name, |
| ConstantExpression defaultValue) |
| : super(value, name, defaultValue); |
| |
| ConstantExpressionKind get kind { |
| return ConstantExpressionKind.BOOL_FROM_ENVIRONMENT; |
| } |
| |
| accept(ConstantExpressionVisitor visitor, [context]) { |
| return visitor.visitBoolFromEnvironment(this, context); |
| } |
| |
| @override |
| ConstantValue evaluate(Environment environment, |
| ConstantSystem constantSystem) { |
| String text = environment.readFromEnvironment(name); |
| if (text == 'true') { |
| return constantSystem.createBool(true); |
| } else if (text == 'false') { |
| return constantSystem.createBool(false); |
| } else { |
| return defaultValue.evaluate(environment, constantSystem); |
| } |
| } |
| |
| ConstantExpression apply(NormalizedArguments arguments) { |
| return new BoolFromEnvironmentConstantExpression( |
| null, name, defaultValue.apply(arguments)); |
| } |
| } |
| |
| /// A `const int.fromEnvironment` constant. |
| class IntFromEnvironmentConstantExpression |
| extends FromEnvironmentConstantExpression { |
| |
| IntFromEnvironmentConstantExpression( |
| ConstantValue value, |
| String name, |
| ConstantExpression defaultValue) |
| : super(value, name, defaultValue); |
| |
| ConstantExpressionKind get kind { |
| return ConstantExpressionKind.INT_FROM_ENVIRONMENT; |
| } |
| |
| accept(ConstantExpressionVisitor visitor, [context]) { |
| return visitor.visitIntFromEnvironment(this, context); |
| } |
| |
| @override |
| ConstantValue evaluate(Environment environment, |
| ConstantSystem constantSystem) { |
| int value; |
| String text = environment.readFromEnvironment(name); |
| if (text != null) { |
| value = int.parse(text, onError: (_) => null); |
| } |
| if (value == null) { |
| return defaultValue.evaluate(environment, constantSystem); |
| } else { |
| return constantSystem.createInt(value); |
| } |
| } |
| |
| ConstantExpression apply(NormalizedArguments arguments) { |
| return new IntFromEnvironmentConstantExpression( |
| null, name, defaultValue.apply(arguments)); |
| } |
| } |
| |
| /// A `const String.fromEnvironment` constant. |
| class StringFromEnvironmentConstantExpression |
| extends FromEnvironmentConstantExpression { |
| |
| StringFromEnvironmentConstantExpression( |
| ConstantValue value, |
| String name, |
| ConstantExpression defaultValue) |
| : super(value, name, defaultValue); |
| |
| ConstantExpressionKind get kind { |
| return ConstantExpressionKind.STRING_FROM_ENVIRONMENT; |
| } |
| |
| accept(ConstantExpressionVisitor visitor, [context]) { |
| return visitor.visitStringFromEnvironment(this, context); |
| } |
| |
| @override |
| ConstantValue evaluate(Environment environment, |
| ConstantSystem constantSystem) { |
| String text = environment.readFromEnvironment(name); |
| if (text == null) { |
| return defaultValue.evaluate(environment, constantSystem); |
| } else { |
| return constantSystem.createString(new DartString.literal(text)); |
| } |
| } |
| |
| ConstantExpression apply(NormalizedArguments arguments) { |
| return new StringFromEnvironmentConstantExpression( |
| null, name, defaultValue.apply(arguments)); |
| } |
| } |
| |
| /// A constant expression referenced with a deferred prefix. |
| /// For example `lib.C`. |
| class DeferredConstantExpression extends ConstantExpression { |
| final ConstantValue value; |
| final ConstantExpression expression; |
| final PrefixElement prefix; |
| |
| DeferredConstantExpression(this.value, this.expression, this.prefix); |
| |
| ConstantExpressionKind get kind => ConstantExpressionKind.DEFERRED; |
| |
| @override |
| ConstantValue evaluate(Environment environment, |
| ConstantSystem constantSystem) { |
| return expression.evaluate(environment, constantSystem); |
| } |
| |
| @override |
| int _computeHashCode() { |
| return 13 * expression.hashCode; |
| } |
| |
| @override |
| bool _equals(DeferredConstantExpression other) { |
| return expression == other.expression; |
| } |
| |
| @override |
| accept(ConstantExpressionVisitor visitor, [context]) { |
| return visitor.visitDeferred(this, context); |
| } |
| } |
| |
| abstract class ConstantExpressionVisitor<R, A> { |
| const ConstantExpressionVisitor(); |
| |
| R visit(ConstantExpression constant, A context) { |
| return constant.accept(this, context); |
| } |
| |
| R visitBool(BoolConstantExpression exp, A context); |
| R visitInt(IntConstantExpression exp, A context); |
| R visitDouble(DoubleConstantExpression exp, A context); |
| R visitString(StringConstantExpression exp, A context); |
| R visitNull(NullConstantExpression exp, A context); |
| R visitList(ListConstantExpression exp, A context); |
| R visitMap(MapConstantExpression exp, A context); |
| R visitConstructed(ConstructedConstantExpression exp, A context); |
| R visitConcatenate(ConcatenateConstantExpression exp, A context); |
| R visitSymbol(SymbolConstantExpression exp, A context); |
| R visitType(TypeConstantExpression exp, A context); |
| R visitVariable(VariableConstantExpression exp, A context); |
| R visitFunction(FunctionConstantExpression exp, A context); |
| R visitBinary(BinaryConstantExpression exp, A context); |
| R visitIdentical(IdenticalConstantExpression exp, A context); |
| R visitUnary(UnaryConstantExpression exp, A context); |
| R visitConditional(ConditionalConstantExpression exp, A context); |
| R visitBoolFromEnvironment(BoolFromEnvironmentConstantExpression exp, |
| A context); |
| R visitIntFromEnvironment(IntFromEnvironmentConstantExpression exp, |
| A context); |
| R visitStringFromEnvironment(StringFromEnvironmentConstantExpression exp, |
| A context); |
| R visitDeferred(DeferredConstantExpression exp, A context); |
| |
| R visitPositional(PositionalArgumentReference exp, A context); |
| R visitNamed(NamedArgumentReference exp, A context); |
| } |
| |
| /// Represents the declaration of a constant [element] with value [expression]. |
| // TODO(johnniwinther): Where does this class belong? |
| class ConstDeclaration { |
| final VariableElement element; |
| final ConstantExpression expression; |
| |
| ConstDeclaration(this.element, this.expression); |
| } |
| |
| class ConstExpPrinter extends ConstantExpressionVisitor { |
| final StringBuffer sb = new StringBuffer(); |
| |
| void write(ConstantExpression parent, |
| ConstantExpression child, |
| {bool leftAssociative: true}) { |
| if (child.precedence < parent.precedence || |
| !leftAssociative && child.precedence == parent.precedence) { |
| sb.write('('); |
| child.accept(this); |
| sb.write(')'); |
| } else { |
| child.accept(this); |
| } |
| } |
| |
| void writeTypeArguments(InterfaceType type) { |
| if (type.treatAsRaw) return; |
| sb.write('<'); |
| bool needsComma = false; |
| for (DartType value in type.typeArguments) { |
| if (needsComma) { |
| sb.write(', '); |
| } |
| sb.write(value); |
| needsComma = true; |
| } |
| sb.write('>'); |
| } |
| |
| @override |
| void visit(ConstantExpression constant, [_]) { |
| return constant.accept(this, null); |
| } |
| |
| void visitPrimitive(PrimitiveConstantExpression exp) { |
| sb.write(exp.primitiveValue); |
| } |
| |
| @override |
| void visitBool(BoolConstantExpression exp, [_]) { |
| visitPrimitive(exp); |
| } |
| |
| @override |
| void visitDouble(DoubleConstantExpression exp, [_]) { |
| visitPrimitive(exp); |
| } |
| |
| @override |
| void visitInt(IntConstantExpression exp, [_]) { |
| visitPrimitive(exp); |
| } |
| |
| @override |
| void visitNull(NullConstantExpression exp, [_]) { |
| visitPrimitive(exp); |
| } |
| |
| @override |
| void visitString(StringConstantExpression exp, [_]) { |
| // TODO(johnniwinther): Ensure correct escaping. |
| sb.write('"${exp.primitiveValue}"'); |
| } |
| |
| @override |
| void visitList(ListConstantExpression exp, [_]) { |
| sb.write('const '); |
| writeTypeArguments(exp.type); |
| sb.write('['); |
| bool needsComma = false; |
| for (ConstantExpression value in exp.values) { |
| if (needsComma) { |
| sb.write(', '); |
| } |
| visit(value); |
| needsComma = true; |
| } |
| sb.write(']'); |
| } |
| |
| @override |
| void visitMap(MapConstantExpression exp, [_]) { |
| sb.write('const '); |
| writeTypeArguments(exp.type); |
| sb.write('{'); |
| for (int index = 0; index < exp.keys.length; index++) { |
| if (index > 0) { |
| sb.write(', '); |
| } |
| visit(exp.keys[index]); |
| sb.write(': '); |
| visit(exp.values[index]); |
| } |
| sb.write('}'); |
| } |
| |
| @override |
| void visitConstructed(ConstructedConstantExpression exp, [_]) { |
| sb.write('const '); |
| sb.write(exp.target.enclosingClass.name); |
| if (exp.target.name != '') { |
| sb.write('.'); |
| sb.write(exp.target.name); |
| } |
| writeTypeArguments(exp.type); |
| sb.write('('); |
| bool needsComma = false; |
| |
| int namedOffset = exp.callStructure.positionalArgumentCount; |
| for (int index = 0; index < namedOffset; index++) { |
| if (needsComma) { |
| sb.write(', '); |
| } |
| visit(exp.arguments[index]); |
| needsComma = true; |
| } |
| for (int index = 0; index < exp.callStructure.namedArgumentCount; index++) { |
| if (needsComma) { |
| sb.write(', '); |
| } |
| sb.write(exp.callStructure.namedArguments[index]); |
| sb.write(': '); |
| visit(exp.arguments[namedOffset + index]); |
| needsComma = true; |
| } |
| sb.write(')'); |
| } |
| |
| @override |
| void visitConcatenate(ConcatenateConstantExpression exp, [_]) { |
| sb.write(exp.value.unparse()); |
| } |
| |
| @override |
| void visitSymbol(SymbolConstantExpression exp, [_]) { |
| sb.write('#'); |
| sb.write(exp.name); |
| } |
| |
| @override |
| void visitType(TypeConstantExpression exp, [_]) { |
| sb.write(exp.type.name); |
| } |
| |
| @override |
| void visitVariable(VariableConstantExpression exp, [_]) { |
| if (exp.element.isStatic) { |
| sb.write(exp.element.enclosingClass.name); |
| sb.write('.'); |
| } |
| sb.write(exp.element.name); |
| } |
| |
| @override |
| void visitFunction(FunctionConstantExpression exp, [_]) { |
| if (exp.element.isStatic) { |
| sb.write(exp.element.enclosingClass.name); |
| sb.write('.'); |
| } |
| sb.write(exp.element.name); |
| } |
| |
| @override |
| void visitBinary(BinaryConstantExpression exp, [_]) { |
| write(exp, exp.left); |
| sb.write(' '); |
| sb.write(exp.operator.name); |
| sb.write(' '); |
| write(exp, exp.right); |
| } |
| |
| @override |
| void visitIdentical(IdenticalConstantExpression exp, [_]) { |
| sb.write('identical('); |
| visit(exp.left); |
| sb.write(', '); |
| visit(exp.right); |
| sb.write(')'); |
| } |
| |
| @override |
| void visitUnary(UnaryConstantExpression exp, [_]) { |
| sb.write(exp.operator); |
| write(exp, exp.expression); |
| } |
| |
| @override |
| void visitConditional(ConditionalConstantExpression exp, [_]) { |
| write(exp, exp.condition, leftAssociative: false); |
| sb.write(' ? '); |
| write(exp, exp.trueExp); |
| sb.write(' : '); |
| write(exp, exp.falseExp); |
| } |
| |
| @override |
| void visitPositional(PositionalArgumentReference exp, [_]) { |
| // TODO(johnniwinther): Maybe this should throw. |
| sb.write('args[${exp.index}]'); |
| } |
| |
| @override |
| void visitNamed(NamedArgumentReference exp, [_]) { |
| // TODO(johnniwinther): Maybe this should throw. |
| sb.write('args[${exp.name}]'); |
| } |
| |
| @override |
| void visitDeferred(DeferredConstantExpression exp, context) { |
| sb.write(exp.prefix.deferredImport.prefix.source); |
| sb.write('.'); |
| write(exp, exp.expression); |
| } |
| |
| @override |
| void visitBoolFromEnvironment(BoolFromEnvironmentConstantExpression exp, |
| [_]) { |
| sb.write('const bool.fromEnvironment("${exp.name}", defaultValue: '); |
| visit(exp.defaultValue); |
| sb.write(')'); |
| } |
| |
| @override |
| void visitIntFromEnvironment(IntFromEnvironmentConstantExpression exp, [_]) { |
| sb.write('const int.fromEnvironment("${exp.name}", defaultValue: '); |
| visit(exp.defaultValue); |
| sb.write(')'); |
| } |
| |
| @override |
| void visitStringFromEnvironment(StringFromEnvironmentConstantExpression exp, |
| [_]) { |
| sb.write('const String.fromEnvironment("${exp.name}", defaultValue: '); |
| visit(exp.defaultValue); |
| sb.write(')'); |
| } |
| |
| String toString() => sb.toString(); |
| } |