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

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: Rebased. 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);
138 LinkBuilder<tree.LibraryTag> imports = new LinkBuilder<tree.LibraryTag>(); 136 LinkBuilder<tree.LibraryTag> imports = new LinkBuilder<tree.LibraryTag>();
139 compiler.withCurrentElement(compilationUnit, () { 137 compiler.withCurrentElement(patchLibrary.entryCompilationUnit, () {
140 // This patches the elements of the patch library into [library]. 138 // This patches the elements of the patch library into [library].
141 // Injected elements are added directly under the compilation unit. 139 // Injected elements are added directly under the compilation unit.
142 // Patch elements are stored on the patched functions or classes. 140 // Patch elements are stored on the patched functions or classes.
143 scanLibraryElements(compilationUnit, imports); 141 scanLibraryElements(patchLibrary.entryCompilationUnit, imports);
144 }); 142 });
145 // After scanning declarations, we handle the import tags in the patch. 143 // After scanning declarations, we handle the import tags in the patch.
146 // TODO(lrn): These imports end up in the original library and are in 144 // TODO(lrn): These imports end up in the original library and are in
147 // scope for the original methods too. This should be fixed. 145 // scope for the original methods too. This should be fixed.
148 for (tree.LibraryTag tag in imports.toLink()) { 146 for (tree.LibraryTag tag in imports.toLink()) {
149 compiler.scanner.importLibraryFromTag(tag, compilationUnit); 147 compiler.scanner.importLibraryFromTag(tag,
148 patchLibrary.entryCompilationUnit);
150 } 149 }
151 } 150 }
152 151
153 void scanLibraryElements( 152 void scanLibraryElements(
154 CompilationUnitElement compilationUnit, 153 CompilationUnitElement compilationUnit,
155 LinkBuilder<tree.LibraryTag> imports) { 154 LinkBuilder<tree.LibraryTag> imports) {
156 measure(() { 155 measure(() {
157 // TODO(lrn): Possibly recursively handle #source directives in patch. 156 // TODO(lrn): Possibly recursively handle #source directives in patch.
158 leg.Script script = compilationUnit.script; 157 leg.Script script = compilationUnit.script;
159 Token tokens = new StringScanner(script.text).tokenize(); 158 Token tokens = new StringScanner(script.text).tokenize();
160 Function idGenerator = compiler.getNextFreeClassId; 159 Function idGenerator = compiler.getNextFreeClassId;
161 PatchListener patchListener = 160 PatchListener patchListener =
162 new PatchElementListener(compiler, 161 new PatchElementListener(compiler,
163 compilationUnit, 162 compilationUnit,
164 idGenerator, 163 idGenerator,
165 imports); 164 imports);
166 new PatchParser(patchListener).parseUnit(tokens); 165 new PatchParser(patchListener).parseUnit(tokens);
167 }); 166 });
168 } 167 }
169 168
170 tree.ClassNode parsePatchClassNode(PartialClassElement element) { 169 tree.ClassNode parsePatchClassNode(PartialClassElement element) {
170 // Parse [PartialClassElement] using a "patch"-aware parser instead
171 // of calling its [parseNode] method.
172 if (element.cachedNode != null) return element.cachedNode;
173
171 return measure(() => compiler.withCurrentElement(element, () { 174 return measure(() => compiler.withCurrentElement(element, () {
172 // Parse [PartialClassElement] using a "patch"-aware parser instead 175 PatchMemberListener listener = new PatchMemberListener(compiler, element);
173 // of calling its [parseNode] method.
174 if (element.cachedNode != null) return element.cachedNode;
175 PatchMemberListener listener =
176 new PatchMemberListener(compiler, element);
177 Parser parser = new PatchClassElementParser(listener); 176 Parser parser = new PatchClassElementParser(listener);
178 Token token = parser.parseTopLevelDeclaration(element.beginToken); 177 Token token = parser.parseTopLevelDeclaration(element.beginToken);
179 assert(token === element.endToken.next); 178 assert(token === element.endToken.next);
180 element.cachedNode = listener.popNode(); 179 element.cachedNode = listener.popNode();
181 assert(listener.nodes.isEmpty()); 180 assert(listener.nodes.isEmpty());
182 return element.cachedNode; 181 return element.cachedNode;
183 })); 182 }));
184 } 183 }
185 } 184 }
186 185
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 306
308 void addLibraryTag(tree.LibraryTag tag) { 307 void addLibraryTag(tree.LibraryTag tag) {
309 super.addLibraryTag(tag); 308 super.addLibraryTag(tag);
310 imports.addLast(tag); 309 imports.addLast(tag);
311 } 310 }
312 311
313 void pushElement(Element element) { 312 void pushElement(Element element) {
314 if (isMemberPatch || (isClassPatch && element is ClassElement)) { 313 if (isMemberPatch || (isClassPatch && element is ClassElement)) {
315 // Apply patch. 314 // Apply patch.
316 element.addMetadata(popMetadata()); 315 element.addMetadata(popMetadata());
317 LibraryElement library = compilationUnitElement.getLibrary(); 316 LibraryElement originLibrary = compilationUnitElement.getLibrary();
318 Element existing = library.localLookup(element.name); 317 assert(originLibrary.isPatched);
318 Element existing = originLibrary.localLookup(element.name);
319 if (isMemberPatch) { 319 if (isMemberPatch) {
320 if (element is! FunctionElement) { 320 if (element is! FunctionElement) {
321 listener.internalErrorOnElement(element, 321 listener.internalErrorOnElement(element,
322 "Member patch is not a function."); 322 "Member patch is not a function.");
323 } 323 }
324 if (existing.kind === ElementKind.ABSTRACT_FIELD) { 324 if (existing.kind === ElementKind.ABSTRACT_FIELD) {
325 if (!element.isAccessor()) { 325 if (!element.isAccessor()) {
326 listener.internalErrorOnElement( 326 listener.internalErrorOnElement(
327 element, "Patching non-accessor with accessor"); 327 element, "Patching non-accessor with accessor");
328 } 328 }
329 AbstractFieldElement field = existing; 329 AbstractFieldElement field = existing;
330 if (element.isGetter()) { 330 if (element.isGetter()) {
331 existing = field.getter; 331 existing = field.getter;
332 } else { 332 } else {
333 existing = field.setter; 333 existing = field.setter;
334 } 334 }
335 } 335 }
336 if (existing is! FunctionElement) { 336 if (existing is! FunctionElement) {
337 listener.internalErrorOnElement(element, 337 listener.internalErrorOnElement(element,
338 "No corresponding method for patch."); 338 "No corresponding method for patch.");
339 } 339 }
340 FunctionElement function = existing; 340 FunctionElement function = existing;
341 if (function.isPatched) { 341 if (function.isPatched) {
342 listener.internalErrorOnElement( 342 listener.internalErrorOnElement(
343 element, "Patching the same function more than once."); 343 element, "Patching the same function more than once.");
344 } 344 }
345 function.patch = element; 345 function.patch = element;
346 element.origin = function;
346 } else { 347 } else {
347 if (existing is! ClassElement) { 348 if (existing is! ClassElement) {
348 listener.internalErrorOnElement( 349 listener.internalErrorOnElement(
349 element, "Patching a non-class with a class patch."); 350 element, "Patching a non-class with a class patch.");
350 } 351 }
351 ClassElement classElement = existing; 352 ClassElement classElement = existing;
352 if (classElement.isPatched) { 353 if (classElement.isPatched) {
353 listener.internalErrorOnElement( 354 listener.internalErrorOnElement(
354 element, "Patching the same class more than once."); 355 element, "Patching the same class more than once.");
355 } 356 }
356 classElement.patch = element; 357 classElement.patch = element;
358 element.origin = classElement;
357 } 359 }
358 return;
359 } 360 }
360 super.pushElement(element); 361 super.pushElement(element);
361 } 362 }
362 } 363 }
363 364
364 /** 365 /**
365 * Extension of [MemberListener] for parsing patch class bodies. 366 * Extension of [MemberListener] for parsing patch class bodies.
366 */ 367 */
367 class PatchMemberListener extends MemberListener implements PatchListener { 368 class PatchMemberListener extends MemberListener implements PatchListener {
368 bool isMemberPatch = false; 369 bool isMemberPatch = false;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
401 super.addMember(element); 402 super.addMember(element);
402 } 403 }
403 } 404 }
404 405
405 // TODO(ahe): Get rid of this class. 406 // TODO(ahe): Get rid of this class.
406 class PatchMetadataAnnotation extends MetadataAnnotation { 407 class PatchMetadataAnnotation extends MetadataAnnotation {
407 final leg.Constant value = null; 408 final leg.Constant value = null;
408 409
409 PatchMetadataAnnotation() : super(STATE_DONE); 410 PatchMetadataAnnotation() : super(STATE_DONE);
410 } 411 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698