| // Copyright (c) 2017, 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. |
| |
| // @dart = 2.9 |
| |
| /// Listener used in combination with `TopLevelParser` to extract the URIs of |
| /// import, part, and export directives. |
| library front_end.src.fasta.source.directive_listener; |
| |
| import 'package:_fe_analyzer_shared/src/scanner/token.dart' show Token; |
| import 'package:_fe_analyzer_shared/src/parser/identifier_context.dart'; |
| import 'package:_fe_analyzer_shared/src/parser/listener.dart'; |
| import 'package:_fe_analyzer_shared/src/parser/quote.dart'; |
| import '../fasta_codes.dart' show messageExpectedBlockToSkip; |
| |
| /// 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 |
| /// for directives. Note that on correct programs directives cannot occur after |
| /// any top-level declaration, but we recommend to continue parsing the entire |
| /// file in order to gracefully handle input errors. |
| class DirectiveListener extends Listener { |
| /// Import directives with URIs and combinators. |
| final List<NamespaceDirective> imports = <NamespaceDirective>[]; |
| |
| /// Export directives with URIs and combinators. |
| final List<NamespaceDirective> exports = <NamespaceDirective>[]; |
| |
| /// Collects URIs that occur on any part directive. |
| final Set<String> parts = new Set<String>(); |
| |
| bool _inPart = false; |
| String _uri; |
| List<NamespaceCombinator> _combinators; |
| List<String> _combinatorNames; |
| |
| DirectiveListener(); |
| |
| @override |
| beginExport(Token export) { |
| _combinators = <NamespaceCombinator>[]; |
| } |
| |
| @override |
| void beginHide(Token hide) { |
| _combinatorNames = <String>[]; |
| } |
| |
| @override |
| beginImport(Token import) { |
| _combinators = <NamespaceCombinator>[]; |
| } |
| |
| @override |
| void beginLiteralString(Token token) { |
| if (_combinators != null || _inPart) { |
| _uri = unescapeString(token.lexeme, token, this); |
| } |
| } |
| |
| @override |
| beginPart(Token part) { |
| _inPart = true; |
| } |
| |
| @override |
| void beginShow(Token show) { |
| _combinatorNames = <String>[]; |
| } |
| |
| @override |
| endExport(Token export, Token semicolon) { |
| exports.add(new NamespaceDirective.export(_uri, _combinators)); |
| _uri = null; |
| _combinators = null; |
| } |
| |
| @override |
| void endHide(Token hide) { |
| _combinators.add(new NamespaceCombinator.hide(_combinatorNames)); |
| _combinatorNames = null; |
| } |
| |
| @override |
| endImport(Token import, Token semicolon) { |
| imports.add(new NamespaceDirective.import(_uri, _combinators)); |
| _uri = null; |
| _combinators = null; |
| } |
| |
| @override |
| endPart(Token part, Token semicolon) { |
| parts.add(_uri); |
| _uri = null; |
| _inPart = false; |
| } |
| |
| @override |
| void endShow(Token show) { |
| _combinators.add(new NamespaceCombinator.show(_combinatorNames)); |
| _combinatorNames = null; |
| } |
| |
| @override |
| void handleIdentifier(Token token, IdentifierContext context) { |
| if (_combinatorNames != null && context == IdentifierContext.combinator) { |
| _combinatorNames.add(token.lexeme); |
| } |
| } |
| |
| /// By default, native clauses are not handled and an error is thrown. |
| @override |
| void handleNativeFunctionBodySkipped(Token nativeToken, Token semicolon) { |
| super.handleRecoverableError( |
| messageExpectedBlockToSkip, nativeToken, nativeToken); |
| } |
| } |
| |
| 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(); |
| } |
| |
| class NamespaceDirective { |
| final bool isImport; |
| final String uri; |
| final List<NamespaceCombinator> combinators; |
| |
| NamespaceDirective.export(this.uri, this.combinators) : isImport = false; |
| |
| NamespaceDirective.import(this.uri, this.combinators) : isImport = true; |
| } |