Index: pkg/front_end/lib/src/fasta/source/directive_listener.dart |
diff --git a/pkg/front_end/lib/src/fasta/source/directive_listener.dart b/pkg/front_end/lib/src/fasta/source/directive_listener.dart |
index 2adf931162d80de7e7e4b86f3420fb8a2e382937..ce4709a5a2390c8173dc0a1450757fe4ac08c9a1 100644 |
--- a/pkg/front_end/lib/src/fasta/source/directive_listener.dart |
+++ b/pkg/front_end/lib/src/fasta/source/directive_listener.dart |
@@ -7,11 +7,13 @@ |
library front_end.src.fasta.source.directive_listener; |
import '../fasta_codes.dart' show FastaMessage, codeExpectedBlockToSkip; |
+import '../parser/identifier_context.dart'; |
import '../parser/listener.dart'; |
import '../quote.dart'; |
import '../scanner/token.dart'; |
+import 'stack_listener.dart'; |
-/// Listener that records the URIs from imports, exports, and part directives. |
+/// Listener that records imports, exports, and part directives. |
/// |
/// This is normally used in combination with the `TopLevelParser`, which skips |
/// over the body of declarations like classes and function that are irrelevant |
@@ -19,60 +21,102 @@ import '../scanner/token.dart'; |
/// any top-level declaration, but we recommend to continue parsing the entire |
/// file in order to gracefully handle input errors. |
class DirectiveListener extends Listener { |
- /// Collects URIs that occur on any import directive. |
- final Set<String> imports = new Set<String>(); |
+ final Stack _stack = new Stack(); |
- /// Collects URIs that occur on any export directive. |
- final Set<String> exports = new Set<String>(); |
+ /// Export directives with URIs and combinators. |
+ final List<ImportDirective> imports = <ImportDirective>[]; |
+ |
+ /// Export directives with URIs and combinators. |
+ final List<ExportDirective> exports = <ExportDirective>[]; |
/// Collects URIs that occur on any part directive. |
final Set<String> parts = new Set<String>(); |
- DirectiveListener(); |
+ bool _inDirective = false; |
- /// Set when entering the context of a directive, null when the parser is not |
- /// looking at a directive. |
- Set<String> _current = null; |
+ DirectiveListener(); |
- bool get _inDirective => _current != null; |
+ @override |
+ beginExport(_) { |
+ _inDirective = true; |
+ } |
@override |
beginImport(_) { |
- _current = imports; |
+ _inDirective = true; |
} |
@override |
- beginExport(_) { |
- _current = exports; |
+ void beginLiteralString(Token token) { |
+ if (_inDirective) { |
+ _push(unescapeString(token.lexeme)); |
+ } |
} |
@override |
beginPart(_) { |
- _current = parts; |
+ _inDirective = true; |
+ } |
+ |
+ @override |
+ void endCombinators(int count) { |
+ List<String> names = _popList(count); |
Siggi Cherem (dart-lang)
2017/05/15 22:18:53
I'm not opposed to keeping it as it is, but given
scheglov
2017/05/16 00:14:24
Thank you, good idea.
I will send a new CL with th
|
+ _push(names); |
} |
@override |
endExport(export, semicolon) { |
- _current = null; |
+ List<NamespaceCombinator> combinators = _pop(); |
+ String uri = _pop(); |
+ exports.add(new ExportDirective(uri, combinators)); |
+ _inDirective = false; |
+ } |
+ |
+ @override |
+ void endHide(Token hideKeyword) { |
+ List<String> names = _pop(); |
+ _push(new NamespaceCombinator.hide(names)); |
+ } |
+ |
+ @override |
+ void endIdentifierList(int count) { |
+ if (_inDirective) { |
+ _push(_popList(count) ?? <String>[]); |
+ } |
} |
@override |
endImport(import, deferred, asKeyword, semicolon) { |
- _current = null; |
+ List<NamespaceCombinator> combinators = _pop(); |
+ String uri = _pop(); |
+ imports.add(new ImportDirective(uri, combinators)); |
+ _inDirective = false; |
} |
@override |
endPart(part, semicolon) { |
- _current = null; |
+ String uri = _pop(); |
+ parts.add(uri); |
+ _inDirective = false; |
} |
@override |
- void beginLiteralString(Token token) { |
- if (_inDirective) { |
- _current.add(unescapeString(token.lexeme)); |
+ void endShow(Token showKeyword) { |
+ List<String> names = _pop(); |
+ _push(new NamespaceCombinator.show(names)); |
+ } |
+ |
+ @override |
+ void handleIdentifier(Token token, IdentifierContext context) { |
+ if (_inDirective && context == IdentifierContext.combinator) { |
+ _push(token.lexeme); |
} |
} |
+ /// Defines how native clauses are handled. By default, they are not handled |
+ /// and an error is thrown; |
+ Token handleNativeClause(Token token) => null; |
+ |
@override |
Token handleUnrecoverableError(Token token, FastaMessage message) { |
if (message.code == codeExpectedBlockToSkip) { |
@@ -82,7 +126,43 @@ class DirectiveListener extends Listener { |
return super.handleUnrecoverableError(token, message); |
} |
- /// Defines how native clauses are handled. By default, they are not handled |
- /// and an error is thrown; |
- Token handleNativeClause(Token token) => null; |
+ T _pop<T>() { |
+ var value = _stack.pop() as T; |
+ return value; |
+ } |
+ |
+ List<T> _popList<T>(int n) { |
+ return _stack.popList(n); |
+ } |
+ |
+ void _push<T>(T value) { |
+ _stack.push(value); |
+ } |
+} |
+ |
+class ExportDirective { |
+ final String uri; |
+ final List<NamespaceCombinator> combinators; |
Siggi Cherem (dart-lang)
2017/05/15 22:18:53
Just double checking - I was wondering whether we
scheglov
2017/05/16 00:14:24
The specification does not limit the number of com
|
+ |
+ ExportDirective(this.uri, this.combinators); |
+} |
+ |
+class ImportDirective { |
Siggi Cherem (dart-lang)
2017/05/15 22:18:53
consider using a single Directive class for both i
scheglov
2017/05/16 00:14:24
Done.
|
+ final String uri; |
+ final List<NamespaceCombinator> combinators; |
+ |
+ ImportDirective(this.uri, this.combinators); |
+} |
+ |
+class NamespaceCombinator { |
+ final bool isShow; |
+ final Set<String> names; |
+ |
+ NamespaceCombinator.hide(List<String> names) |
+ : isShow = false, |
+ names = names.toSet(); |
+ |
+ NamespaceCombinator.show(List<String> names) |
+ : isShow = true, |
+ names = names.toSet(); |
} |