// Copyright (c) 2018, 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.transformations.pragma; import 'package:kernel/ast.dart'; import 'package:kernel/core_types.dart' show CoreTypes; const kEntryPointPragmaName = "vm:entry-point"; const kExactResultTypePragmaName = "vm:exact-result-type"; const kNonNullableResultType = "vm:non-nullable-result-type"; const kResultTypeUsesPassedTypeArguments = "result-type-uses-passed-type-arguments"; const kRecognizedPragmaName = "vm:recognized"; const kDisableUnboxedParametetersPragmaName = "vm:disable-unboxed-parameters"; abstract class ParsedPragma {} enum PragmaEntryPointType { Default, GetterOnly, SetterOnly, CallOnly } enum PragmaRecognizedType { AsmIntrinsic, GraphIntrinsic, Other } class ParsedEntryPointPragma extends ParsedPragma { final PragmaEntryPointType type; ParsedEntryPointPragma(this.type); } class ParsedResultTypeByTypePragma extends ParsedPragma { final DartType type; final bool resultTypeUsesPassedTypeArguments; ParsedResultTypeByTypePragma( this.type, this.resultTypeUsesPassedTypeArguments); } class ParsedResultTypeByPathPragma extends ParsedPragma { final String path; ParsedResultTypeByPathPragma(this.path); } class ParsedNonNullableResultType extends ParsedPragma { ParsedNonNullableResultType(); } class ParsedRecognized extends ParsedPragma { final PragmaRecognizedType type; ParsedRecognized(this.type); } class ParsedDisableUnboxedParameters extends ParsedPragma { ParsedDisableUnboxedParameters(); } abstract class PragmaAnnotationParser { /// May return 'null' if the annotation does not represent a recognized /// @pragma. ParsedPragma parsePragma(Expression annotation); } class ConstantPragmaAnnotationParser extends PragmaAnnotationParser { final CoreTypes coreTypes; ConstantPragmaAnnotationParser(this.coreTypes); ParsedPragma parsePragma(Expression annotation) { InstanceConstant pragmaConstant; if (annotation is ConstantExpression) { Constant constant = annotation.constant; if (constant is InstanceConstant) { if (constant.classNode == coreTypes.pragmaClass) { pragmaConstant = constant; } } else if (constant is UnevaluatedConstant) { throw 'Error: unevaluated constant $constant'; } } else { throw 'Error: non-constant annotation $annotation'; } if (pragmaConstant == null) return null; String pragmaName; Constant name = pragmaConstant.fieldValues[coreTypes.pragmaName.getterReference]; if (name is StringConstant) { pragmaName = name.value; } else { return null; } Constant options = pragmaConstant.fieldValues[coreTypes.pragmaOptions.getterReference]; assert(options != null); switch (pragmaName) { case kEntryPointPragmaName: PragmaEntryPointType type; if (options is NullConstant) { type = PragmaEntryPointType.Default; } else if (options is BoolConstant && options.value == true) { type = PragmaEntryPointType.Default; } else if (options is StringConstant) { if (options.value == "get") { type = PragmaEntryPointType.GetterOnly; } else if (options.value == "set") { type = PragmaEntryPointType.SetterOnly; } else if (options.value == "call") { type = PragmaEntryPointType.CallOnly; } else { throw "Error: string directive to @pragma('$kEntryPointPragmaName', ...) " "must be either 'get' or 'set' for fields " "or 'get' or 'call' for procedures."; } } return type != null ? new ParsedEntryPointPragma(type) : null; case kExactResultTypePragmaName: if (options == null) return null; if (options is TypeLiteralConstant) { return new ParsedResultTypeByTypePragma(options.type, false); } else if (options is StringConstant) { return new ParsedResultTypeByPathPragma(options.value); } else if (options is ListConstant && options.entries.length == 2 && options.entries[0] is TypeLiteralConstant && options.entries[1] is StringConstant && (options.entries[1] as StringConstant).value == kResultTypeUsesPassedTypeArguments) { return new ParsedResultTypeByTypePragma( (options.entries[0] as TypeLiteralConstant).type, true); } throw "ERROR: Unsupported option to '$kExactResultTypePragmaName' " "pragma: $options"; case kNonNullableResultType: return new ParsedNonNullableResultType(); case kRecognizedPragmaName: PragmaRecognizedType type; if (options is StringConstant) { if (options.value == "asm-intrinsic") { type = PragmaRecognizedType.AsmIntrinsic; } else if (options.value == "graph-intrinsic") { type = PragmaRecognizedType.GraphIntrinsic; } else if (options.value == "other") { type = PragmaRecognizedType.Other; } } if (type == null) { throw "ERROR: Unsupported option to '$kRecognizedPragmaName' " "pragma: $options"; } return new ParsedRecognized(type); case kDisableUnboxedParametetersPragmaName: return new ParsedDisableUnboxedParameters(); default: return null; } } }