blob: 5908d9285d4823531609f01626fdf93a3f872272 [file] [log] [blame]
// 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.
/// Information about the parser state which is passed to the listener at the
/// time an identifier is encountered.
///
/// 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 IdentifierContext._(
'importPrefixDeclaration',
inDeclaration: true,
isBuiltInIdentifierAllowed: false);
/// Identifier is the start of a dotted name in a conditional import or
/// export.
static const dottedName = const IdentifierContext._('dottedName');
/// 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 IdentifierContext._('dottedNameContinuation', isContinuation: true);
/// Identifier is one of the shown/hidden names in an import/export
/// combinator.
static const combinator = const IdentifierContext._('combinator');
/// 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 IdentifierContext._('metadataReference', isScopeReference: true);
/// 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 IdentifierContext._('metadataContinuation', isContinuation: true);
/// 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 IdentifierContext._('metadataContinuationAfterTypeArguments',
isContinuation: true);
/// Identifier is the name being declared by a typedef declaration.
static const typedefDeclaration = const IdentifierContext._(
'typedefDeclaration',
inDeclaration: true,
isBuiltInIdentifierAllowed: false);
/// Identifier is a field initializer in a formal parameter list (i.e. it
/// appears directly after `this.`).
static const fieldInitializer =
const IdentifierContext._('fieldInitializer', isContinuation: true);
/// Identifier is a formal parameter being declared as part of a function,
/// method, or typedef declaration.
static const formalParameterDeclaration = const IdentifierContext._(
'formalParameterDeclaration',
inDeclaration: true);
/// Identifier is the start of a library name (e.g. `foo` in the directive
/// 'library foo;`).
static const libraryName = const IdentifierContext._('libraryName',
inLibraryOrPartOfDeclaration: true);
/// Identifier is part of a library name, but it's not the first identifier in
/// the name.
static const libraryNameContinuation = const IdentifierContext._(
'libraryNameContinuation',
inLibraryOrPartOfDeclaration: true,
isContinuation: true);
/// 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 IdentifierContext._('partName', inLibraryOrPartOfDeclaration: true);
/// 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 IdentifierContext._(
'partNameContinuation',
inLibraryOrPartOfDeclaration: true,
isContinuation: true);
/// Identifier is the type name being declared by an enum declaration.
static const enumDeclaration = const IdentifierContext._('enumDeclaration',
inDeclaration: true, isBuiltInIdentifierAllowed: false);
/// Identifier is an enumerated value name being declared by an enum
/// declaration.
static const enumValueDeclaration =
const IdentifierContext._('enumValueDeclaration', inDeclaration: true);
/// Identifier is the name being declared by a named mixin declaration (e.g.
/// `Foo` in `class Foo = X with Y;`).
static const namedMixinDeclaration = const IdentifierContext._(
'namedMixinDeclaration',
inDeclaration: true,
isBuiltInIdentifierAllowed: false);
/// Identifier is the name being declared by a class declaration.
static const classDeclaration = const IdentifierContext._('classDeclaration',
inDeclaration: true, isBuiltInIdentifierAllowed: false);
/// Identifier is the name of a type variable being declared (e.g. `Foo` in
/// `class C<Foo extends num> {}`).
static const typeVariableDeclaration = const IdentifierContext._(
'typeVariableDeclaration',
inDeclaration: true,
isBuiltInIdentifierAllowed: false);
/// Identifier is the start of a reference to a type that starts with prefix.
static const prefixedTypeReference = const IdentifierContext._(
'prefixedTypeReference',
isScopeReference: true,
isBuiltInIdentifierAllowed: true);
/// Identifier is the start of a reference to a type declared elsewhere.
static const typeReference = const IdentifierContext._('typeReference',
isScopeReference: true, isBuiltInIdentifierAllowed: false);
/// 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 IdentifierContext._(
'typeReferenceContinuation',
isContinuation: true,
isBuiltInIdentifierAllowed: false);
/// Identifier is a name being declared by a top level variable declaration.
static const topLevelVariableDeclaration = const IdentifierContext._(
'topLevelVariableDeclaration',
inDeclaration: true);
/// Identifier is a name being declared by a field declaration.
static const fieldDeclaration =
const IdentifierContext._('fieldDeclaration', inDeclaration: true);
/// Identifier is the name being declared by a top level function declaration.
static const topLevelFunctionDeclaration = const IdentifierContext._(
'topLevelFunctionDeclaration',
inDeclaration: true);
/// Identifier is the start of the name being declared by a method
/// declaration.
static const methodDeclaration =
const IdentifierContext._('methodDeclaration', inDeclaration: true);
/// 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 IdentifierContext._(
'methodDeclarationContinuation',
inDeclaration: true,
isContinuation: true);
/// 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 IdentifierContext._('operatorName');
/// Identifier is the name being declared by a local function declaration that
/// uses a "get" or "set" keyword.
///
/// 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 localFunctionDeclaration.
static const localAccessorDeclaration = const IdentifierContext._(
'localAccessorDeclaration',
inDeclaration: true);
/// Identifier is the start of the name being declared by a local function
/// declaration.
static const localFunctionDeclaration = const IdentifierContext._(
'localFunctionDeclaration',
inDeclaration: true);
/// 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 IdentifierContext._(
'localFunctionDeclarationContinuation',
inDeclaration: true,
isContinuation: true);
/// Identifier is the name appearing in a function expression.
///
/// TODO(paulberry,ahe): What is an example of valid Dart code where this
/// would occur?
static const functionExpressionName =
const IdentifierContext._('functionExpressionName');
/// Identifier is the start of a reference to a constructor declared
/// elsewhere.
static const constructorReference =
const IdentifierContext._('constructorReference', isScopeReference: true);
/// 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 IdentifierContext._(
'constructorReferenceContinuation',
isContinuation: true);
/// 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 IdentifierContext._(
'constructorReferenceContinuationAfterTypeArguments',
isContinuation: true);
/// Identifier is the declaration of a label (i.e. it is followed by `:` and
/// then a statement).
static const labelDeclaration =
const IdentifierContext._('labelDeclaration', inDeclaration: true);
/// Identifier is the start of a reference occurring in a literal symbol (e.g.
/// `foo` in `#foo`).
static const literalSymbol =
const IdentifierContext._('literalSymbol', inSymbol: true);
/// 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 IdentifierContext._(
'literalSymbolContinuation',
inSymbol: true,
isContinuation: true);
/// Identifier appears in an expression, and it does not immediately follow a
/// `.`.
static const expression =
const IdentifierContext._('expression', isScopeReference: true);
/// Identifier appears in an expression, and it immediately follows a `.`.
static const expressionContinuation =
const IdentifierContext._('expressionContinuation', isContinuation: true);
/// 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 IdentifierContext._(
'namedArgumentReference',
allowedInConstantExpression: true);
/// Identifier is a name being declared by a local variable declaration.
static const localVariableDeclaration = const IdentifierContext._(
'localVariableDeclaration',
inDeclaration: true);
/// Identifier is a reference to a label (e.g. `foo` in `break foo;`).
/// Labels have their own scope.
static const labelReference = const IdentifierContext._('labelReference');
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;
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.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;
}