mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 10:10:22 +00:00
Improve fasta parser import prefix recovery
Change-Id: Ib1265cee27ff4e7cfc20012d3e4281cd151accdc Reviewed-on: https://dart-review.googlesource.com/53140 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Dan Rubel <danrubel@google.com>
This commit is contained in:
parent
d85c175a22
commit
bf91621857
4 changed files with 59 additions and 8 deletions
|
@ -76,6 +76,15 @@ class ImportDirectivesTest extends PartialCodeTest {
|
|||
ParserErrorCode.EXPECTED_STRING_LITERAL
|
||||
],
|
||||
"import 'a.dart' if (b) '';"),
|
||||
new TestDescriptor(
|
||||
'ifCondition',
|
||||
"import 'a.dart' as",
|
||||
[
|
||||
ParserErrorCode.MISSING_IDENTIFIER,
|
||||
ParserErrorCode.EXPECTED_TOKEN
|
||||
],
|
||||
"import 'a.dart' as _s_;",
|
||||
failing: ['functionNonVoid', 'getter']),
|
||||
],
|
||||
PartialCodeTest.prePartSuffixes);
|
||||
}
|
||||
|
|
|
@ -22,10 +22,7 @@ import 'parser.dart' show Parser;
|
|||
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);
|
||||
static const importPrefixDeclaration = const ImportPrefixIdentifierContext();
|
||||
|
||||
/// Identifier is the start of a dotted name in a conditional import or
|
||||
/// export.
|
||||
|
|
|
@ -31,6 +31,7 @@ class ClassOrNamedMixinIdentifierContext extends IdentifierContext {
|
|||
return identifier;
|
||||
}
|
||||
|
||||
// Recovery
|
||||
if (looksLikeStartOfNextTopLevelDeclaration(identifier) ||
|
||||
isOneOfOrEof(
|
||||
identifier, const ['<', '{', 'extends', 'with', 'implements'])) {
|
||||
|
@ -76,6 +77,7 @@ class DottedNameIdentifierContext extends IdentifierContext {
|
|||
}
|
||||
}
|
||||
|
||||
// Recovery
|
||||
if (looksLikeStartOfNextTopLevelDeclaration(identifier) ||
|
||||
isOneOfOrEof(identifier, followingValues)) {
|
||||
identifier = parser.insertSyntheticIdentifier(token, this,
|
||||
|
@ -123,6 +125,8 @@ class ExpressionIdentifierContext extends IdentifierContext {
|
|||
}
|
||||
return identifier;
|
||||
}
|
||||
|
||||
// Recovery
|
||||
parser.reportRecoverableErrorWithToken(
|
||||
identifier, fasta.templateExpectedIdentifier);
|
||||
if (identifier.isKeywordOrIdentifier) {
|
||||
|
@ -152,6 +156,7 @@ class FieldDeclarationIdentifierContext extends IdentifierContext {
|
|||
if (identifier.isIdentifier) {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
// Recovery
|
||||
if (isOneOfOrEof(identifier, const [';', '=', ',', '}']) ||
|
||||
looksLikeStartOfNextClassMember(identifier)) {
|
||||
|
@ -183,6 +188,8 @@ class FieldInitializerIdentifierContext extends IdentifierContext {
|
|||
if (identifier.isIdentifier) {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
// Recovery
|
||||
parser.reportRecoverableErrorWithToken(
|
||||
identifier, fasta.templateExpectedIdentifier);
|
||||
// Insert a synthetic identifier to satisfy listeners.
|
||||
|
@ -190,6 +197,43 @@ class FieldInitializerIdentifierContext extends IdentifierContext {
|
|||
}
|
||||
}
|
||||
|
||||
/// See [IdentifierContext].importPrefixDeclaration
|
||||
class ImportPrefixIdentifierContext extends IdentifierContext {
|
||||
const ImportPrefixIdentifierContext()
|
||||
: super('importPrefixDeclaration',
|
||||
inDeclaration: true, isBuiltInIdentifierAllowed: false);
|
||||
|
||||
@override
|
||||
Token ensureIdentifier(Token token, Parser parser) {
|
||||
Token identifier = token.next;
|
||||
assert(identifier.kind != IDENTIFIER_TOKEN);
|
||||
if (identifier.type.isPseudo) {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
// Recovery
|
||||
const followingValues = const [';', 'if', 'show', 'hide', 'deferred', 'as'];
|
||||
if (identifier.type.isBuiltIn &&
|
||||
isOneOfOrEof(identifier.next, followingValues)) {
|
||||
parser.reportRecoverableErrorWithToken(
|
||||
identifier, fasta.templateBuiltInIdentifierInDeclaration);
|
||||
} else if (looksLikeStartOfNextTopLevelDeclaration(identifier) ||
|
||||
isOneOfOrEof(identifier, followingValues)) {
|
||||
identifier = parser.insertSyntheticIdentifier(token, this,
|
||||
message: fasta.templateExpectedIdentifier.withArguments(identifier));
|
||||
} else {
|
||||
parser.reportRecoverableErrorWithToken(
|
||||
identifier, fasta.templateExpectedIdentifier);
|
||||
if (!identifier.isKeywordOrIdentifier) {
|
||||
// When in doubt, consume the token to ensure we make progress
|
||||
// but insert a synthetic identifier to satisfy listeners.
|
||||
identifier = insertSyntheticIdentifierAfter(identifier, parser);
|
||||
}
|
||||
}
|
||||
return identifier;
|
||||
}
|
||||
}
|
||||
|
||||
/// See [IdentifierContext].libraryName
|
||||
class LibraryIdentifierContext extends IdentifierContext {
|
||||
const LibraryIdentifierContext()
|
||||
|
@ -213,6 +257,8 @@ class LibraryIdentifierContext extends IdentifierContext {
|
|||
// is invalid and this looks like the start of the next declaration.
|
||||
// In this situation, fall through to insert a synthetic library name.
|
||||
}
|
||||
|
||||
// Recovery
|
||||
if (isOneOfOrEof(identifier, const ['.', ';']) ||
|
||||
looksLikeStartOfNextTopLevelDeclaration(identifier)) {
|
||||
identifier = parser.insertSyntheticIdentifier(token, this,
|
||||
|
@ -243,6 +289,8 @@ class LocalVariableDeclarationIdentifierContext extends IdentifierContext {
|
|||
checkAsyncAwaitYieldAsIdentifier(identifier, parser);
|
||||
return identifier;
|
||||
}
|
||||
|
||||
// Recovery
|
||||
if (isOneOfOrEof(identifier, const [';', '=', ',', '{', '}']) ||
|
||||
looksLikeStartOfNextStatement(identifier)) {
|
||||
identifier = parser.insertSyntheticIdentifier(token, this,
|
||||
|
@ -275,6 +323,7 @@ class MethodDeclarationIdentifierContext extends IdentifierContext {
|
|||
if (identifier.isIdentifier) {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
// Recovery
|
||||
if (identifier.isUserDefinableOperator && !isContinuation) {
|
||||
return parser.insertSyntheticIdentifier(identifier, this,
|
||||
|
|
|
@ -2005,8 +2005,6 @@ class Parser {
|
|||
followingValues = [',', '}'];
|
||||
} else if (context == IdentifierContext.formalParameterDeclaration) {
|
||||
followingValues = [':', '=', ',', '(', ')', '[', ']', '{', '}'];
|
||||
} else if (context == IdentifierContext.importPrefixDeclaration) {
|
||||
followingValues = [';', 'hide', 'show', 'deferred', 'as'];
|
||||
} else if (context == IdentifierContext.labelDeclaration) {
|
||||
followingValues = [':'];
|
||||
} else if (context == IdentifierContext.literalSymbol ||
|
||||
|
@ -2084,8 +2082,6 @@ class Parser {
|
|||
..addAll(classMemberKeywords())
|
||||
..addAll(statementKeywords())
|
||||
..add('covariant');
|
||||
} else if (context == IdentifierContext.importPrefixDeclaration) {
|
||||
initialKeywords = topLevelKeywords();
|
||||
} else if (context == IdentifierContext.labelDeclaration) {
|
||||
initialKeywords = statementKeywords();
|
||||
} else if (context == IdentifierContext.localAccessorDeclaration) {
|
||||
|
|
Loading…
Reference in a new issue