| // 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. |
| |
| library vm.constants_native_effects; |
| |
| import '../ast.dart'; |
| import '../transformations/constants.dart'; |
| import '../core_types.dart'; |
| |
| class VmConstantsBackend implements ConstantsBackend { |
| final Map<String, String> defines; |
| |
| final Class immutableMapClass; |
| final Class internalSymbolClass; |
| final Class stringClass; |
| final Field symbolNameField; |
| |
| VmConstantsBackend._(this.defines, this.immutableMapClass, |
| this.internalSymbolClass, this.stringClass, this.symbolNameField); |
| |
| /// If [defines] is not `null` it will be used for handling |
| /// `const {bool,...}.fromEnvironment()` otherwise the current VM's values |
| /// will be used. |
| factory VmConstantsBackend(Map<String, String> defines, CoreTypes coreTypes) { |
| final Library coreLibrary = coreTypes.coreLibrary; |
| final Class immutableMapClass = coreLibrary.classes |
| .firstWhere((Class klass) => klass.name == '_ImmutableMap'); |
| assert(immutableMapClass != null); |
| |
| final Class internalSymbolClass = coreTypes.internalSymbolClass; |
| assert(internalSymbolClass != null); |
| |
| final Class stringClass = coreTypes.stringClass; |
| assert(stringClass != null); |
| |
| final Field symbolNameField = |
| internalSymbolClass.fields.where((Field field) { |
| return field.isInstanceMember && field.name.name == '_name'; |
| }).single; |
| |
| return new VmConstantsBackend._(defines, immutableMapClass, |
| internalSymbolClass, stringClass, symbolNameField); |
| } |
| |
| Constant buildConstantForNative( |
| String nativeName, |
| List<DartType> typeArguments, |
| List<Constant> positionalArguments, |
| Map<String, Constant> namedArguments, |
| List<TreeNode> context, |
| StaticInvocation node, |
| ErrorReporter errorReporter, |
| void abortEvaluation()) { |
| if ([ |
| 'Bool_fromEnvironment', |
| 'Integer_fromEnvironment', |
| 'String_fromEnvironment' |
| ].contains(nativeName)) { |
| final argument = positionalArguments[0]; |
| if (argument is StringConstant) { |
| final name = argument.value; |
| |
| Constant handleFromEnvironment<ValueT, ConstantT>( |
| {ValueT defaultValue, |
| ValueT parse(String v, {ValueT defaultValue}), |
| ValueT fromEnvironment(String name, {ValueT defaultValue}), |
| ConstantT makeConstant(ValueT val)}) { |
| final Constant constant = namedArguments['defaultValue']; |
| if (constant is ConstantT) { |
| defaultValue = (constant as dynamic).value; |
| } else if (constant is NullConstant) { |
| defaultValue = null; |
| } |
| ValueT value; |
| if (defines != null) { |
| value = parse(defines[name], defaultValue: defaultValue); |
| } else { |
| value = fromEnvironment(name, defaultValue: defaultValue); |
| } |
| return value != null ? makeConstant(value) : new NullConstant(); |
| } |
| |
| switch (nativeName) { |
| case 'Bool_fromEnvironment': |
| return handleFromEnvironment<bool, BoolConstant>( |
| defaultValue: false, |
| parse: (String v, {bool defaultValue}) { |
| final String defineValue = defines[name]; |
| return defineValue == 'true' |
| ? true |
| : (defineValue == 'false' ? false : defaultValue); |
| }, |
| fromEnvironment: (v, {defaultValue}) => |
| bool.fromEnvironment(v, defaultValue: defaultValue), |
| makeConstant: (v) => BoolConstant(v)); |
| case 'Integer_fromEnvironment': |
| return handleFromEnvironment<int, IntConstant>( |
| defaultValue: null, |
| parse: (String v, {int defaultValue}) { |
| final String defineValue = defines[name]; |
| return defineValue != null |
| ? (int.tryParse(defineValue) ?? defaultValue) |
| : defaultValue; |
| }, |
| fromEnvironment: (v, {defaultValue}) => |
| int.fromEnvironment(v, defaultValue: defaultValue), |
| makeConstant: (v) => new IntConstant(v)); |
| case 'String_fromEnvironment': |
| return handleFromEnvironment<String, StringConstant>( |
| defaultValue: null, |
| parse: (String v, {String defaultValue}) { |
| final String defineValue = defines[name]; |
| return defineValue ?? defaultValue; |
| }, |
| fromEnvironment: (v, {defaultValue}) => |
| String.fromEnvironment(v, defaultValue: defaultValue), |
| makeConstant: (v) => new StringConstant(v)); |
| } |
| } else { |
| errorReporter.invalidDartType(context, node.arguments.positional.first, |
| argument, new InterfaceType(stringClass)); |
| abortEvaluation(); |
| } |
| } |
| |
| throw 'No native effect registered for constant evaluation: $nativeName'; |
| } |
| |
| Constant lowerMapConstant(MapConstant constant) { |
| // The _ImmutableMap class is implemented via one field pointing to a list |
| // of key/value pairs -- see runtime/lib/immutable_map.dart! |
| final List<Constant> kvListPairs = |
| new List<Constant>(2 * constant.entries.length); |
| for (int i = 0; i < constant.entries.length; i++) { |
| final ConstantMapEntry entry = constant.entries[i]; |
| kvListPairs[2 * i] = entry.key; |
| kvListPairs[2 * i + 1] = entry.value; |
| } |
| // This is a bit fishy, since we merge the key and the value type by |
| // putting both into the same list. |
| final kvListConstant = new ListConstant(const DynamicType(), kvListPairs); |
| assert(immutableMapClass.fields.length == 1); |
| final Field kvPairListField = immutableMapClass.fields[0]; |
| return new InstanceConstant(immutableMapClass.reference, <DartType>[ |
| constant.keyType, |
| constant.valueType, |
| ], <Reference, Constant>{ |
| kvPairListField.reference: kvListConstant, |
| }); |
| } |
| |
| Constant lowerListConstant(ListConstant constant) { |
| // Currently we let vipunen deal with the [ListConstant]s. |
| return constant; |
| } |
| } |