blob: cde363a214720c3f3e33e7519a3541ccc359d155 [file] [log] [blame]
// 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;
}
}
}