| // 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. |
| |
| import '../../scanner/token.dart' show Token; |
| |
| import '../messages.dart' show Message; |
| |
| import 'forwarding_listener.dart' show ForwardingListener; |
| |
| import 'listener.dart' show Listener; |
| |
| /// The abstract superclass of recovery listeners. |
| /// |
| /// During the first phase of recovery, some portion of the code is reparsed |
| /// to record information (e.g. tokens) that were not recorded during |
| /// the primary parse phase. During this phase, the [listener] is null |
| /// so that reparsing will not effect the primary listener state, |
| /// but the [_primaryListener] is non-null for those few events |
| /// where the parser requires the listener to interpret the token stream. |
| class RecoveryListener extends ForwardingListener { |
| // TODO(danrubel): remove the need for this field and this class |
| // by removing listener events that interpret the token stream for the parser. |
| final Listener _primaryListener; |
| |
| RecoveryListener(this._primaryListener); |
| |
| @override |
| Token handleUnrecoverableError(Token token, Message message) => |
| _primaryListener.handleUnrecoverableError(token, message); |
| |
| @override |
| Token newSyntheticToken(Token next) => |
| _primaryListener.newSyntheticToken(next); |
| } |
| |
| class ClassHeaderRecoveryListener extends RecoveryListener { |
| Token extendsKeyword; |
| Token implementsKeyword; |
| Token withKeyword; |
| |
| ClassHeaderRecoveryListener(Listener primaryListener) |
| : super(primaryListener); |
| |
| void clear() { |
| extendsKeyword = null; |
| implementsKeyword = null; |
| withKeyword = null; |
| } |
| |
| @override |
| void endMixinApplication(Token withKeyword) { |
| this.withKeyword = withKeyword; |
| super.endMixinApplication(withKeyword); |
| } |
| |
| @override |
| void handleClassExtends(Token extendsKeyword) { |
| this.extendsKeyword = extendsKeyword; |
| super.handleClassExtends(extendsKeyword); |
| } |
| |
| @override |
| void handleClassImplements(Token implementsKeyword, int interfacesCount) { |
| this.implementsKeyword = implementsKeyword; |
| super.handleClassImplements(implementsKeyword, interfacesCount); |
| } |
| } |
| |
| class ImportRecoveryListener extends RecoveryListener { |
| Token asKeyword; |
| Token deferredKeyword; |
| Token ifKeyword; |
| bool hasCombinator = false; |
| |
| ImportRecoveryListener(Listener primaryListener) : super(primaryListener); |
| |
| void clear() { |
| asKeyword = null; |
| deferredKeyword = null; |
| ifKeyword = null; |
| hasCombinator = false; |
| } |
| |
| void endConditionalUri(Token ifKeyword, Token leftParen, Token equalSign) { |
| this.ifKeyword = ifKeyword; |
| super.endConditionalUri(ifKeyword, leftParen, equalSign); |
| } |
| |
| void endHide(Token hideKeyword) { |
| this.hasCombinator = true; |
| super.endHide(hideKeyword); |
| } |
| |
| void endShow(Token showKeyword) { |
| this.hasCombinator = true; |
| super.endShow(showKeyword); |
| } |
| |
| void handleImportPrefix(Token deferredKeyword, Token asKeyword) { |
| this.deferredKeyword = deferredKeyword; |
| this.asKeyword = asKeyword; |
| super.handleImportPrefix(deferredKeyword, asKeyword); |
| } |
| } |