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

Side by Side Diff: lib/compiler/implementation/patch_parser.dart

Issue 10905305: Patch refactoring. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Replaced includeInjectedMembers by implementation Created 8 years, 2 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 * TODO(johnniwinther): The terminology and invariants described below will not
7 * hold until CL 10905305 has been committed.
8 *
9 * This library contains the infrastructure to parse and integrate patch files. 6 * This library contains the infrastructure to parse and integrate patch files.
10 * 7 *
11 * Three types of elements can be patched: [LibraryElement], [ClassElement], 8 * Three types of elements can be patched: [LibraryElement], [ClassElement],
12 * [FunctionElement]. Patches are introduced in patch libraries which are loaded 9 * [FunctionElement]. Patches are introduced in patch libraries which are loaded
13 * together with the corresponding origin library. Which libraries that are 10 * together with the corresponding origin library. Which libraries that are
14 * patched is determined by the [dart2jsPatchPath] field of [LibraryInfo] found 11 * patched is determined by the [dart2jsPatchPath] field of [LibraryInfo] found
15 * in [:lib/_internal/libraries.dart:]. 12 * in [:lib/_internal/libraries.dart:].
16 * 13 *
17 * Patch libraries are parsed like regular library and thus provided with their 14 * Patch libraries are parsed like regular library and thus provided with their
18 * own elements. These elements which are distinct from the elements from the 15 * own elements. These elements which are distinct from the elements from the
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 * class RegularClass { // A regular class. 51 * class RegularClass { // A regular class.
55 * void regularMethod() {} // A regular method. 52 * void regularMethod() {} // A regular method.
56 * } 53 * }
57 * class PatchedClass { // An origin class. 54 * class PatchedClass { // An origin class.
58 * int regularField; // A regular field. 55 * int regularField; // A regular field.
59 * void regularMethod() {} // A regular method. 56 * void regularMethod() {} // A regular method.
60 * external void patchedMethod(); // An origin method. 57 * external void patchedMethod(); // An origin method.
61 * } 58 * }
62 * 59 *
63 * // In the patch library: 60 * // In the patch library:
64 * class _GhostClass { // A ghost class. 61 * class _InjectedClass { // An injected class.
65 * void _ghostMethod() {} // A ghost method. 62 * void _injectedMethod() {} // An injected method.
66 * } 63 * }
67 * patch class PatchedClass { // A patch class. 64 * patch class PatchedClass { // A patch class.
68 * int _ghostField; { // A ghost field. 65 * int _injectedField; { // An injected field.
69 * patch void patchedMethod() {} // A patch method. 66 * patch void patchedMethod() {} // A patch method.
70 * } 67 * }
71 * 68 *
72 * 69 *
73 * ## Declaration and Implementation ## 70 * ## Declaration and Implementation ##
74 * 71 *
75 * With patches we have two views on elements: as the 'declaration' which 72 * With patches we have two views on elements: as the 'declaration' which
76 * introduces the entity and defines its interface, and as the 'implementation' 73 * introduces the entity and defines its interface, and as the 'implementation'
77 * which defines the actual implementation of the entity. 74 * which defines the actual implementation of the entity.
78 * 75 *
79 * Every element has a 'declaration' and an 'implementation' element. For 76 * Every element has a 'declaration' and an 'implementation' element. For
80 * regular and ghost elements these are the same. For origin elements the 77 * regular and injected elements these are the same. For origin elements the
81 * declaration is the element itself and the implementation is the patch element 78 * declaration is the element itself and the implementation is the patch element
82 * found through its [:patch:] field. For patch elements the implementation is 79 * found through its [:patch:] field. For patch elements the implementation is
83 * the element itself and the declaration is the origin element found through 80 * the element itself and the declaration is the origin element found through
84 * its [:origin:] field. The declaration and implementation of any element is 81 * its [:origin:] field. The declaration and implementation of any element is
85 * conveniently available through the [Element.declaration] and 82 * conveniently available through the [Element.declaration] and
86 * [Element.implementation] getters. 83 * [Element.implementation] getters.
87 * 84 *
88 * Most patch-related invariants enforced through-out the compiler are defined 85 * Most patch-related invariants enforced through-out the compiler are defined
89 * in terms of 'declaration' and 'implementation', and tested through the 86 * in terms of 'declaration' and 'implementation', and tested through the
90 * predicate getters [Element.isDeclaration] and [Element.isImplementation]. 87 * predicate getters [Element.isDeclaration] and [Element.isImplementation].
91 * Patch invariants are stated both in comments and as assertions. 88 * Patch invariants are stated both in comments and as assertions.
92 * 89 *
93 * 90 *
94 * ## General invariant guidelines ## 91 * ## General invariant guidelines ##
95 * 92 *
96 * For [LibraryElement] we always use declarations. This means the 93 * For [LibraryElement] we always use declarations. This means the
97 * [Element.getLibrary] method will only return library declarations. Patch 94 * [Element.getLibrary] method will only return library declarations. Patch
98 * library implementations are only accessed through calls to 95 * library implementations are only accessed through calls to
99 * [Element.getImplementationLibrary] which is used to setup the correct 96 * [Element.getImplementationLibrary] which is used to setup the correct
100 * [Element.enclosingElement] relation between patch/ghost elements and the 97 * [Element.enclosingElement] relation between patch/injected elements and the
101 * patch library. 98 * patch library.
102 * 99 *
103 * For [ClassElement] and [FunctionElement] we use declarations for determining 100 * For [ClassElement] and [FunctionElement] we use declarations for determining
104 * identity and implementations for work based on the AST nodes, such as 101 * identity and implementations for work based on the AST nodes, such as
105 * resolution, type-checking, type inference, building SSA graphs, etc. 102 * resolution, type-checking, type inference, building SSA graphs, etc.
106 * - Worklist only contain declaration elements. 103 * - Worklist only contain declaration elements.
107 * - Most maps and sets use declarations exclusively, and their individual 104 * - Most maps and sets use declarations exclusively, and their individual
108 * invariants are stated in the field comments. 105 * invariants are stated in the field comments.
109 * - [TreeElements] only map to patch elements from inside a patch library. 106 * - [TreeElements] only map to patch elements from inside a patch library.
107 * TODO(johnniwinther): Simplify this invariant to use only declarations in
108 * [TreeElements].
110 * - Builders shift between declaration and implementation depending on usages. 109 * - Builders shift between declaration and implementation depending on usages.
111 * - Compile-time constants use constructor implementation exclusively. 110 * - Compile-time constants use constructor implementation exclusively.
112 * - Work on function parameters is performed on the declaration of the function 111 * - Work on function parameters is performed on the declaration of the function
113 * element. 112 * element.
114 */ 113 */
115 #library("patchparser"); 114 #library("patchparser");
116 115
117 #import("dart:uri"); 116 #import("dart:uri");
118 #import("tree/tree.dart", prefix: "tree"); 117 #import("tree/tree.dart", prefix: "tree");
119 #import("leg.dart", prefix: 'leg'); // CompilerTask, Compiler. 118 #import("leg.dart", prefix: 'leg'); // CompilerTask, Compiler.
120 #import("apiimpl.dart"); 119 #import("apiimpl.dart");
121 #import("scanner/scannerlib.dart"); // Scanner, Parsers, Listeners 120 #import("scanner/scannerlib.dart"); // Scanner, Parsers, Listeners
122 #import("elements/elements.dart"); 121 #import("elements/elements.dart");
123 #import('util/util.dart'); 122 #import('util/util.dart');
124 123
125 class PatchParserTask extends leg.CompilerTask { 124 class PatchParserTask extends leg.CompilerTask {
126 PatchParserTask(leg.Compiler compiler): super(compiler); 125 PatchParserTask(leg.Compiler compiler): super(compiler);
127 final String name = "Patching Parser"; 126 final String name = "Patching Parser";
128 127
129 /** 128 /**
130 * Scans a library patch file, applies the method patches and 129 * Scans a library patch file, applies the method patches and
131 * injections to the library, and returns a list of class 130 * injections to the library, and returns a list of class
132 * patches. 131 * patches.
133 */ 132 */
134 void patchLibrary(Uri patchUri, LibraryElement library) { 133 void patchLibrary(Uri patchUri, LibraryElement originLibrary) {
135 leg.Script script = compiler.readScript(patchUri, null); 134 leg.Script script = compiler.readScript(patchUri, null);
136 CompilationUnitElement compilationUnit = 135 var patchLibrary = new LibraryElement(script, patchUri, originLibrary);
137 new CompilationUnitElement(script, library); 136
138 library.addCompilationUnit(compilationUnit);
139 LinkBuilder<tree.LibraryTag> imports = new LinkBuilder<tree.LibraryTag>(); 137 LinkBuilder<tree.LibraryTag> imports = new LinkBuilder<tree.LibraryTag>();
140 compiler.withCurrentElement(compilationUnit, () { 138 compiler.withCurrentElement(patchLibrary.entryCompilationUnit, () {
141 // This patches the elements of the patch library into [library]. 139 // This patches the elements of the patch library into [library].
142 // Injected elements are added directly under the compilation unit. 140 // Injected elements are added directly under the compilation unit.
143 // Patch elements are stored on the patched functions or classes. 141 // Patch elements are stored on the patched functions or classes.
144 scanLibraryElements(compilationUnit, imports); 142 scanLibraryElements(patchLibrary.entryCompilationUnit, imports);
145 }); 143 });
146 // After scanning declarations, we handle the import tags in the patch. 144 // After scanning declarations, we handle the import tags in the patch.
147 // TODO(lrn): These imports end up in the original library and are in 145 // TODO(lrn): These imports end up in the original library and are in
148 // scope for the original methods too. This should be fixed. 146 // scope for the original methods too. This should be fixed.
149 for (tree.LibraryTag tag in imports.toLink()) { 147 for (tree.LibraryTag tag in imports.toLink()) {
150 compiler.scanner.importLibraryFromTag(tag, compilationUnit); 148 compiler.scanner.importLibraryFromTag(tag,
149 patchLibrary.entryCompilationUnit);
151 } 150 }
152 } 151 }
153 152
154 void scanLibraryElements( 153 void scanLibraryElements(
155 CompilationUnitElement compilationUnit, 154 CompilationUnitElement compilationUnit,
156 LinkBuilder<tree.LibraryTag> imports) { 155 LinkBuilder<tree.LibraryTag> imports) {
157 measure(() { 156 measure(() {
158 // TODO(lrn): Possibly recursively handle #source directives in patch. 157 // TODO(lrn): Possibly recursively handle #source directives in patch.
159 leg.Script script = compilationUnit.script; 158 leg.Script script = compilationUnit.script;
160 Token tokens = new StringScanner(script.text).tokenize(); 159 Token tokens = new StringScanner(script.text).tokenize();
161 Function idGenerator = compiler.getNextFreeClassId; 160 Function idGenerator = compiler.getNextFreeClassId;
162 PatchListener patchListener = 161 PatchListener patchListener =
163 new PatchElementListener(compiler, 162 new PatchElementListener(compiler,
164 compilationUnit, 163 compilationUnit,
165 idGenerator, 164 idGenerator,
166 imports); 165 imports);
167 new PatchParser(patchListener).parseUnit(tokens); 166 new PatchParser(patchListener).parseUnit(tokens);
168 }); 167 });
169 } 168 }
170 169
171 tree.ClassNode parsePatchClassNode(PartialClassElement element) { 170 tree.ClassNode parsePatchClassNode(PartialClassElement element) {
171 // Parse [PartialClassElement] using a "patch"-aware parser instead
172 // of calling its [parseNode] method.
173 if (element.cachedNode != null) return element.cachedNode;
174
172 return measure(() => compiler.withCurrentElement(element, () { 175 return measure(() => compiler.withCurrentElement(element, () {
173 // Parse [PartialClassElement] using a "patch"-aware parser instead 176 PatchMemberListener listener = new PatchMemberListener(compiler, element);
174 // of calling its [parseNode] method.
175 if (element.cachedNode != null) return element.cachedNode;
176 PatchMemberListener listener =
177 new PatchMemberListener(compiler, element);
178 Parser parser = new PatchClassElementParser(listener); 177 Parser parser = new PatchClassElementParser(listener);
179 Token token = parser.parseTopLevelDeclaration(element.beginToken); 178 Token token = parser.parseTopLevelDeclaration(element.beginToken);
180 assert(token === element.endToken.next); 179 assert(token === element.endToken.next);
181 element.cachedNode = listener.popNode(); 180 element.cachedNode = listener.popNode();
182 assert(listener.nodes.isEmpty()); 181 assert(listener.nodes.isEmpty());
183 return element.cachedNode; 182 return element.cachedNode;
184 })); 183 }));
185 } 184 }
186 } 185 }
187 186
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
308 307
309 void addLibraryTag(tree.LibraryTag tag) { 308 void addLibraryTag(tree.LibraryTag tag) {
310 super.addLibraryTag(tag); 309 super.addLibraryTag(tag);
311 imports.addLast(tag); 310 imports.addLast(tag);
312 } 311 }
313 312
314 void pushElement(Element element) { 313 void pushElement(Element element) {
315 if (isMemberPatch || (isClassPatch && element is ClassElement)) { 314 if (isMemberPatch || (isClassPatch && element is ClassElement)) {
316 // Apply patch. 315 // Apply patch.
317 element.addMetadata(popMetadata()); 316 element.addMetadata(popMetadata());
318 LibraryElement library = compilationUnitElement.getLibrary(); 317 LibraryElement originLibrary = compilationUnitElement.getLibrary();
319 Element existing = library.localLookup(element.name); 318 assert(originLibrary.isPatched);
319 Element existing = originLibrary.localLookup(element.name);
320 if (isMemberPatch) { 320 if (isMemberPatch) {
321 if (element is! FunctionElement) { 321 if (element is! FunctionElement) {
322 listener.internalErrorOnElement(element, 322 listener.internalErrorOnElement(element,
323 "Member patch is not a function."); 323 "Member patch is not a function.");
324 } 324 }
325 if (existing.kind === ElementKind.ABSTRACT_FIELD) { 325 if (existing.kind === ElementKind.ABSTRACT_FIELD) {
326 if (!element.isAccessor()) { 326 if (!element.isAccessor()) {
327 listener.internalErrorOnElement( 327 listener.internalErrorOnElement(
328 element, "Patching non-accessor with accessor"); 328 element, "Patching non-accessor with accessor");
329 } 329 }
330 AbstractFieldElement field = existing; 330 AbstractFieldElement field = existing;
331 if (element.isGetter()) { 331 if (element.isGetter()) {
332 existing = field.getter; 332 existing = field.getter;
333 } else { 333 } else {
334 existing = field.setter; 334 existing = field.setter;
335 } 335 }
336 } 336 }
337 if (existing is! FunctionElement) { 337 if (existing is! FunctionElement) {
338 listener.internalErrorOnElement(element, 338 listener.internalErrorOnElement(element,
339 "No corresponding method for patch."); 339 "No corresponding method for patch.");
340 } 340 }
341 FunctionElement function = existing; 341 FunctionElement function = existing;
342 if (function.isPatched) { 342 if (function.isPatched) {
343 listener.internalErrorOnElement( 343 listener.internalErrorOnElement(
344 element, "Patching the same function more than once."); 344 element, "Patching the same function more than once.");
345 } 345 }
346 function.patch = element; 346 function.patch = element;
347 element.origin = function;
347 } else { 348 } else {
348 if (existing is! ClassElement) { 349 if (existing is! ClassElement) {
349 listener.internalErrorOnElement( 350 listener.internalErrorOnElement(
350 element, "Patching a non-class with a class patch."); 351 element, "Patching a non-class with a class patch.");
351 } 352 }
352 ClassElement classElement = existing; 353 ClassElement classElement = existing;
353 if (classElement.isPatched) { 354 if (classElement.isPatched) {
354 listener.internalErrorOnElement( 355 listener.internalErrorOnElement(
355 element, "Patching the same class more than once."); 356 element, "Patching the same class more than once.");
356 } 357 }
357 classElement.patch = element; 358 classElement.patch = element;
359 element.origin = classElement;
358 } 360 }
359 return;
360 } 361 }
361 super.pushElement(element); 362 super.pushElement(element);
362 } 363 }
363 } 364 }
364 365
365 /** 366 /**
366 * Extension of [MemberListener] for parsing patch class bodies. 367 * Extension of [MemberListener] for parsing patch class bodies.
367 */ 368 */
368 class PatchMemberListener extends MemberListener implements PatchListener { 369 class PatchMemberListener extends MemberListener implements PatchListener {
369 bool isMemberPatch = false; 370 bool isMemberPatch = false;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
402 super.addMember(element); 403 super.addMember(element);
403 } 404 }
404 } 405 }
405 406
406 // TODO(ahe): Get rid of this class. 407 // TODO(ahe): Get rid of this class.
407 class PatchMetadataAnnotation extends MetadataAnnotation { 408 class PatchMetadataAnnotation extends MetadataAnnotation {
408 final leg.Constant value = null; 409 final leg.Constant value = null;
409 410
410 PatchMetadataAnnotation() : super(STATE_DONE); 411 PatchMetadataAnnotation() : super(STATE_DONE);
411 } 412 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698