Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(97)

Unified Diff: pkg/compiler/lib/src/kernel/element_adapter.dart

Issue 2663793002: Extract reusable parts of KernelAstAdapter in a mixin. (Closed)
Patch Set: Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/kernel/element_adapter.dart
diff --git a/pkg/compiler/lib/src/kernel/element_adapter.dart b/pkg/compiler/lib/src/kernel/element_adapter.dart
index 5d9f69dc51fb983c31f1a356f6d7add69d9eb84a..15d7e0e96e4d8de0194e17b23f5bc7550190bd2d 100644
--- a/pkg/compiler/lib/src/kernel/element_adapter.dart
+++ b/pkg/compiler/lib/src/kernel/element_adapter.dart
@@ -4,15 +4,22 @@
import 'package:kernel/ast.dart' as ir;
+import '../common.dart';
+import '../common/names.dart';
+import '../core_types.dart';
import '../elements/elements.dart';
import '../elements/entities.dart';
import '../elements/types.dart';
+import '../js_backend/backend_helpers.dart';
import '../native/native.dart' as native;
import '../universe/call_structure.dart';
import '../universe/selector.dart';
/// Interface that translates between Kernel IR nodes and entities.
abstract class KernelElementAdapter {
+ /// Access to the commonly used elements and types.
+ CommonElements get commonElements;
+
/// Returns the [DartType] corresponding to [type].
DartType getDartType(ir.DartType type);
@@ -52,7 +59,7 @@ abstract class KernelElementAdapter {
/// Returns the [Local] corresponding to the [node]. The node must be either
/// a [ir.FunctionDeclaration] or [ir.FunctionExpression].
- Local getLocalFunction(ir.Node node);
+ Local getLocalFunction(ir.TreeNode node);
/// Returns the [LibraryEntity] corresponding to the library [node].
LibraryEntity getLibrary(ir.Library node);
@@ -104,3 +111,266 @@ enum ForeignKind {
JS_INTERCEPTOR_CONSTANT,
NONE,
}
+
+abstract class KernelElementAdapterMixin implements KernelElementAdapter {
+ DiagnosticReporter get reporter;
+ CommonElements get commonElements;
+
+ LibraryEntity lookupLibrary(Uri uri);
+ ClassEntity lookupClass(LibraryEntity library, String name);
+ InterfaceType getRawType(ClassEntity cls);
+ InterfaceType getThisType(ClassEntity cls);
+
+ @override
+ Name getName(ir.Name name) {
+ return new Name(
+ name.name, name.isPrivate ? getLibrary(name.library) : null);
+ }
+
+ @override
+ CallStructure getCallStructure(ir.Arguments arguments) {
+ int argumentCount = arguments.positional.length + arguments.named.length;
+ List<String> namedArguments = arguments.named.map((e) => e.name).toList();
+ return new CallStructure(argumentCount, namedArguments);
+ }
+
+ @override
+ Selector getSelector(ir.Expression node) {
+ if (node is ir.PropertyGet) return getGetterSelector(node);
+ if (node is ir.PropertySet) return getSetterSelector(node);
+ if (node is ir.InvocationExpression) return getInvocationSelector(node);
+ throw new SpannableAssertionFailure(CURRENT_ELEMENT_SPANNABLE,
+ "Can only get the selector for a property get or an invocation: ${node}");
Johnni Winther 2017/01/30 14:40:00 Fixed in later CL (dartfmt doesn't handle this)
+ }
+
+ Selector getInvocationSelector(ir.InvocationExpression invocation) {
+ Name name = getName(invocation.name);
+ SelectorKind kind;
+ if (Elements.isOperatorName(invocation.name.name)) {
+ if (name == Names.INDEX_NAME || name == Names.INDEX_SET_NAME) {
+ kind = SelectorKind.INDEX;
+ } else {
+ kind = SelectorKind.OPERATOR;
+ }
+ } else {
+ kind = SelectorKind.CALL;
+ }
+
+ CallStructure callStructure = getCallStructure(invocation.arguments);
+ return new Selector(kind, name, callStructure);
+ }
+
+ Selector getGetterSelector(ir.PropertyGet getter) {
+ ir.Name irName = getter.name;
+ Name name = new Name(
+ irName.name, irName.isPrivate ? getLibrary(irName.library) : null);
+ return new Selector.getter(name);
+ }
+
+ Selector getSetterSelector(ir.PropertySet setter) {
+ ir.Name irName = setter.name;
+ Name name = new Name(
+ irName.name, irName.isPrivate ? getLibrary(irName.library) : null);
+ return new Selector.setter(name);
+ }
+
+ /// Returns `true` is [node] has a `@Native(...)` annotation.
+ // TODO(johnniwinther): Cache this for later use.
+ bool isNativeClass(ir.Class node) {
+ for (ir.Expression annotation in node.annotations) {
+ if (annotation is ir.ConstructorInvocation) {
+ FunctionEntity target = getConstructor(annotation.target);
+ if (target.enclosingClass == commonElements.nativeAnnotationClass) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /// Compute the kind of foreign helper function called by [node], if any.
+ ForeignKind getForeignKind(ir.StaticInvocation node) {
+ if (isForeignLibrary(node.target.enclosingLibrary)) {
+ switch (node.target.name.name) {
+ case BackendHelpers.JS:
+ return ForeignKind.JS;
+ case BackendHelpers.JS_BUILTIN:
+ return ForeignKind.JS_BUILTIN;
+ case BackendHelpers.JS_EMBEDDED_GLOBAL:
+ return ForeignKind.JS_EMBEDDED_GLOBAL;
+ case BackendHelpers.JS_INTERCEPTOR_CONSTANT:
+ return ForeignKind.JS_INTERCEPTOR_CONSTANT;
+ }
+ }
+ return ForeignKind.NONE;
+ }
+
+ /// Return `true` if [node] is the `dart:_foreign_helper` library.
+ bool isForeignLibrary(ir.Library node) {
+ return node.importUri == BackendHelpers.DART_FOREIGN_HELPER;
+ }
+
+ /// Looks up [typeName] for use in the spec-string of a `JS` called.
+ // TODO(johnniwinther): Use this in [native.NativeBehavior] instead of calling
+ // the `ForeignResolver`.
+ // TODO(johnniwinther): Cache the result to avoid redundant lookups?
+ native.TypeLookup typeLookup({bool resolveAsRaw: true}) {
+ return (String typeName) {
+ DartType findIn(Uri uri) {
+ LibraryEntity library = lookupLibrary(uri);
+ if (library != null) {
+ ClassEntity cls = lookupClass(library, typeName);
+ if (cls != null) {
+ // TODO(johnniwinther): Align semantics.
+ return resolveAsRaw ? getRawType(cls) : getThisType(cls);
+ }
+ }
+ return null;
+ }
+
+ DartType type = findIn(Uris.dart_core);
+ type ??= findIn(BackendHelpers.DART_JS_HELPER);
+ type ??= findIn(BackendHelpers.DART_INTERCEPTORS);
+ type ??= findIn(BackendHelpers.DART_ISOLATE_HELPER);
+ type ??= findIn(Uris.dart_collection);
+ type ??= findIn(Uris.dart_html);
+ type ??= findIn(Uris.dart_svg);
+ type ??= findIn(Uris.dart_web_audio);
+ type ??= findIn(Uris.dart_web_gl);
+ return type;
+ };
+ }
+
+ String _getStringArgument(ir.StaticInvocation node, int index) {
+ return node.arguments.positional[index].accept(new Stringifier());
+ }
+
+ /// Computes the [native.NativeBehavior] for a call to the [JS] function.
+ // TODO(johnniwinther): Cache this for later use.
+ native.NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node) {
+ if (node.arguments.positional.length < 2 ||
+ node.arguments.named.isNotEmpty) {
+ reporter.reportErrorMessage(
+ CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS);
+ return new native.NativeBehavior();
+ }
+ String specString = _getStringArgument(node, 0);
+ if (specString == null) {
+ reporter.reportErrorMessage(
+ CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_FIRST);
+ return new native.NativeBehavior();
+ }
+
+ String codeString = _getStringArgument(node, 1);
+ if (codeString == null) {
+ reporter.reportErrorMessage(
+ CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_SECOND);
+ return new native.NativeBehavior();
+ }
+
+ return native.NativeBehavior.ofJsCall(
+ specString,
+ codeString,
+ typeLookup(resolveAsRaw: true),
+ CURRENT_ELEMENT_SPANNABLE,
+ reporter,
+ commonElements);
+ }
+
+ /// Computes the [native.NativeBehavior] for a call to the [JS_BUILTIN]
+ /// function.
+ // TODO(johnniwinther): Cache this for later use.
+ native.NativeBehavior getNativeBehaviorForJsBuiltinCall(
+ ir.StaticInvocation node) {
+ if (node.arguments.positional.length < 1) {
+ reporter.internalError(
+ CURRENT_ELEMENT_SPANNABLE, "JS builtin expression has no type.");
+ return new native.NativeBehavior();
+ }
+ if (node.arguments.positional.length < 2) {
+ reporter.internalError(
+ CURRENT_ELEMENT_SPANNABLE, "JS builtin is missing name.");
+ return new native.NativeBehavior();
+ }
+ String specString = _getStringArgument(node, 0);
+ if (specString == null) {
+ reporter.internalError(
+ CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument.");
+ return new native.NativeBehavior();
+ }
+ return native.NativeBehavior.ofJsBuiltinCall(
+ specString,
+ typeLookup(resolveAsRaw: true),
+ CURRENT_ELEMENT_SPANNABLE,
+ reporter,
+ commonElements);
+ }
+
+ /// Computes the [native.NativeBehavior] for a call to the
+ /// [JS_EMBEDDED_GLOBAL] function.
+ // TODO(johnniwinther): Cache this for later use.
+ native.NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
+ ir.StaticInvocation node) {
+ if (node.arguments.positional.length < 1) {
+ reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
+ "JS embedded global expression has no type.");
+ return new native.NativeBehavior();
+ }
+ if (node.arguments.positional.length < 2) {
+ reporter.internalError(
+ CURRENT_ELEMENT_SPANNABLE, "JS embedded global is missing name.");
+ return new native.NativeBehavior();
+ }
+ if (node.arguments.positional.length > 2 ||
+ node.arguments.named.isNotEmpty) {
+ reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
+ "JS embedded global has more than 2 arguments.");
+ return new native.NativeBehavior();
+ }
+ String specString = _getStringArgument(node, 0);
+ if (specString == null) {
+ reporter.internalError(
+ CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument.");
+ return new native.NativeBehavior();
+ }
+ return native.NativeBehavior.ofJsEmbeddedGlobalCall(
+ specString,
+ typeLookup(resolveAsRaw: true),
+ CURRENT_ELEMENT_SPANNABLE,
+ reporter,
+ commonElements);
+ }
+
+ /// Computes the [InterfaceType] referenced by a call to the
+ /// [JS_INTERCEPTOR_CONSTANT] function, if any.
+ InterfaceType getInterfaceTypeForJsInterceptorCall(ir.StaticInvocation node) {
+ if (node.arguments.positional.length != 1 ||
+ node.arguments.named.isNotEmpty) {
+ reporter.reportErrorMessage(CURRENT_ELEMENT_SPANNABLE,
+ MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
+ }
+ ir.Node argument = node.arguments.positional.first;
+ if (argument is ir.TypeLiteral && argument.type is ir.InterfaceType) {
+ return getInterfaceType(argument.type);
+ }
+ return null;
+ }
+}
+
+/// Visitor that converts string literals and concatenations of string literals
+/// into the string value.
+class Stringifier extends ir.ExpressionVisitor<String> {
+ @override
+ String visitStringLiteral(ir.StringLiteral node) => node.value;
+
+ @override
+ String visitStringConcatenation(ir.StringConcatenation node) {
+ StringBuffer sb = new StringBuffer();
+ for (ir.Expression expression in node.expressions) {
+ String value = expression.accept(this);
+ if (value == null) return null;
+ sb.write(value);
+ }
+ return sb.toString();
+ }
+}
« no previous file with comments | « no previous file | pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698