blob: ff3431b216466600c203d759454843f03a7e98b1 [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";
abstract class ParsedPragma {}
enum PragmaEntryPointType { Default, GetterOnly, SetterOnly, CallOnly }
class ParsedEntryPointPragma extends ParsedPragma {
final PragmaEntryPointType type;
ParsedEntryPointPragma(this.type);
}
class ParsedResultTypeByTypePragma extends ParsedPragma {
final DartType type;
ParsedResultTypeByTypePragma(this.type);
}
class ParsedResultTypeByPathPragma extends ParsedPragma {
final String path;
ParsedResultTypeByPathPragma(this.path);
}
class ParsedNonNullableResultType extends ParsedPragma {
ParsedNonNullableResultType();
}
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.classReference.node == coreTypes.pragmaClass) {
pragmaConstant = constant;
}
}
}
if (pragmaConstant == null) return null;
String pragmaName;
Constant name = pragmaConstant.fieldValues[coreTypes.pragmaName.reference];
if (name is StringConstant) {
pragmaName = name.value;
} else {
return null;
}
Constant options =
pragmaConstant.fieldValues[coreTypes.pragmaOptions.reference];
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);
} else if (options is StringConstant) {
return new ParsedResultTypeByPathPragma(options.value);
}
throw "ERROR: Unsupported option to '$kExactResultTypePragmaName' "
"pragma: $options";
case kNonNullableResultType:
return new ParsedNonNullableResultType();
default:
return null;
}
}
}