| // Copyright (c) 2018, 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. |
| |
| library fasta.parser.type_info_impl; |
| |
| import '../../scanner/token.dart' show Token; |
| |
| import 'identifier_context.dart' show IdentifierContext; |
| |
| import 'listener.dart' show Listener; |
| |
| import 'parser.dart' show Parser; |
| |
| import 'type_info.dart' show TypeInfo, simpleTypeInfo; |
| |
| import 'util.dart' show optional; |
| |
| /// See documentation on the [noTypeInfo] const. |
| class NoTypeInfo implements TypeInfo { |
| const NoTypeInfo(); |
| |
| @override |
| Token parseType(Token token, Parser parser) { |
| parser.listener.handleNoType(token); |
| return token; |
| } |
| |
| @override |
| Token skipType(Token token) { |
| return token; |
| } |
| } |
| |
| /// See documentation on the [prefixedTypeInfo] const. |
| class PrefixedTypeInfo implements TypeInfo { |
| const PrefixedTypeInfo(); |
| |
| @override |
| Token parseType(Token token, Parser parser) { |
| Token start = token = token.next; |
| assert(token.isKeywordOrIdentifier); |
| Listener listener = parser.listener; |
| listener.handleIdentifier(token, IdentifierContext.prefixedTypeReference); |
| |
| Token period = token = token.next; |
| assert(optional('.', token)); |
| |
| token = token.next; |
| assert(token.isKeywordOrIdentifier); |
| listener.handleIdentifier( |
| token, IdentifierContext.typeReferenceContinuation); |
| listener.handleQualified(period); |
| |
| listener.handleNoTypeArguments(token.next); |
| listener.handleType(start, token.next); |
| return token; |
| } |
| |
| @override |
| Token skipType(Token token) { |
| return token.next.next.next; |
| } |
| } |
| |
| /// See documentation on the [simpleTypeArgumentsInfo] const. |
| class SimpleTypeArgumentsInfo implements TypeInfo { |
| const SimpleTypeArgumentsInfo(); |
| |
| @override |
| Token parseType(Token token, Parser parser) { |
| Token start = token = token.next; |
| assert(token.isKeywordOrIdentifier); |
| Listener listener = parser.listener; |
| listener.handleIdentifier(token, IdentifierContext.typeReference); |
| |
| Token begin = token = token.next; |
| assert(optional('<', token)); |
| listener.beginTypeArguments(token); |
| |
| token = simpleTypeInfo.parseType(token, parser); |
| |
| token = token.next; |
| assert(optional('>', token)); |
| assert(begin.endGroup == token); |
| listener.endTypeArguments(1, begin, token); |
| |
| listener.handleType(start, token.next); |
| return token; |
| } |
| |
| @override |
| Token skipType(Token token) { |
| return token.next.next.endGroup; |
| } |
| } |
| |
| /// See documentation on the [simpleTypeInfo] const. |
| class SimpleTypeInfo implements TypeInfo { |
| const SimpleTypeInfo(); |
| |
| @override |
| Token parseType(Token token, Parser parser) { |
| token = token.next; |
| assert(token.isKeywordOrIdentifier); |
| Listener listener = parser.listener; |
| listener.handleIdentifier(token, IdentifierContext.typeReference); |
| listener.handleNoTypeArguments(token.next); |
| listener.handleType(token, token.next); |
| return token; |
| } |
| |
| @override |
| Token skipType(Token token) { |
| return token.next; |
| } |
| } |
| |
| /// See documentation on the [voidTypeInfo] const. |
| class VoidTypeInfo implements TypeInfo { |
| const VoidTypeInfo(); |
| |
| @override |
| Token parseType(Token token, Parser parser) { |
| token = token.next; |
| parser.listener.handleVoidKeyword(token); |
| return token; |
| } |
| |
| @override |
| Token skipType(Token token) { |
| return token.next; |
| } |
| } |
| |
| bool looksLikeName(Token next) => next.isIdentifier || optional('this', next); |
| |
| Token skipTypeArguments(Token token) { |
| assert(optional('<', token)); |
| Token endGroup = token.endGroup; |
| |
| // The scanner sets the endGroup in situations like this: C<T && T>U; |
| // Scan the type arguments to assert there are no operators. |
| // TODO(danrubel) Fix the scanner and remove this code. |
| if (endGroup != null) { |
| token = token.next; |
| while (token != endGroup) { |
| if (token.isOperator) { |
| String value = token.stringValue; |
| if (!identical(value, '<') && |
| !identical(value, '>') && |
| !identical(value, '>>')) { |
| return null; |
| } |
| } |
| token = token.next; |
| } |
| } |
| |
| return endGroup; |
| } |