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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /** 5 /**
6 * This library contains the infrastructure to parse and integrate patch files. 6 * This library contains the infrastructure to parse and integrate patch files.
7 * 7 *
8 * Three types of elements can be patched: [LibraryElement], [ClassElement], 8 * Three types of elements can be patched: [LibraryElement], [ClassElement],
9 * [FunctionElement]. Patches are introduced in patch libraries which are loaded 9 * [FunctionElement]. Patches are introduced in patch libraries which are loaded
10 * together with the corresponding origin library. Which libraries that are 10 * together with the corresponding origin library. Which libraries that are
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 super.pushElement(patch); 223 super.pushElement(patch);
224 if (isPatchElement(compiler, patch)) { 224 if (isPatchElement(compiler, patch)) {
225 LibraryElement originLibrary = compilationUnitElement.library; 225 LibraryElement originLibrary = compilationUnitElement.library;
226 assert(originLibrary.isPatched); 226 assert(originLibrary.isPatched);
227 Element origin = originLibrary.localLookup(patch.name); 227 Element origin = originLibrary.localLookup(patch.name);
228 patchElement(listener, origin, patch); 228 patchElement(listener, origin, patch);
229 } 229 }
230 } 230 }
231 } 231 }
232 232
233 void patchElement(leg.DiagnosticListener listener, 233 void patchElement(leg.Compiler compiler,
234 Element origin, 234 Element origin,
235 Element patch) { 235 Element patch) {
236 if (origin == null) { 236 if (origin == null) {
237 listener.reportError( 237 compiler.reportError(
238 patch, leg.MessageKind.PATCH_NON_EXISTING, {'name': patch.name}); 238 patch, leg.MessageKind.PATCH_NON_EXISTING, {'name': patch.name});
239 return; 239 return;
240 } 240 }
241 if (!(origin.isClass || 241 if (!(origin.isClass ||
242 origin.isConstructor || 242 origin.isConstructor ||
243 origin.isFunction || 243 origin.isFunction ||
244 origin.isAbstractField)) { 244 origin.isAbstractField)) {
245 // TODO(ahe): Remove this error when the parser rejects all bad modifiers. 245 // TODO(ahe): Remove this error when the parser rejects all bad modifiers.
246 listener.reportError(origin, leg.MessageKind.PATCH_NONPATCHABLE); 246 compiler.reportError(origin, leg.MessageKind.PATCH_NONPATCHABLE);
247 return; 247 return;
248 } 248 }
249 if (patch.isClass) { 249 if (patch.isClass) {
250 tryPatchClass(listener, origin, patch); 250 tryPatchClass(compiler, origin, patch);
251 } else if (patch.isGetter) { 251 } else if (patch.isGetter) {
252 tryPatchGetter(listener, origin, patch); 252 tryPatchGetter(compiler, origin, patch);
253 } else if (patch.isSetter) { 253 } else if (patch.isSetter) {
254 tryPatchSetter(listener, origin, patch); 254 tryPatchSetter(compiler, origin, patch);
255 } else if (patch.isConstructor) { 255 } else if (patch.isConstructor) {
256 tryPatchConstructor(listener, origin, patch); 256 tryPatchConstructor(compiler, origin, patch);
257 } else if(patch.isFunction) { 257 } else if(patch.isFunction) {
258 tryPatchFunction(listener, origin, patch); 258 tryPatchFunction(compiler, origin, patch);
259 } else { 259 } else {
260 // TODO(ahe): Remove this error when the parser rejects all bad modifiers. 260 // TODO(ahe): Remove this error when the parser rejects all bad modifiers.
261 listener.reportError(patch, leg.MessageKind.PATCH_NONPATCHABLE); 261 compiler.reportError(patch, leg.MessageKind.PATCH_NONPATCHABLE);
262 } 262 }
263 } 263 }
264 264
265 void tryPatchClass(leg.DiagnosticListener listener, 265 void tryPatchClass(leg.Compiler compiler,
266 Element origin, 266 Element origin,
267 ClassElement patch) { 267 ClassElement patch) {
268 if (!origin.isClass) { 268 if (!origin.isClass) {
269 listener.reportError( 269 compiler.reportError(
270 origin, leg.MessageKind.PATCH_NON_CLASS, {'className': patch.name}); 270 origin, leg.MessageKind.PATCH_NON_CLASS, {'className': patch.name});
271 listener.reportInfo( 271 compiler.reportInfo(
272 patch, leg.MessageKind.PATCH_POINT_TO_CLASS, {'className': patch.name}); 272 patch, leg.MessageKind.PATCH_POINT_TO_CLASS, {'className': patch.name});
273 return; 273 return;
274 } 274 }
275 patchClass(listener, origin, patch); 275 patchClass(compiler, origin, patch);
276 } 276 }
277 277
278 void patchClass(leg.DiagnosticListener listener, 278 void patchClass(leg.Compiler compiler,
279 ClassElementX origin, 279 ClassElementX origin,
280 ClassElementX patch) { 280 ClassElementX patch) {
281 if (origin.isPatched) { 281 if (origin.isPatched) {
282 listener.internalError(origin, 282 compiler.internalError(origin,
283 "Patching the same class more than once."); 283 "Patching the same class more than once.");
284 } 284 }
285 origin.applyPatch(patch); 285 origin.applyPatch(patch);
286 checkNativeAnnotation(compiler, patch);
286 } 287 }
287 288
289 /// Check whether [cls] has a `@Native(...)` annotation, and if so, set its
290 /// native name from the annotation.
291 checkNativeAnnotation(leg.Compiler compiler, ClassElement cls) {
292 EagerAnnotationHandler.checkAnnotation(compiler, cls,
293 const NativeAnnotationHandler());
294 }
295
296 /// Abstract interface for pre-resolution detection of metadata.
297 ///
298 /// The detection is handled in two steps:
299 /// - match the annotation syntactically and assume that the annotation is valid
300 /// if it looks correct,
301 /// - setup a deferred action to check that the annotation has a valid constant
302 /// value and report an internal error if not.
303 abstract class EagerAnnotationHandler {
304 /// Checks that [annotation] looks like a matching annotation and optionally
305 /// applies actions on [element]. Returns `true` if the annotation matched.
306 bool apply(leg.Compiler compiler,
307 Element element,
308 MetadataAnnotation annotation);
309
310 /// Checks that the annotation value is valid.
311 void validate(leg.Compiler compiler,
312 Element element,
313 MetadataAnnotation annotation,
314 leg.Constant constant);
315
316
317 /// Checks [element] for metadata matching the [handler]. Return `true` if
318 /// matching metadata was found.
319 static bool checkAnnotation(leg.Compiler compiler,
320 Element element,
321 EagerAnnotationHandler handler) {
322 for (Link<MetadataAnnotation> link = element.metadata;
323 !link.isEmpty;
324 link = link.tail) {
325 MetadataAnnotation annotation = link.head;
326 if (handler.apply(compiler, element, annotation)) {
327 // TODO(johnniwinther): Perform this check in
328 // [Compiler.onLibrariesLoaded].
329 compiler.enqueuer.resolution.addDeferredAction(element, () {
330 annotation.ensureResolved(compiler);
331 handler.validate(compiler, element, annotation, annotation.value);
332 });
333 return true;
334 }
335 }
336 return false;
337 }
338 }
339
340 /// Annotation handler for pre-resolution detection of `@Native(...)`
341 /// annotations.
342 class NativeAnnotationHandler implements EagerAnnotationHandler {
343 const NativeAnnotationHandler();
344
345 String getNativeAnnotation(MetadataAnnotation annotation) {
346 if (annotation.beginToken != null &&
347 annotation.beginToken.next.value == 'Native') {
348 // Skipping '@', 'Native', and '('.
349 Token argument = annotation.beginToken.next.next.next;
350 if (argument is StringToken) {
351 return argument.value;
352 }
353 }
354 return null;
355 }
356
357 bool apply(leg.Compiler compiler,
358 Element element,
359 MetadataAnnotation annotation) {
360 if (element.isClass) {
361 String native = getNativeAnnotation(annotation);
362 if (native != null) {
363 ClassElementX declaration = element.declaration;
364 declaration.setNative(native);
365 return true;
366 }
367 }
368 return false;
369 }
370
371 void validate(leg.Compiler compiler,
372 Element element,
373 MetadataAnnotation annotation,
374 leg.Constant constant) {
375 if (constant.computeType(compiler).element !=
376 compiler.nativeAnnotationClass) {
377 compiler.internalError(annotation, 'Invalid @Native(...) annotation.');
378 }
379 }
380 }
381
382 /// Annotation handler for pre-resolution detection of `@patch` annotations.
383 class PatchAnnotationHandler implements EagerAnnotationHandler {
384 const PatchAnnotationHandler();
385
386 bool isPatchAnnotation(MetadataAnnotation annotation) {
387 return annotation.beginToken != null &&
388 annotation.beginToken.next.value == 'patch';
389 }
390
391 bool apply(leg.Compiler compiler,
392 Element element,
393 MetadataAnnotation annotation) {
394 return isPatchAnnotation(annotation);
395 }
396
397 void validate(leg.Compiler compiler,
398 Element element,
399 MetadataAnnotation annotation,
400 leg.Constant constant) {
401 if (constant != compiler.patchConstant) {
402 compiler.internalError(annotation, 'Invalid patch annotation.');
403 }
404 }
405 }
406
407
288 void tryPatchGetter(leg.DiagnosticListener listener, 408 void tryPatchGetter(leg.DiagnosticListener listener,
289 Element origin, 409 Element origin,
290 FunctionElement patch) { 410 FunctionElement patch) {
291 if (!origin.isAbstractField) { 411 if (!origin.isAbstractField) {
292 listener.reportError( 412 listener.reportError(
293 origin, leg.MessageKind.PATCH_NON_GETTER, {'name': origin.name}); 413 origin, leg.MessageKind.PATCH_NON_GETTER, {'name': origin.name});
294 listener.reportInfo( 414 listener.reportInfo(
295 patch, 415 patch,
296 leg.MessageKind.PATCH_POINT_TO_GETTER, {'getterName': patch.name}); 416 leg.MessageKind.PATCH_POINT_TO_GETTER, {'getterName': patch.name});
297 return; 417 return;
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
374 } 494 }
375 if (origin.isPatched) { 495 if (origin.isPatched) {
376 listener.internalError(origin, 496 listener.internalError(origin,
377 "Trying to patch a function more than once."); 497 "Trying to patch a function more than once.");
378 } 498 }
379 origin.applyPatch(patch); 499 origin.applyPatch(patch);
380 } 500 }
381 501
382 // TODO(johnniwinther): Add unittest when patch is (real) metadata. 502 // TODO(johnniwinther): Add unittest when patch is (real) metadata.
383 bool isPatchElement(leg.Compiler compiler, Element element) { 503 bool isPatchElement(leg.Compiler compiler, Element element) {
384 // TODO(lrn): More checks needed if we introduce metadata for real. 504 return EagerAnnotationHandler.checkAnnotation(compiler, element,
385 // In that case, it must have the identifier "native" as metadata. 505 const PatchAnnotationHandler());
386 for (Link<MetadataAnnotation> link = element.metadata;
387 !link.isEmpty;
388 link = link.tail) {
389 MetadataAnnotation annotation = link.head;
390 if (annotation.beginToken != null &&
391 annotation.beginToken.next.value == 'patch') {
392 // TODO(johnniwinther): Perform this check in
393 // [Compiler.onLibrariesLoaded].
394 compiler.enqueuer.resolution.addDeferredAction(element, () {
395 annotation.ensureResolved(compiler);
396 if (annotation.value != compiler.patchConstant) {
397 compiler.internalError(annotation, 'Invalid patch annotation.');
398 }
399 });
400 return true;
401 }
402 }
403 return false;
404 } 506 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698