| // 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 '../fasta_codes.dart' show Message, Template, templateExpectedIdentifier; |
| |
| import '../scanner/token_constants.dart' show IDENTIFIER_TOKEN; |
| |
| import 'identifier_context_impl.dart'; |
| |
| import 'parser.dart' show Parser; |
| |
| /// Information about the parser state that is passed to the listener at the |
| /// time an identifier is encountered. It is also used by the parser for error |
| /// recovery when a recovery template is defined. |
| /// |
| /// This can be used by the listener to determine the context in which the |
| /// identifier appears; that in turn can help the listener decide how to resolve |
| /// the identifier (if the listener is doing resolution). |
| class IdentifierContext { |
| /// Identifier is being declared as the name of an import prefix (i.e. `Foo` |
| /// in `import "..." as Foo;`) |
| static const importPrefixDeclaration = const ImportPrefixIdentifierContext(); |
| |
| /// Identifier is the start of a dotted name in a conditional import or |
| /// export. |
| static const dottedName = const DottedNameIdentifierContext(); |
| |
| /// Identifier is part of a dotted name in a conditional import or export, but |
| /// it's not the first identifier of the dotted name. |
| static const dottedNameContinuation = |
| const DottedNameIdentifierContext.continuation(); |
| |
| /// Identifier is one of the shown/hidden names in an import/export |
| /// combinator. |
| static const combinator = const CombinatorIdentifierContext(); |
| |
| /// Identifier is the start of a name in an annotation that precedes a |
| /// declaration (i.e. it appears directly after an `@`). |
| static const metadataReference = const MetadataReferenceIdentifierContext(); |
| |
| /// Identifier is part of a name in an annotation that precedes a declaration, |
| /// but it's not the first identifier in the name. |
| static const metadataContinuation = |
| const MetadataReferenceIdentifierContext.continuation(); |
| |
| /// Identifier is part of a name in an annotation that precedes a declaration, |
| /// but it appears after type parameters (e.g. `foo` in `@X<Y>.foo()`). |
| static const metadataContinuationAfterTypeArguments = |
| const MetadataReferenceIdentifierContext.continuationAfterTypeArguments(); |
| |
| /// Identifier is the name being declared by a typedef declaration. |
| static const typedefDeclaration = const TypedefDeclarationIdentifierContext(); |
| |
| /// Identifier is a field initializer in a formal parameter list (i.e. it |
| /// appears directly after `this.`). |
| static const fieldInitializer = const FieldInitializerIdentifierContext(); |
| |
| /// Identifier is a formal parameter being declared as part of a function, |
| /// method, or typedef declaration. |
| static const formalParameterDeclaration = |
| const FormalParameterDeclarationIdentifierContext(); |
| |
| /// Identifier is the start of a library name (e.g. `foo` in the directive |
| /// 'library foo;`). |
| static const libraryName = const LibraryIdentifierContext(); |
| |
| /// Identifier is part of a library name, but it's not the first identifier in |
| /// the name. |
| static const libraryNameContinuation = |
| const LibraryIdentifierContext.continuation(); |
| |
| /// Identifier is the start of a library name referenced by a `part of` |
| /// directive (e.g. `foo` in the directive `part of foo;`). |
| static const partName = const LibraryIdentifierContext.partName(); |
| |
| /// Identifier is part of a library name referenced by a `part of` directive, |
| /// but it's not the first identifier in the name. |
| static const partNameContinuation = |
| const LibraryIdentifierContext.partNameContinuation(); |
| |
| /// Identifier is the type name being declared by an enum declaration. |
| static const enumDeclaration = const EnumDeclarationIdentifierContext(); |
| |
| /// Identifier is an enumerated value name being declared by an enum |
| /// declaration. |
| static const enumValueDeclaration = |
| const EnumValueDeclarationIdentifierContext(); |
| |
| /// Identifier is the name being declared by a class declaration or a named |
| /// mixin application, for example, `Foo` in `class Foo = X with Y;`. |
| static const classOrNamedMixinDeclaration = |
| const ClassOrNamedMixinIdentifierContext(); |
| |
| /// Identifier is the name of a type variable being declared (e.g. `Foo` in |
| /// `class C<Foo extends num> {}`). |
| static const typeVariableDeclaration = |
| const TypeVariableDeclarationIdentifierContext(); |
| |
| /// Identifier is the start of a reference to a type that starts with prefix. |
| static const prefixedTypeReference = |
| const TypeReferenceIdentifierContext.prefixed(); |
| |
| /// Identifier is the start of a reference to a type declared elsewhere. |
| static const typeReference = const TypeReferenceIdentifierContext(); |
| |
| /// Identifier is part of a reference to a type declared elsewhere, but it's |
| /// not the first identifier of the reference. |
| static const typeReferenceContinuation = |
| const TypeReferenceIdentifierContext.continuation(); |
| |
| /// Identifier is a name being declared by a top level variable declaration. |
| static const topLevelVariableDeclaration = |
| const TopLevelDeclarationIdentifierContext( |
| 'topLevelVariableDeclaration', const [';', '=', ',']); |
| |
| /// Identifier is a name being declared by a field declaration. |
| static const fieldDeclaration = const FieldDeclarationIdentifierContext(); |
| |
| /// Identifier is the name being declared by a top level function declaration. |
| static const topLevelFunctionDeclaration = |
| const TopLevelDeclarationIdentifierContext( |
| 'topLevelFunctionDeclaration', const ['<', '(', '{', '=>']); |
| |
| /// Identifier is the start of the name being declared by a method |
| /// declaration. |
| static const methodDeclaration = const MethodDeclarationIdentifierContext(); |
| |
| /// Identifier is part of the name being declared by a method declaration, |
| /// but it's not the first identifier of the name. |
| /// |
| /// In valid Dart, this can only happen if the identifier is the name of a |
| /// named constructor which is being declared, e.g. `foo` in |
| /// `class C { C.foo(); }`. |
| static const methodDeclarationContinuation = |
| const MethodDeclarationIdentifierContext.continuation(); |
| |
| /// Identifier appears after the word `operator` in a method declaration. |
| /// |
| /// TODO(paulberry,ahe): Does this ever occur in valid Dart, or does it only |
| /// occur as part of error recovery? If it's only as part of error recovery, |
| /// perhaps we should just re-use methodDeclaration. |
| static const operatorName = |
| const MethodDeclarationIdentifierContext.continuation(); |
| |
| /// Identifier is the start of the name being declared by a local function |
| /// declaration. |
| static const localFunctionDeclaration = |
| const LocalFunctionDeclarationIdentifierContext(); |
| |
| /// Identifier is part of the name being declared by a local function |
| /// declaration, but it's not the first identifier of the name. |
| /// |
| /// TODO(paulberry,ahe): Does this ever occur in valid Dart, or does it only |
| /// occur as part of error recovery? |
| static const localFunctionDeclarationContinuation = |
| const LocalFunctionDeclarationIdentifierContext.continuation(); |
| |
| /// Identifier is the start of a reference to a constructor declared |
| /// elsewhere. |
| static const constructorReference = |
| const ConstructorReferenceIdentifierContext(); |
| |
| /// Identifier is part of a reference to a constructor declared elsewhere, but |
| /// it's not the first identifier of the reference. |
| static const constructorReferenceContinuation = |
| const ConstructorReferenceIdentifierContext.continuation(); |
| |
| /// Identifier is part of a reference to a constructor declared elsewhere, but |
| /// it appears after type parameters (e.g. `foo` in `X<Y>.foo`). |
| static const constructorReferenceContinuationAfterTypeArguments = |
| const ConstructorReferenceIdentifierContext |
| .continuationAfterTypeArguments(); |
| |
| /// Identifier is the declaration of a label (i.e. it is followed by `:` and |
| /// then a statement). |
| static const labelDeclaration = const LabelDeclarationIdentifierContext(); |
| |
| /// Identifier is the start of a reference occurring in a literal symbol (e.g. |
| /// `foo` in `#foo`). |
| static const literalSymbol = const LiteralSymbolIdentifierContext(); |
| |
| /// Identifier is part of a reference occurring in a literal symbol, but it's |
| /// not the first identifier of the reference (e.g. `foo` in `#prefix.foo`). |
| static const literalSymbolContinuation = |
| const LiteralSymbolIdentifierContext.continuation(); |
| |
| /// Identifier appears in an expression, and it does not immediately follow a |
| /// `.`. |
| static const expression = const ExpressionIdentifierContext(); |
| |
| /// Identifier appears in an expression, and it immediately follows a `.`. |
| static const expressionContinuation = |
| const ExpressionIdentifierContext.continuation(); |
| |
| /// Identifier is a reference to a named argument of a function or method |
| /// invocation (e.g. `foo` in `f(foo: 0);`. |
| static const namedArgumentReference = |
| const NamedArgumentReferenceIdentifierContext(); |
| |
| /// Identifier is a name being declared by a local variable declaration. |
| static const localVariableDeclaration = |
| const LocalVariableDeclarationIdentifierContext(); |
| |
| /// Identifier is a reference to a label (e.g. `foo` in `break foo;`). |
| /// Labels have their own scope. |
| static const labelReference = const LabelReferenceIdentifierContext(); |
| |
| final String _name; |
| |
| /// Indicates whether the identifier represents a name which is being |
| /// declared. |
| final bool inDeclaration; |
| |
| /// Indicates whether the identifier is within a `library` or `part of` |
| /// declaration. |
| final bool inLibraryOrPartOfDeclaration; |
| |
| /// Indicates whether the identifier is within a symbol literal. |
| final bool inSymbol; |
| |
| /// Indicates whether the identifier follows a `.`. |
| final bool isContinuation; |
| |
| /// Indicates whether the identifier should be looked up in the current scope. |
| final bool isScopeReference; |
| |
| /// Indicates whether built-in identifiers are allowed in this context. |
| final bool isBuiltInIdentifierAllowed; |
| |
| /// Indicated whether the identifier is allowed in a context where constant |
| /// expressions are required. |
| final bool allowedInConstantExpression; |
| |
| final Template<_MessageWithArgument<Token>> recoveryTemplate; |
| |
| const IdentifierContext(this._name, |
| {this.inDeclaration: false, |
| this.inLibraryOrPartOfDeclaration: false, |
| this.inSymbol: false, |
| this.isContinuation: false, |
| this.isScopeReference: false, |
| this.isBuiltInIdentifierAllowed: true, |
| bool allowedInConstantExpression, |
| this.recoveryTemplate: templateExpectedIdentifier}) |
| : this.allowedInConstantExpression = |
| // Generally, declarations are legal in constant expressions. A |
| // continuation doesn't affect constant expressions: if what it's |
| // continuing is a problem, it has already been reported. |
| allowedInConstantExpression ?? |
| (inDeclaration || isContinuation || inSymbol); |
| |
| String toString() => _name; |
| |
| /// Ensure that the next token is an identifier (or keyword which should be |
| /// treated as an identifier) and return that identifier. |
| /// Report errors as necessary via [parser]. |
| Token ensureIdentifier(Token token, Parser parser) { |
| assert(token.next.kind != IDENTIFIER_TOKEN); |
| // TODO(danrubel): Implement this method for each identifier context |
| // such that they return a non-null value. |
| return null; |
| } |
| } |
| |
| // TODO(ahe): Remove when analyzer supports generalized function syntax. |
| typedef _MessageWithArgument<T> = Message Function(T); |