Chromium Code Reviews| Index: lib/src/dart_parser.dart |
| diff --git a/lib/src/dart_parser.dart b/lib/src/dart_parser.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..01274bf1dc920c520ea4e14f6ea51d58f2ef8dcc |
| --- /dev/null |
| +++ b/lib/src/dart_parser.dart |
| @@ -0,0 +1,174 @@ |
| +// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| +// for details. All rights reserved. Use of this source code is governed by a |
| +// BSD-style license that can be found in the LICENSE file. |
| + |
| +/** |
| + * Parser for Dart code based on the experimental analyzer. |
| + */ |
| +library dart_parser; |
| + |
| +import 'dart:utf'; |
| +import 'dart:math' as math; |
| +import 'package:analyzer_experimental/src/generated/ast.dart'; |
| +import 'package:analyzer_experimental/src/generated/error.dart'; |
| +import 'package:analyzer_experimental/src/generated/java_core.dart'; |
| +import 'package:analyzer_experimental/src/generated/parser.dart'; |
| +import 'package:analyzer_experimental/src/generated/scanner.dart'; |
| +import 'package:source_maps/span.dart' show File, FileSpan; |
| +import 'file_system/path.dart'; |
| +import 'info.dart'; |
| +import 'messages.dart'; |
| +import 'refactor.dart' show $CR, $LF; |
| +import 'utils.dart'; |
| + |
| +/** Information extracted from a source Dart file. */ |
| +class DartCodeInfo { |
| + // TODO(jmesserly): VM hashCode performance workaround ... |
| + static int _nextHash = 0; |
| + final int hashCode = ++_nextHash; |
| + |
| + /** Library qualified identifier, if any. */ |
| + final String libraryName; |
| + |
| + /** Library which the code is part-of, if any. */ |
| + final String partOf; |
| + |
| + /** Declared imports, exports, and parts. */ |
| + final List<Directive> directives; |
| + |
| + /** The parsed code. */ |
| + CompilationUnit _compilationUnit; |
| + |
| + /** The full source code. */ |
| + String _code; |
| + |
| + DartCodeInfo(this.libraryName, this.partOf, this.directives, code, |
| + [compilationUnit]) : _code = code, _compilationUnit = compilationUnit; |
| + |
| + String get code => _code; |
| + |
| + set code(String value) { |
| + // TODO(jmesserly): invalidate libraryName, partOf, and directives as well? |
| + // In general we should move this to querying from the CompilationUnit. |
| + _code = value; |
| + _compilationUnit = null; |
| + } |
| + |
| + CompilationUnit get compilationUnit { |
| + // If this has been invalidated, reparse the code |
| + if (_compilationUnit == null) _compilationUnit = parseCompilationUnit(code); |
| + return _compilationUnit; |
| + } |
| + |
| + int get directivesEnd { |
| + if (compilationUnit.directives.length == 0) return 0; |
| + return compilationUnit.directives.map((d) => d.end).max(); |
| + } |
| + |
| + /** Gets the code after the [directives]. */ |
| + 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
|
| + |
| + ClassDeclaration findClass(String name) { |
| + for (var decl in compilationUnit.declarations) { |
| + if (decl is ClassDeclaration) { |
| + if (decl.name.name == name) return decl; |
| + } |
| + } |
| + return null; |
| + } |
| +} |
| + |
| +// TODO(jmesserly): I think Part and Import will have a common base class soon, |
| +// which will make this easier. |
| +StringLiteral getDirectiveUri(Directive directive) { |
| + if (directive is NamespaceDirective) { |
| + 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
|
| + } else { |
| + return (directive as PartDirective).partUri; |
| + } |
| +} |
| + |
| +void setDirectiveUri(Directive directive, StringLiteral uri) { |
| + if (directive is NamespaceDirective) { |
| + (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
|
| + } else { |
| + (directive as PartDirective).partUri2 = uri; |
| + } |
| +} |
| + |
| +SimpleStringLiteral createStringLiteral(String contents) { |
| + var lexeme = "'${escapeDartString(contents)}'"; |
| + var token = new StringToken(TokenType.STRING, lexeme, null); |
| + return new SimpleStringLiteral(token, contents); |
| +} |
| + |
| + |
| +/** |
| + * Parse and extract top-level directives from [code]. |
| + * |
| + * Adds emitted error/warning messages to [messages], if [messages] is |
| + * supplied. |
| + */ |
| +DartCodeInfo parseDartCode(Path path, String code, Messages messages) { |
| + var unit = parseCompilationUnit(code, path: path, messages: messages); |
| + |
| + // Extract some information from the compilation unit. |
| + String libraryName, partName; |
| + var directives = []; |
| + int directiveEnd = 0; |
| + for (var directive in unit.directives) { |
| + if (directive is LibraryDirective) { |
| + libraryName = directive.name.name; |
| + } else if (directive is PartOfDirective) { |
| + partName = directive.libraryName.name; |
| + } else { |
| + // Normalize the library URI. |
| + var uriNode = getDirectiveUri(directive); |
| + if (uriNode is! SimpleStringLiteral) { |
| + String uri = uriNode.accept(new ConstantEvaluator()); |
| + setDirectiveUri(directive, createStringLiteral(uri)); |
| + } |
| + directives.add(directive); |
| + } |
| + } |
| + |
| + return new DartCodeInfo(libraryName, partName, directives, code, unit); |
| +} |
| + |
| +CompilationUnit parseCompilationUnit(String code, {Path path, |
| + Messages messages}) { |
| + |
| + var errorListener = new _ErrorCollector(); |
| + var scanner = new StringScanner(null, code, errorListener); |
| + var token = scanner.tokenize(); |
| + var parser = new Parser(null, errorListener); |
| + var unit = parser.parseCompilationUnit(token); |
| + |
| + if (path == null || messages == null) return unit; |
| + |
| + // TODO(jmesserly): removed this for now because the analyzer doesn't format |
| + // messages properly, so you end up with things like "Unexpected token '%s'". |
| + // This used to convert parser messages into our messages. Enable this |
| + // once analyzer is fixed. |
| + if (false) { |
| + var file = new File.text(path.toString(), code); |
| + for (var e in errorListener.errors) { |
| + var span = new FileSpan(file, e.offset, e.offset + e.length); |
| + |
| + var severity = e.errorCode.errorSeverity; |
| + if (severity == ErrorSeverity.ERROR) { |
| + messages.error(e.message, span, file: path); |
| + } else { |
| + assert(severity == ErrorSeverity.WARNING); |
| + messages.warning(e.message, span, file: path); |
| + } |
| + } |
| + } |
| + |
| + return unit; |
| +} |
| + |
| +class _ErrorCollector extends AnalysisErrorListener { |
| + final errors = new List<AnalysisError>(); |
| + onError(error) => errors.add(error); |
| +} |