| OLD | NEW |
| 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 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 135 import 'library_loader.dart' show LibraryLoader; | 135 import 'library_loader.dart' show LibraryLoader; |
| 136 import 'options.dart' show ParserOptions; | 136 import 'options.dart' show ParserOptions; |
| 137 import 'parser/listener.dart' show Listener, ParserError; | 137 import 'parser/listener.dart' show Listener, ParserError; |
| 138 import 'parser/element_listener.dart' show ElementListener; | 138 import 'parser/element_listener.dart' show ElementListener; |
| 139 import 'parser/member_listener.dart' show MemberListener; | 139 import 'parser/member_listener.dart' show MemberListener; |
| 140 import 'parser/partial_elements.dart' show PartialClassElement; | 140 import 'parser/partial_elements.dart' show PartialClassElement; |
| 141 import 'parser/partial_parser.dart' show PartialParser; | 141 import 'parser/partial_parser.dart' show PartialParser; |
| 142 import 'parser/parser.dart' show Parser; | 142 import 'parser/parser.dart' show Parser; |
| 143 import 'scanner/scanner.dart' show Scanner; | 143 import 'scanner/scanner.dart' show Scanner; |
| 144 import 'script.dart'; | 144 import 'script.dart'; |
| 145 import 'tokens/token.dart' show StringToken, Token; | 145 import 'tokens/token.dart' show SymbolToken, StringToken, Token; |
| 146 |
| 147 import 'tokens/token_constants.dart' show EOF_TOKEN; |
| 148 |
| 149 import 'tokens/precedence_constants.dart' show AT_INFO; |
| 150 |
| 151 class PartialPatchParser extends PartialParser { |
| 152 PartialPatchParser(Listener listener, ParserOptions options) |
| 153 : super(listener, options); |
| 154 |
| 155 Token parseMetadataStar(Token token, {bool forParameter: false}) { |
| 156 listener.beginMetadataStar(token); |
| 157 int count = 0; |
| 158 while (token.kind != EOF_TOKEN) { |
| 159 if (optional('@', token)) { |
| 160 token = parseMetadata(token); |
| 161 count++; |
| 162 } else if (optional('patch', token)) { |
| 163 token = parsePatchKeyword(token); |
| 164 } else { |
| 165 break; |
| 166 } |
| 167 } |
| 168 listener.endMetadataStar(count, forParameter); |
| 169 return token; |
| 170 } |
| 171 |
| 172 Token parsePatchKeyword(Token token) { |
| 173 listener.beginMetadata(token); |
| 174 Token start = new SymbolToken(AT_INFO, token.charOffset)..next = token; |
| 175 assert(optional('patch', token)); |
| 176 token = parseIdentifier(token); |
| 177 token = parseQualifiedRestOpt(token); |
| 178 token = parseTypeArgumentsOpt(token); |
| 179 Token period = null; |
| 180 if (optional('.', token)) { |
| 181 period = token; |
| 182 token = parseIdentifier(token.next); |
| 183 } |
| 184 token = parseArgumentsOpt(token); |
| 185 listener.endMetadata(start, period, token); |
| 186 return token; |
| 187 } |
| 188 } |
| 146 | 189 |
| 147 class PatchParserTask extends CompilerTask { | 190 class PatchParserTask extends CompilerTask { |
| 148 final String name = "Patching Parser"; | 191 final String name = "Patching Parser"; |
| 149 final ParserOptions parserOptions; | 192 final ParserOptions parserOptions; |
| 150 | 193 |
| 151 PatchParserTask(Compiler compiler, this.parserOptions) : super(compiler); | 194 PatchParserTask(Compiler compiler, this.parserOptions) : super(compiler); |
| 152 | 195 |
| 153 /** | 196 /** |
| 154 * Scans a library patch file, applies the method patches and | 197 * Scans a library patch file, applies the method patches and |
| 155 * injections to the library, and returns a list of class | 198 * injections to the library, and returns a list of class |
| 156 * patches. | 199 * patches. |
| 157 */ | 200 */ |
| 158 Future patchLibrary( | 201 Future patchLibrary( |
| 159 LibraryLoader loader, Uri patchUri, LibraryElement originLibrary) { | 202 LibraryLoader loader, Uri patchUri, LibraryElement originLibrary) { |
| 160 return compiler.readScript(patchUri, originLibrary).then((Script script) { | 203 return compiler.readScript(patchUri, originLibrary).then((Script script) { |
| 161 var patchLibrary = new LibraryElementX(script, null, originLibrary); | 204 var patchLibrary = new LibraryElementX(script, null, originLibrary); |
| 162 return reporter.withCurrentElement(patchLibrary, () { | 205 return reporter.withCurrentElement(patchLibrary, () { |
| 163 loader.registerNewLibrary(patchLibrary); | 206 loader.registerNewLibrary(patchLibrary); |
| 164 reporter.withCurrentElement(patchLibrary.entryCompilationUnit, () { | 207 reporter.withCurrentElement(patchLibrary.entryCompilationUnit, () { |
| 165 // This patches the elements of the patch library into [library]. | 208 // This patches the elements of the patch library into [library]. |
| 166 // Injected elements are added directly under the compilation unit. | 209 // Injected elements are added directly under the compilation unit. |
| 167 // Patch elements are stored on the patched functions or classes. | 210 // Patch elements are stored on the patched functions or classes. |
| 168 scanLibraryElements(patchLibrary.entryCompilationUnit); | 211 scanLibraryElements(patchLibrary.entryCompilationUnit); |
| 169 }); | 212 }); |
| 170 return loader.processLibraryTags(patchLibrary); | 213 return loader.processLibraryTags(patchLibrary, isPatchLibrary: true); |
| 171 }); | 214 }); |
| 172 }); | 215 }); |
| 173 } | 216 } |
| 174 | 217 |
| 175 void scanLibraryElements(CompilationUnitElement compilationUnit) { | 218 void scanLibraryElements(CompilationUnitElement compilationUnit) { |
| 176 measure(() { | 219 measure(() { |
| 177 // TODO(johnniwinther): Test that parts and exports are handled correctly. | 220 // TODO(johnniwinther): Test that parts and exports are handled correctly. |
| 178 Script script = compilationUnit.script; | 221 Script script = compilationUnit.script; |
| 179 Token tokens = new Scanner(script.file).tokenize(); | 222 Token tokens = new Scanner(script.file).tokenize(); |
| 180 Listener patchListener = | 223 Listener patchListener = |
| 181 new PatchElementListener(compiler, compilationUnit, compiler); | 224 new PatchElementListener(compiler, compilationUnit, compiler); |
| 182 try { | 225 try { |
| 183 new PartialParser(patchListener, parserOptions).parseUnit(tokens); | 226 new PartialPatchParser(patchListener, parserOptions).parseUnit(tokens); |
| 184 } on ParserError catch (e) { | 227 } on ParserError catch (e) { |
| 185 // No need to recover from a parser error in platform libraries, user | 228 // No need to recover from a parser error in platform libraries, user |
| 186 // will never see this if the libraries are tested correctly. | 229 // will never see this if the libraries are tested correctly. |
| 187 reporter.internalError( | 230 reporter.internalError( |
| 188 compilationUnit, "Parser error in patch file: $e"); | 231 compilationUnit, "Parser error in patch file: $e"); |
| 189 } | 232 } |
| 190 }); | 233 }); |
| 191 } | 234 } |
| 192 | 235 |
| 193 void parsePatchClassNode(PartialClassElement cls) { | 236 void parsePatchClassNode(PartialClassElement cls) { |
| 194 // Parse [PartialClassElement] using a "patch"-aware parser instead | 237 // Parse [PartialClassElement] using a "patch"-aware parser instead |
| 195 // of calling its [parseNode] method. | 238 // of calling its [parseNode] method. |
| 196 if (cls.cachedNode != null) return; | 239 if (cls.cachedNode != null) return; |
| 197 | 240 |
| 198 measure(() => reporter.withCurrentElement(cls, () { | 241 measure(() => reporter.withCurrentElement(cls, () { |
| 199 MemberListener listener = new PatchMemberListener(compiler, cls); | 242 MemberListener listener = new PatchMemberListener(compiler, cls); |
| 200 Parser parser = new PatchClassElementParser(listener, parserOptions); | 243 Parser parser = new PatchClassElementParser(listener, parserOptions); |
| 201 try { | 244 try { |
| 202 Token token = parser.parseTopLevelDeclaration(cls.beginToken); | 245 Token token = parser.parseTopLevelDeclaration(cls.beginToken); |
| 203 assert(identical(token, cls.endToken.next)); | 246 assert(identical(token, cls.endToken.next)); |
| 204 } on ParserError catch (e) { | 247 } on ParserError catch (e) { |
| 205 // No need to recover from a parser error in platform libraries, use
r | 248 // No need to recover from a parser error in platform libraries, use
r |
| 206 // will never see this if the libraries are tested correctly. | 249 // will never see this if the libraries are tested correctly. |
| 207 reporter.internalError(cls, "Parser error in patch file: $e"); | 250 reporter.internalError(cls, "Parser error in patch file: $e"); |
| 208 } | 251 } |
| 209 cls.cachedNode = listener.popNode(); | 252 cls.cachedNode = listener.popNode(); |
| 210 assert(listener.nodes.isEmpty); | 253 assert(listener.nodes.isEmpty); |
| 211 })); | 254 })); |
| 212 } | 255 } |
| 256 |
| 257 void scanUnit(CompilationUnitElement unit, {bool isPart: true}) { |
| 258 // TODO(ahe): Implement this. |
| 259 throw "not implemented"; |
| 260 } |
| 213 } | 261 } |
| 214 | 262 |
| 215 class PatchMemberListener extends MemberListener { | 263 class PatchMemberListener extends MemberListener { |
| 216 final Compiler compiler; | 264 final Compiler compiler; |
| 217 | 265 |
| 218 PatchMemberListener(Compiler compiler, ClassElement enclosingClass) | 266 PatchMemberListener(Compiler compiler, ClassElement enclosingClass) |
| 219 : this.compiler = compiler, | 267 : this.compiler = compiler, |
| 220 super(compiler.parsing.getScannerOptionsFor(enclosingClass), | 268 super(compiler.parsing.getScannerOptionsFor(enclosingClass), |
| 221 compiler.reporter, enclosingClass); | 269 compiler.reporter, enclosingClass); |
| 222 | 270 |
| 223 @override | 271 @override |
| 224 void addMember(Element patch) { | 272 void addMember(Element patch) { |
| 225 addMetadata(patch); | 273 addMetadata(patch); |
| 226 | 274 |
| 227 PatchVersion patchVersion = getPatchVersion(compiler, patch); | 275 PatchVersion patchVersion = getPatchVersion(compiler, patch); |
| 228 if (patchVersion != null) { | 276 if (patchVersion != null) { |
| 229 if (patchVersion.isActive(compiler.patchVersion)) { | 277 if (patchVersion.isActive(compiler.patchVersion)) { |
| 230 Element origin = enclosingClass.origin.localLookup(patch.name); | 278 Element origin = enclosingClass.origin.localLookup(patch.name); |
| 231 patchElement(compiler, reporter, origin, patch); | 279 patchElement(compiler, reporter, origin, patch); |
| 232 enclosingClass.addMember(patch, reporter); | 280 enclosingClass.addMember(patch, reporter); |
| 233 } else { | 281 } else { |
| 234 // Skip this element. | 282 // Skip this element. |
| 235 } | 283 } |
| 236 } else { | 284 } else { |
| 237 if (Name.isPublicName(patch.name)) { | 285 Element origin = enclosingClass.origin.localLookup(patch.name); |
| 286 if (origin != null) { |
| 287 patchElement(compiler, reporter, origin, patch); |
| 288 } else if (Name.isPublicName(patch.name)) { |
| 238 reporter.reportErrorMessage(patch, MessageKind.INJECTED_PUBLIC_MEMBER); | 289 reporter.reportErrorMessage(patch, MessageKind.INJECTED_PUBLIC_MEMBER); |
| 239 } | 290 } |
| 240 enclosingClass.addMember(patch, reporter); | 291 enclosingClass.addMember(patch, reporter); |
| 241 } | 292 } |
| 242 } | 293 } |
| 243 } | 294 } |
| 244 | 295 |
| 245 /** | 296 /** |
| 246 * Partial parser for patch files that also handles the members of class | 297 * Partial parser for patch files that also handles the members of class |
| 247 * declarations. | 298 * declarations. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 274 if (patchVersion.isActive(compiler.patchVersion)) { | 325 if (patchVersion.isActive(compiler.patchVersion)) { |
| 275 LibraryElement originLibrary = compilationUnitElement.library; | 326 LibraryElement originLibrary = compilationUnitElement.library; |
| 276 assert(originLibrary.isPatched); | 327 assert(originLibrary.isPatched); |
| 277 Element origin = originLibrary.localLookup(patch.name); | 328 Element origin = originLibrary.localLookup(patch.name); |
| 278 patchElement(compiler, reporter, origin, patch); | 329 patchElement(compiler, reporter, origin, patch); |
| 279 compilationUnitElement.addMember(patch, reporter); | 330 compilationUnitElement.addMember(patch, reporter); |
| 280 } else { | 331 } else { |
| 281 // Skip this element. | 332 // Skip this element. |
| 282 } | 333 } |
| 283 } else { | 334 } else { |
| 284 if (Name.isPublicName(patch.name)) { | 335 LibraryElement originLibrary = compilationUnitElement.library; |
| 336 Element origin = originLibrary.localLookup(patch.name); |
| 337 if (origin != null) { |
| 338 patchElement(compiler, reporter, origin, patch); |
| 339 } else if (Name.isPublicName(patch.name)) { |
| 285 reporter.reportErrorMessage(patch, MessageKind.INJECTED_PUBLIC_MEMBER); | 340 reporter.reportErrorMessage(patch, MessageKind.INJECTED_PUBLIC_MEMBER); |
| 286 } | 341 } |
| 287 compilationUnitElement.addMember(patch, reporter); | 342 compilationUnitElement.addMember(patch, reporter); |
| 288 } | 343 } |
| 289 } | 344 } |
| 290 } | 345 } |
| 291 | 346 |
| 292 void patchElement(Compiler compiler, DiagnosticReporter reporter, | 347 void patchElement(Compiler compiler, DiagnosticReporter reporter, |
| 293 Element origin, Element patch) { | 348 Element origin, Element patch) { |
| 294 if (origin == null) { | 349 if (origin == null) { |
| (...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 612 | 667 |
| 613 class PatchVersion { | 668 class PatchVersion { |
| 614 final String tag; | 669 final String tag; |
| 615 | 670 |
| 616 const PatchVersion(this.tag); | 671 const PatchVersion(this.tag); |
| 617 | 672 |
| 618 bool isActive(String patchTag) => tag == null || tag == patchTag; | 673 bool isActive(String patchTag) => tag == null || tag == patchTag; |
| 619 | 674 |
| 620 String toString() => 'PatchVersion($tag)'; | 675 String toString() => 'PatchVersion($tag)'; |
| 621 } | 676 } |
| OLD | NEW |