OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 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. |
| 4 |
| 5 /** |
| 6 * Parser for Dart code based on the experimental analyzer. |
| 7 */ |
| 8 library dart_parser; |
| 9 |
| 10 import 'dart:utf'; |
| 11 import 'dart:math' as math; |
| 12 import 'package:analyzer_experimental/src/generated/ast.dart'; |
| 13 import 'package:analyzer_experimental/src/generated/error.dart'; |
| 14 import 'package:analyzer_experimental/src/generated/java_core.dart'; |
| 15 import 'package:analyzer_experimental/src/generated/parser.dart'; |
| 16 import 'package:analyzer_experimental/src/generated/scanner.dart'; |
| 17 import 'package:source_maps/span.dart' show File, FileSpan; |
| 18 import 'file_system/path.dart'; |
| 19 import 'info.dart'; |
| 20 import 'messages.dart'; |
| 21 import 'refactor.dart' show $CR, $LF; |
| 22 import 'utils.dart'; |
| 23 |
| 24 /** Information extracted from a source Dart file. */ |
| 25 class DartCodeInfo { |
| 26 // TODO(jmesserly): VM hashCode performance workaround ... |
| 27 static int _nextHash = 0; |
| 28 final int hashCode = ++_nextHash; |
| 29 |
| 30 /** Library qualified identifier, if any. */ |
| 31 final String libraryName; |
| 32 |
| 33 /** Library which the code is part-of, if any. */ |
| 34 final String partOf; |
| 35 |
| 36 /** Declared imports, exports, and parts. */ |
| 37 final List<Directive> directives; |
| 38 |
| 39 /** The parsed code. */ |
| 40 CompilationUnit _compilationUnit; |
| 41 |
| 42 /** The full source code. */ |
| 43 String _code; |
| 44 |
| 45 DartCodeInfo(this.libraryName, this.partOf, this.directives, code, |
| 46 [compilationUnit]) : _code = code, _compilationUnit = compilationUnit; |
| 47 |
| 48 String get code => _code; |
| 49 |
| 50 set code(String value) { |
| 51 // TODO(jmesserly): invalidate libraryName, partOf, and directives as well? |
| 52 // In general we should move this to querying from the CompilationUnit. |
| 53 _code = value; |
| 54 _compilationUnit = null; |
| 55 } |
| 56 |
| 57 CompilationUnit get compilationUnit { |
| 58 // If this has been invalidated, reparse the code |
| 59 if (_compilationUnit == null) _compilationUnit = parseCompilationUnit(code); |
| 60 return _compilationUnit; |
| 61 } |
| 62 |
| 63 int get directivesEnd { |
| 64 if (compilationUnit.directives.length == 0) return 0; |
| 65 return compilationUnit.directives.map((d) => d.end).max(); |
| 66 } |
| 67 |
| 68 /** Gets the code after the [directives]. */ |
| 69 String codeAfterDirectives() => code.substring(directivesEnd); |
| 70 |
| 71 ClassDeclaration findClass(String name) { |
| 72 for (var decl in compilationUnit.declarations) { |
| 73 if (decl is ClassDeclaration) { |
| 74 if (decl.name.name == name) return decl; |
| 75 } |
| 76 } |
| 77 return null; |
| 78 } |
| 79 } |
| 80 |
| 81 // TODO(jmesserly): I think Part and Import will have a common base class soon, |
| 82 // which will make this easier. |
| 83 StringLiteral getDirectiveUri(Directive directive) { |
| 84 if (directive is NamespaceDirective) { |
| 85 return (directive as NamespaceDirective).libraryUri; |
| 86 } else { |
| 87 return (directive as PartDirective).partUri; |
| 88 } |
| 89 } |
| 90 |
| 91 void setDirectiveUri(Directive directive, StringLiteral uri) { |
| 92 if (directive is NamespaceDirective) { |
| 93 (directive as NamespaceDirective).libraryUri2 = uri; |
| 94 } else { |
| 95 (directive as PartDirective).partUri2 = uri; |
| 96 } |
| 97 } |
| 98 |
| 99 SimpleStringLiteral createStringLiteral(String contents) { |
| 100 var lexeme = "'${escapeDartString(contents)}'"; |
| 101 var token = new StringToken(TokenType.STRING, lexeme, null); |
| 102 return new SimpleStringLiteral(token, contents); |
| 103 } |
| 104 |
| 105 |
| 106 /** |
| 107 * Parse and extract top-level directives from [code]. |
| 108 * |
| 109 * Adds emitted error/warning messages to [messages], if [messages] is |
| 110 * supplied. |
| 111 */ |
| 112 DartCodeInfo parseDartCode(Path path, String code, Messages messages) { |
| 113 var unit = parseCompilationUnit(code, path: path, messages: messages); |
| 114 |
| 115 // Extract some information from the compilation unit. |
| 116 String libraryName, partName; |
| 117 var directives = []; |
| 118 int directiveEnd = 0; |
| 119 for (var directive in unit.directives) { |
| 120 if (directive is LibraryDirective) { |
| 121 libraryName = directive.name.name; |
| 122 } else if (directive is PartOfDirective) { |
| 123 partName = directive.libraryName.name; |
| 124 } else { |
| 125 // Normalize the library URI. |
| 126 var uriNode = getDirectiveUri(directive); |
| 127 if (uriNode is! SimpleStringLiteral) { |
| 128 String uri = uriNode.accept(new ConstantEvaluator()); |
| 129 setDirectiveUri(directive, createStringLiteral(uri)); |
| 130 } |
| 131 directives.add(directive); |
| 132 } |
| 133 } |
| 134 |
| 135 return new DartCodeInfo(libraryName, partName, directives, code, unit); |
| 136 } |
| 137 |
| 138 CompilationUnit parseCompilationUnit(String code, {Path path, |
| 139 Messages messages}) { |
| 140 |
| 141 var errorListener = new _ErrorCollector(); |
| 142 var scanner = new StringScanner(null, code, errorListener); |
| 143 var token = scanner.tokenize(); |
| 144 var parser = new Parser(null, errorListener); |
| 145 var unit = parser.parseCompilationUnit(token); |
| 146 |
| 147 if (path == null || messages == null) return unit; |
| 148 |
| 149 // TODO(jmesserly): removed this for now because the analyzer doesn't format |
| 150 // messages properly, so you end up with things like "Unexpected token '%s'". |
| 151 // This used to convert parser messages into our messages. Enable this |
| 152 // once analyzer is fixed. |
| 153 if (false) { |
| 154 var file = new File.text(path.toString(), code); |
| 155 for (var e in errorListener.errors) { |
| 156 var span = new FileSpan(file, e.offset, e.offset + e.length); |
| 157 |
| 158 var severity = e.errorCode.errorSeverity; |
| 159 if (severity == ErrorSeverity.ERROR) { |
| 160 messages.error(e.message, span, file: path); |
| 161 } else { |
| 162 assert(severity == ErrorSeverity.WARNING); |
| 163 messages.warning(e.message, span, file: path); |
| 164 } |
| 165 } |
| 166 } |
| 167 |
| 168 return unit; |
| 169 } |
| 170 |
| 171 class _ErrorCollector extends AnalysisErrorListener { |
| 172 final errors = new List<AnalysisError>(); |
| 173 onError(error) => errors.add(error); |
| 174 } |
OLD | NEW |