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

Unified Diff: sdk/lib/_internal/compiler/implementation/patch_parser.dart

Issue 383413003: Add @Native(...) annotation for native class names. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Updated cf. comments. Created 6 years, 5 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
Index: sdk/lib/_internal/compiler/implementation/patch_parser.dart
diff --git a/sdk/lib/_internal/compiler/implementation/patch_parser.dart b/sdk/lib/_internal/compiler/implementation/patch_parser.dart
index 541091c93cefc3c1c537b79b81ff67ea5c3aa7f4..22c2d9d9151dafd1c7a4de6243ea7d4207461a2e 100644
--- a/sdk/lib/_internal/compiler/implementation/patch_parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/patch_parser.dart
@@ -230,11 +230,11 @@ class PatchElementListener extends ElementListener implements Listener {
}
}
-void patchElement(leg.DiagnosticListener listener,
+void patchElement(leg.Compiler compiler,
Element origin,
Element patch) {
if (origin == null) {
- listener.reportError(
+ compiler.reportError(
patch, leg.MessageKind.PATCH_NON_EXISTING, {'name': patch.name});
return;
}
@@ -243,48 +243,168 @@ void patchElement(leg.DiagnosticListener listener,
origin.isFunction ||
origin.isAbstractField)) {
// TODO(ahe): Remove this error when the parser rejects all bad modifiers.
- listener.reportError(origin, leg.MessageKind.PATCH_NONPATCHABLE);
+ compiler.reportError(origin, leg.MessageKind.PATCH_NONPATCHABLE);
return;
}
if (patch.isClass) {
- tryPatchClass(listener, origin, patch);
+ tryPatchClass(compiler, origin, patch);
} else if (patch.isGetter) {
- tryPatchGetter(listener, origin, patch);
+ tryPatchGetter(compiler, origin, patch);
} else if (patch.isSetter) {
- tryPatchSetter(listener, origin, patch);
+ tryPatchSetter(compiler, origin, patch);
} else if (patch.isConstructor) {
- tryPatchConstructor(listener, origin, patch);
+ tryPatchConstructor(compiler, origin, patch);
} else if(patch.isFunction) {
- tryPatchFunction(listener, origin, patch);
+ tryPatchFunction(compiler, origin, patch);
} else {
// TODO(ahe): Remove this error when the parser rejects all bad modifiers.
- listener.reportError(patch, leg.MessageKind.PATCH_NONPATCHABLE);
+ compiler.reportError(patch, leg.MessageKind.PATCH_NONPATCHABLE);
}
}
-void tryPatchClass(leg.DiagnosticListener listener,
- Element origin,
- ClassElement patch) {
+void tryPatchClass(leg.Compiler compiler,
+ Element origin,
+ ClassElement patch) {
if (!origin.isClass) {
- listener.reportError(
+ compiler.reportError(
origin, leg.MessageKind.PATCH_NON_CLASS, {'className': patch.name});
- listener.reportInfo(
+ compiler.reportInfo(
patch, leg.MessageKind.PATCH_POINT_TO_CLASS, {'className': patch.name});
return;
}
- patchClass(listener, origin, patch);
+ patchClass(compiler, origin, patch);
}
-void patchClass(leg.DiagnosticListener listener,
+void patchClass(leg.Compiler compiler,
ClassElementX origin,
ClassElementX patch) {
if (origin.isPatched) {
- listener.internalError(origin,
+ compiler.internalError(origin,
"Patching the same class more than once.");
}
origin.applyPatch(patch);
+ checkNativeAnnotation(compiler, patch);
}
+/// Check whether [cls] has a `@Native(...)` annotation, and if so, set its
+/// native name from the annotation.
+checkNativeAnnotation(leg.Compiler compiler, ClassElement cls) {
+ EagerAnnotationHandler.checkAnnotation(compiler, cls,
+ const NativeAnnotationHandler());
+}
+
+/// Abstract interface for pre-resolution detection of metadata.
+///
+/// The detection is handled in two steps:
+/// - match the annotation syntactically and assume that the annotation is valid
+/// if it looks correct,
+/// - setup a deferred action to check that the annotation has a valid constant
+/// value and report an internal error if not.
+abstract class EagerAnnotationHandler {
+ /// Checks that [annotation] looks like a matching annotation and optionally
+ /// applies actions on [element]. Returns `true` if the annotation matched.
+ bool apply(leg.Compiler compiler,
+ Element element,
+ MetadataAnnotation annotation);
+
+ /// Checks that the annotation value is valid.
+ void validate(leg.Compiler compiler,
+ Element element,
+ MetadataAnnotation annotation,
+ leg.Constant constant);
+
+
+ /// Checks [element] for metadata matching the [handler]. Return `true` if
+ /// matching metadata was found.
+ static bool checkAnnotation(leg.Compiler compiler,
+ Element element,
+ EagerAnnotationHandler handler) {
+ for (Link<MetadataAnnotation> link = element.metadata;
+ !link.isEmpty;
+ link = link.tail) {
+ MetadataAnnotation annotation = link.head;
+ if (handler.apply(compiler, element, annotation)) {
+ // TODO(johnniwinther): Perform this check in
+ // [Compiler.onLibrariesLoaded].
+ compiler.enqueuer.resolution.addDeferredAction(element, () {
+ annotation.ensureResolved(compiler);
+ handler.validate(compiler, element, annotation, annotation.value);
+ });
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+/// Annotation handler for pre-resolution detection of `@Native(...)`
+/// annotations.
+class NativeAnnotationHandler implements EagerAnnotationHandler {
+ const NativeAnnotationHandler();
+
+ String getNativeAnnotation(MetadataAnnotation annotation) {
+ if (annotation.beginToken != null &&
+ annotation.beginToken.next.value == 'Native') {
+ // Skipping '@', 'Native', and '('.
+ Token argument = annotation.beginToken.next.next.next;
+ if (argument is StringToken) {
+ return argument.value;
+ }
+ }
+ return null;
+ }
+
+ bool apply(leg.Compiler compiler,
+ Element element,
+ MetadataAnnotation annotation) {
+ if (element.isClass) {
+ String native = getNativeAnnotation(annotation);
+ if (native != null) {
+ ClassElementX declaration = element.declaration;
+ declaration.setNative(native);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void validate(leg.Compiler compiler,
+ Element element,
+ MetadataAnnotation annotation,
+ leg.Constant constant) {
+ if (constant.computeType(compiler).element !=
+ compiler.nativeAnnotationClass) {
+ compiler.internalError(annotation, 'Invalid @Native(...) annotation.');
+ }
+ }
+}
+
+/// Annotation handler for pre-resolution detection of `@patch` annotations.
+class PatchAnnotationHandler implements EagerAnnotationHandler {
+ const PatchAnnotationHandler();
+
+ bool isPatchAnnotation(MetadataAnnotation annotation) {
+ return annotation.beginToken != null &&
+ annotation.beginToken.next.value == 'patch';
+ }
+
+ bool apply(leg.Compiler compiler,
+ Element element,
+ MetadataAnnotation annotation) {
+ return isPatchAnnotation(annotation);
+ }
+
+ void validate(leg.Compiler compiler,
+ Element element,
+ MetadataAnnotation annotation,
+ leg.Constant constant) {
+ if (constant != compiler.patchConstant) {
+ compiler.internalError(annotation, 'Invalid patch annotation.');
+ }
+ }
+}
+
+
void tryPatchGetter(leg.DiagnosticListener listener,
Element origin,
FunctionElement patch) {
@@ -381,24 +501,6 @@ void patchFunction(leg.DiagnosticListener listener,
// TODO(johnniwinther): Add unittest when patch is (real) metadata.
bool isPatchElement(leg.Compiler compiler, Element element) {
- // TODO(lrn): More checks needed if we introduce metadata for real.
- // In that case, it must have the identifier "native" as metadata.
- for (Link<MetadataAnnotation> link = element.metadata;
- !link.isEmpty;
- link = link.tail) {
- MetadataAnnotation annotation = link.head;
- if (annotation.beginToken != null &&
- annotation.beginToken.next.value == 'patch') {
- // TODO(johnniwinther): Perform this check in
- // [Compiler.onLibrariesLoaded].
- compiler.enqueuer.resolution.addDeferredAction(element, () {
- annotation.ensureResolved(compiler);
- if (annotation.value != compiler.patchConstant) {
- compiler.internalError(annotation, 'Invalid patch annotation.');
- }
- });
- return true;
- }
- }
- return false;
+ return EagerAnnotationHandler.checkAnnotation(compiler, element,
+ const PatchAnnotationHandler());
}

Powered by Google App Engine
This is Rietveld 408576698