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); | |
Siggi Cherem (dart-lang)
2013/02/13 01:43:24
nit: make it a property?
Jennifer Messerly
2013/02/13 05:43:15
It could be repeated O(N)'s if used that way. Tryi
Siggi Cherem (dart-lang)
2013/02/13 19:28:54
Shouldn't good inlining take care of that in this
Jennifer Messerly
2013/02/13 20:21:20
No. I think you mean inlining plus common subexpre
| |
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; | |
Siggi Cherem (dart-lang)
2013/02/13 01:43:24
if you haven't, it might be nice to give them feed
Jennifer Messerly
2013/02/13 05:43:15
Already done. I think it's already fixed, but not
| |
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; | |
Siggi Cherem (dart-lang)
2013/02/13 01:43:24
ohh weird - bad code generation =)...
Jennifer Messerly
2013/02/13 05:43:15
hehe, yeah. I think Konstantin is looking into it
| |
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 |