Ignore synthetic elements created by the parser
Change-Id: I558827417c938a22075c5b5357294d27cbd6286a Reviewed-on: https://dart-review.googlesource.com/76121 Reviewed-by: Aske Simon Christensen <askesc@google.com> Commit-Queue: Peter von der Ahé <ahe@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
fc04f56430
commit
4e32a356e0
@@ -117,8 +117,10 @@ abstract class ProcedureBuilder<T extends TypeBuilder> extends MemberBuilder {
|
||||
}
|
||||
|
||||
FormalParameterBuilder getFormal(String name) {
|
||||
for (FormalParameterBuilder formal in formals) {
|
||||
if (formal.name == name) return formal;
|
||||
if (formals != null) {
|
||||
for (FormalParameterBuilder formal in formals) {
|
||||
if (formal.name == name) return formal;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -31,8 +31,7 @@ import '../parser.dart'
|
||||
offsetForToken,
|
||||
optional;
|
||||
|
||||
import '../problems.dart'
|
||||
show internalProblem, unexpected, unhandled, unsupported;
|
||||
import '../problems.dart' show unexpected, unhandled, unsupported;
|
||||
|
||||
import '../quote.dart'
|
||||
show
|
||||
@@ -57,6 +56,7 @@ import '../source/scope_listener.dart'
|
||||
GrowableList,
|
||||
JumpTargetKind,
|
||||
NullValue,
|
||||
ParserRecovery,
|
||||
ScopeListener;
|
||||
|
||||
import '../type_inference/type_inferrer.dart' show TypeInferrer;
|
||||
@@ -324,8 +324,10 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
|
||||
}
|
||||
|
||||
Statement popBlock(int count, Token openBrace, Token closeBrace) {
|
||||
return forest.block(openBrace,
|
||||
const GrowableList<Statement>().pop(stack, count), closeBrace);
|
||||
return forest.block(
|
||||
openBrace,
|
||||
const GrowableList<Statement>().pop(stack, count) ?? <Statement>[],
|
||||
closeBrace);
|
||||
}
|
||||
|
||||
Statement popStatementIfNotNull(Object value) {
|
||||
@@ -471,7 +473,8 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
|
||||
if (count == 0) {
|
||||
push(NullValue.Metadata);
|
||||
} else {
|
||||
push(const GrowableList<Expression>().pop(stack, count));
|
||||
push(const GrowableList<Expression>().pop(stack, count) ??
|
||||
NullValue.Metadata /* Ignore parser recovery */);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1085,8 +1088,13 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
|
||||
@override
|
||||
void endArguments(int count, Token beginToken, Token endToken) {
|
||||
debugEvent("Arguments");
|
||||
List<Object> arguments =
|
||||
const FixedNullableList<Object>().pop(stack, count) ?? <Object>[];
|
||||
List<Object> arguments = count == 0
|
||||
? <Object>[]
|
||||
: const FixedNullableList<Object>().pop(stack, count);
|
||||
if (arguments == null) {
|
||||
push(new ParserRecovery(beginToken.charOffset));
|
||||
return;
|
||||
}
|
||||
int firstNamedArgumentIndex = arguments.length;
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
Object node = arguments[i];
|
||||
@@ -1728,6 +1736,10 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
|
||||
} else {
|
||||
int count = 1 + interpolationCount * 2;
|
||||
List<Object> parts = const FixedNullableList<Object>().pop(stack, count);
|
||||
if (parts == null) {
|
||||
push(new ParserRecovery(endToken.charOffset));
|
||||
return;
|
||||
}
|
||||
Token first = parts.first;
|
||||
Token last = parts.last;
|
||||
Quote quote = analyzeQuote(first.lexeme);
|
||||
@@ -1974,6 +1986,10 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
|
||||
currentLocalVariableType = pop();
|
||||
currentLocalVariableModifiers = pop();
|
||||
List<Expression> annotations = pop();
|
||||
if (variables == null) {
|
||||
push(new ParserRecovery(endToken.charOffset));
|
||||
return;
|
||||
}
|
||||
if (annotations != null) {
|
||||
bool isFirstVariable = true;
|
||||
for (VariableDeclarationJudgment variable in variables) {
|
||||
@@ -2185,7 +2201,8 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
|
||||
void handleLiteralMap(
|
||||
int count, Token leftBrace, Token constKeyword, Token rightBrace) {
|
||||
debugEvent("LiteralMap");
|
||||
List<MapEntry> entries = const GrowableList<MapEntry>().pop(stack, count);
|
||||
List<MapEntry> entries =
|
||||
const GrowableList<MapEntry>().pop(stack, count) ?? <MapEntry>[];
|
||||
List<UnresolvedType<KernelTypeBuilder>> typeArguments = pop();
|
||||
DartType keyType;
|
||||
DartType valueType;
|
||||
@@ -2245,6 +2262,10 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
|
||||
} else {
|
||||
List<Identifier> parts =
|
||||
const FixedNullableList<Identifier>().pop(stack, identifierCount);
|
||||
if (parts == null) {
|
||||
push(new ParserRecovery(hashToken.charOffset));
|
||||
return;
|
||||
}
|
||||
value = symbolPartToString(parts.first);
|
||||
for (int i = 1; i < parts.length; i++) {
|
||||
value += ".${symbolPartToString(parts[i])}";
|
||||
@@ -2460,6 +2481,10 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
|
||||
modifiers |= finalMask;
|
||||
}
|
||||
List<Expression> annotations = pop();
|
||||
if (nameToken.isSynthetic) {
|
||||
push(new ParserRecovery(nameToken.charOffset));
|
||||
return;
|
||||
}
|
||||
KernelFormalParameterBuilder parameter;
|
||||
if (!inCatchClause &&
|
||||
functionNestingLevel == 0 &&
|
||||
@@ -2467,11 +2492,8 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
|
||||
ProcedureBuilder<TypeBuilder> member = this.member;
|
||||
parameter = member.getFormal(name.name);
|
||||
if (parameter == null) {
|
||||
internalProblem(
|
||||
fasta.templateInternalProblemNotFoundIn
|
||||
.withArguments(name.name, "formals"),
|
||||
offsetForToken(nameToken),
|
||||
uri);
|
||||
push(new ParserRecovery(nameToken.charOffset));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
parameter = new KernelFormalParameterBuilder(null, modifiers,
|
||||
@@ -2517,10 +2539,14 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
|
||||
List<KernelFormalParameterBuilder> parameters =
|
||||
const FixedNullableList<KernelFormalParameterBuilder>()
|
||||
.pop(stack, count);
|
||||
for (KernelFormalParameterBuilder parameter in parameters) {
|
||||
parameter.kind = kind;
|
||||
if (parameters == null) {
|
||||
push(new ParserRecovery(offsetForToken(beginToken)));
|
||||
} else {
|
||||
for (KernelFormalParameterBuilder parameter in parameters) {
|
||||
parameter.kind = kind;
|
||||
}
|
||||
push(parameters);
|
||||
}
|
||||
push(parameters);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -2595,6 +2621,7 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
|
||||
if (optionals != null && parameters != null) {
|
||||
parameters.setRange(count, count + optionalsCount, optionals);
|
||||
}
|
||||
assert(parameters?.isNotEmpty ?? true);
|
||||
FormalParameters formals = new FormalParameters(parameters,
|
||||
offsetForToken(beginToken), lengthOfSpan(beginToken, endToken), uri);
|
||||
constantContext = pop();
|
||||
@@ -3238,7 +3265,8 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
|
||||
void endTypeArguments(int count, Token beginToken, Token endToken) {
|
||||
debugEvent("TypeArguments");
|
||||
push(const FixedNullableList<UnresolvedType<KernelTypeBuilder>>()
|
||||
.pop(stack, count));
|
||||
.pop(stack, count) ??
|
||||
NullValue.TypeArguments);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -3564,8 +3592,10 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
|
||||
enterLocalScope(null, scope.createNestedLabelScope());
|
||||
LabelTarget target =
|
||||
new LabelTarget(member, functionNestingLevel, token.charOffset);
|
||||
for (Label label in labels) {
|
||||
scope.declareLabel(label.name, target);
|
||||
if (labels != null) {
|
||||
for (Label label in labels) {
|
||||
scope.declareLabel(label.name, target);
|
||||
}
|
||||
}
|
||||
push(target);
|
||||
}
|
||||
@@ -3690,7 +3720,7 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
|
||||
int count = labelCount + expressionCount;
|
||||
List<Object> labelsAndExpressions =
|
||||
const FixedNullableList<Object>().pop(stack, count);
|
||||
List<Label> labels = new List<Label>(labelCount);
|
||||
List<Label> labels = labelCount == 0 ? null : new List<Label>(labelCount);
|
||||
List<Expression> expressions =
|
||||
new List<Expression>.filled(expressionCount, null, growable: true);
|
||||
int labelIndex = 0;
|
||||
@@ -3705,23 +3735,26 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
|
||||
}
|
||||
}
|
||||
assert(scope == switchScope);
|
||||
for (Label label in labels) {
|
||||
String labelName = label.name;
|
||||
if (scope.hasLocalLabel(labelName)) {
|
||||
// TODO(ahe): Should validate this is a goto target.
|
||||
if (!scope.claimLabel(labelName)) {
|
||||
addProblem(
|
||||
fasta.templateDuplicateLabelInSwitchStatement
|
||||
.withArguments(labelName),
|
||||
label.charOffset,
|
||||
labelName.length);
|
||||
if (labels != null) {
|
||||
for (Label label in labels) {
|
||||
String labelName = label.name;
|
||||
if (scope.hasLocalLabel(labelName)) {
|
||||
// TODO(ahe): Should validate this is a goto target.
|
||||
if (!scope.claimLabel(labelName)) {
|
||||
addProblem(
|
||||
fasta.templateDuplicateLabelInSwitchStatement
|
||||
.withArguments(labelName),
|
||||
label.charOffset,
|
||||
labelName.length);
|
||||
}
|
||||
} else {
|
||||
scope.declareLabel(
|
||||
labelName, createGotoTarget(firstToken.charOffset));
|
||||
}
|
||||
} else {
|
||||
scope.declareLabel(labelName, createGotoTarget(firstToken.charOffset));
|
||||
}
|
||||
}
|
||||
push(expressions);
|
||||
push(labels);
|
||||
push(labels ?? NullValue.Labels);
|
||||
enterLocalScope("switch case");
|
||||
}
|
||||
|
||||
@@ -3749,7 +3782,7 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
|
||||
push(new SwitchCaseJudgment(expressions, expressionOffsets, block,
|
||||
isDefault: defaultKeyword != null)
|
||||
..fileOffset = firstToken.charOffset);
|
||||
push(labels);
|
||||
push(labels ?? NullValue.Labels);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -3778,10 +3811,12 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
|
||||
for (int i = caseCount - 1; i >= 0; i--) {
|
||||
List<Label> labels = pop();
|
||||
SwitchCase current = cases[i] = pop();
|
||||
for (Label label in labels) {
|
||||
JumpTarget target = switchScope.lookupLabel(label.name);
|
||||
if (target != null) {
|
||||
target.resolveGotos(forest, current);
|
||||
if (labels != null) {
|
||||
for (Label label in labels) {
|
||||
JumpTarget target = switchScope.lookupLabel(label.name);
|
||||
if (target != null) {
|
||||
target.resolveGotos(forest, current);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ import 'kernel_builder.dart'
|
||||
ConstructorReferenceBuilder,
|
||||
Declaration,
|
||||
DynamicTypeBuilder,
|
||||
EnumConstantInfo,
|
||||
FormalParameterBuilder,
|
||||
InvalidTypeBuilder,
|
||||
KernelClassBuilder,
|
||||
@@ -700,22 +701,17 @@ class KernelLibraryBuilder
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void addEnum(
|
||||
String documentationComment,
|
||||
List<MetadataBuilder> metadata,
|
||||
String name,
|
||||
List<Object> constantNamesAndOffsets,
|
||||
List<EnumConstantInfo> enumConstantInfos,
|
||||
int charOffset,
|
||||
int charEndOffset) {
|
||||
MetadataCollector metadataCollector = loader.target.metadataCollector;
|
||||
KernelEnumBuilder builder = new KernelEnumBuilder(
|
||||
metadataCollector,
|
||||
metadata,
|
||||
name,
|
||||
constantNamesAndOffsets,
|
||||
this,
|
||||
charOffset,
|
||||
charEndOffset);
|
||||
KernelEnumBuilder builder = new KernelEnumBuilder(metadataCollector,
|
||||
metadata, name, enumConstantInfos, this, charOffset, charEndOffset);
|
||||
addBuilder(name, builder, charOffset);
|
||||
metadataCollector?.setDocumentationComment(
|
||||
builder.target, documentationComment);
|
||||
|
||||
@@ -27,7 +27,8 @@ class KernelMixinApplicationBuilder
|
||||
|
||||
KernelMixinApplicationBuilder(
|
||||
KernelTypeBuilder supertype, List<KernelTypeBuilder> mixins)
|
||||
: super(supertype, mixins);
|
||||
: assert(mixins != null),
|
||||
super(supertype, mixins);
|
||||
|
||||
@override
|
||||
InterfaceType build(LibraryBuilder library) {
|
||||
|
||||
@@ -32,8 +32,8 @@ import '../deprecated_problems.dart'
|
||||
|
||||
import '../fasta_codes.dart'
|
||||
show
|
||||
LocatedMessage,
|
||||
Code,
|
||||
LocatedMessage,
|
||||
Message,
|
||||
messageExpectedBlockToSkip,
|
||||
templateInternalProblemNotFound;
|
||||
@@ -56,7 +56,8 @@ import '../type_inference/type_inference_engine.dart' show TypeInferenceEngine;
|
||||
|
||||
import 'source_library_builder.dart' show SourceLibraryBuilder;
|
||||
|
||||
import 'stack_listener.dart' show FixedNullableList, NullValue, StackListener;
|
||||
import 'stack_listener.dart'
|
||||
show FixedNullableList, NullValue, ParserRecovery, StackListener;
|
||||
|
||||
import '../quote.dart' show unescapeString;
|
||||
|
||||
@@ -78,6 +79,8 @@ class DietListener extends StackListener {
|
||||
|
||||
ClassBuilder currentClass;
|
||||
|
||||
bool currentClassIsParserRecovery = false;
|
||||
|
||||
/// For top-level declarations, this is the library scope. For class members,
|
||||
/// this is the instance scope of [currentClass].
|
||||
Scope memberScope;
|
||||
@@ -95,12 +98,6 @@ class DietListener extends StackListener {
|
||||
stringExpectedAfterNative =
|
||||
library.loader.target.backendTarget.nativeExtensionExpectsString;
|
||||
|
||||
void discard(int n) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
pop();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void endMetadataStar(int count) {
|
||||
debugEvent("MetadataStar");
|
||||
@@ -235,8 +232,10 @@ class DietListener extends StackListener {
|
||||
debugEvent("FunctionTypeAlias");
|
||||
|
||||
if (equals == null) pop(); // endToken
|
||||
String name = pop();
|
||||
Object name = pop();
|
||||
Token metadata = pop();
|
||||
checkEmpty(typedefKeyword.charOffset);
|
||||
if (name is ParserRecovery) return;
|
||||
|
||||
Declaration typedefBuilder = lookupBuilder(typedefKeyword, null, name);
|
||||
parseMetadata(typedefBuilder, metadata, typedefBuilder.target);
|
||||
@@ -292,9 +291,11 @@ class DietListener extends StackListener {
|
||||
void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
|
||||
debugEvent("TopLevelMethod");
|
||||
Token bodyToken = pop();
|
||||
String name = pop();
|
||||
Object name = pop();
|
||||
Token metadata = pop();
|
||||
checkEmpty(beginToken.charOffset);
|
||||
if (name is ParserRecovery) return;
|
||||
|
||||
final StackListener listener =
|
||||
createFunctionListener(lookupBuilder(beginToken, getOrSet, name));
|
||||
buildFunctionBody(listener, bodyToken, metadata, MemberKind.TopLevelMethod);
|
||||
@@ -330,10 +331,16 @@ class DietListener extends StackListener {
|
||||
@override
|
||||
void handleQualified(Token period) {
|
||||
debugEvent("handleQualified");
|
||||
String suffix = pop();
|
||||
var prefix = pop();
|
||||
assert(identical(suffix, period.next.lexeme));
|
||||
push(new QualifiedName(prefix, period.next));
|
||||
Object suffix = pop();
|
||||
Object prefix = pop();
|
||||
if (prefix is ParserRecovery) {
|
||||
push(prefix);
|
||||
} else if (suffix is ParserRecovery) {
|
||||
push(suffix);
|
||||
} else {
|
||||
assert(identical(suffix, period.next.lexeme));
|
||||
push(new QualifiedName(prefix, period.next));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -433,9 +440,11 @@ class DietListener extends StackListener {
|
||||
@override
|
||||
void endImport(Token importKeyword, Token semicolon) {
|
||||
debugEvent("Import");
|
||||
pop(NullValue.Prefix);
|
||||
Object name = pop(NullValue.Prefix);
|
||||
|
||||
Token metadata = pop();
|
||||
checkEmpty(importKeyword.charOffset);
|
||||
if (name is ParserRecovery) return;
|
||||
|
||||
// Native imports must be skipped because they aren't assigned corresponding
|
||||
// LibraryDependency nodes.
|
||||
@@ -507,6 +516,7 @@ class DietListener extends StackListener {
|
||||
Object name = pop();
|
||||
Token metadata = pop();
|
||||
checkEmpty(beginToken.charOffset);
|
||||
if (name is ParserRecovery || currentClassIsParserRecovery) return;
|
||||
|
||||
ProcedureBuilder builder = lookupConstructor(beginToken, name);
|
||||
if (bodyToken == null || optional("=", bodyToken.endGroup.next)) {
|
||||
@@ -555,6 +565,7 @@ class DietListener extends StackListener {
|
||||
Object name = pop();
|
||||
Token metadata = pop();
|
||||
checkEmpty(beginToken.charOffset);
|
||||
if (name is ParserRecovery || currentClassIsParserRecovery) return;
|
||||
ProcedureBuilder builder;
|
||||
if (name is QualifiedName ||
|
||||
(getOrSet == null && name == currentClass.name)) {
|
||||
@@ -633,8 +644,11 @@ class DietListener extends StackListener {
|
||||
|
||||
void buildFields(int count, Token token, bool isTopLevel) {
|
||||
List<String> names = const FixedNullableList<String>().pop(stack, count);
|
||||
Declaration declaration = lookupBuilder(token, null, names.first);
|
||||
Token metadata = pop();
|
||||
checkEmpty(token.charOffset);
|
||||
if (names == null || currentClassIsParserRecovery) return;
|
||||
|
||||
Declaration declaration = lookupBuilder(token, null, names.first);
|
||||
// TODO(paulberry): don't re-parse the field if we've already parsed it
|
||||
// for type inference.
|
||||
parseFields(
|
||||
@@ -642,6 +656,7 @@ class DietListener extends StackListener {
|
||||
token,
|
||||
metadata,
|
||||
isTopLevel);
|
||||
checkEmpty(token.charOffset);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -665,11 +680,15 @@ class DietListener extends StackListener {
|
||||
|
||||
@override
|
||||
void beginClassOrMixinBody(Token token) {
|
||||
debugEvent("beginClassBody");
|
||||
String name = pop();
|
||||
debugEvent("beginClassOrMixinBody");
|
||||
Object name = pop();
|
||||
Token metadata = pop();
|
||||
assert(currentClass == null);
|
||||
assert(memberScope == library.scope);
|
||||
if (name is ParserRecovery) {
|
||||
currentClassIsParserRecovery = true;
|
||||
return;
|
||||
}
|
||||
|
||||
Declaration classBuilder = lookupBuilder(token, null, name);
|
||||
parseMetadata(classBuilder, metadata, classBuilder.target);
|
||||
@@ -682,6 +701,7 @@ class DietListener extends StackListener {
|
||||
void endClassOrMixinBody(int memberCount, Token beginToken, Token endToken) {
|
||||
debugEvent("ClassOrMixinBody");
|
||||
currentClass = null;
|
||||
currentClassIsParserRecovery = false;
|
||||
memberScope = library.scope;
|
||||
}
|
||||
|
||||
@@ -702,8 +722,10 @@ class DietListener extends StackListener {
|
||||
debugEvent("Enum");
|
||||
List<Object> metadataAndValues =
|
||||
const FixedNullableList<Object>().pop(stack, count * 2);
|
||||
String name = pop();
|
||||
Object name = pop();
|
||||
Token metadata = pop();
|
||||
checkEmpty(enumKeyword.charOffset);
|
||||
if (name is ParserRecovery) return;
|
||||
|
||||
ClassBuilder enumBuilder = lookupBuilder(enumKeyword, null, name);
|
||||
parseMetadata(enumBuilder, metadata, enumBuilder.target);
|
||||
@@ -726,13 +748,20 @@ class DietListener extends StackListener {
|
||||
Token equals, Token implementsKeyword, Token endToken) {
|
||||
debugEvent("NamedMixinApplication");
|
||||
|
||||
String name = pop();
|
||||
Object name = pop();
|
||||
Token metadata = pop();
|
||||
|
||||
Declaration classBuilder = lookupBuilder(classKeyword, null, name);
|
||||
parseMetadata(classBuilder, metadata, classBuilder.target);
|
||||
|
||||
checkEmpty(beginToken.charOffset);
|
||||
if (name is ParserRecovery) return;
|
||||
|
||||
Declaration classBuilder = library.scopeBuilder[name];
|
||||
if (classBuilder != null) {
|
||||
// TODO(ahe): We shouldn't have to check for null here. The problem is
|
||||
// that we don't create a named mixin application if the mixins or
|
||||
// supertype are missing. Could we create a class instead? The nested
|
||||
// declarations wouldn't match up.
|
||||
parseMetadata(classBuilder, metadata, classBuilder.target);
|
||||
checkEmpty(beginToken.charOffset);
|
||||
}
|
||||
}
|
||||
|
||||
AsyncMarker getAsyncMarker(StackListener listener) => listener.pop();
|
||||
|
||||
@@ -87,7 +87,8 @@ import '../scanner.dart' show Token;
|
||||
|
||||
import 'source_library_builder.dart' show FieldInfo, SourceLibraryBuilder;
|
||||
|
||||
import 'stack_listener.dart' show FixedNullableList, NullValue, StackListener;
|
||||
import 'stack_listener.dart'
|
||||
show FixedNullableList, NullValue, ParserRecovery, StackListener;
|
||||
|
||||
enum MethodBody {
|
||||
Abstract,
|
||||
@@ -120,12 +121,18 @@ class OutlineBuilder extends StackListener {
|
||||
|
||||
List<String> popIdentifierList(int count) {
|
||||
if (count == 0) return null;
|
||||
List<String> list = new List<String>.filled(count, null, growable: true);
|
||||
List<String> list = new List<String>(count);
|
||||
bool isParserRecovery = false;
|
||||
for (int i = count - 1; i >= 0; i--) {
|
||||
popCharOffset();
|
||||
list[i] = pop();
|
||||
Object identifier = pop();
|
||||
if (identifier is ParserRecovery) {
|
||||
isParserRecovery = true;
|
||||
} else {
|
||||
list[i] = identifier;
|
||||
}
|
||||
}
|
||||
return list;
|
||||
return isParserRecovery ? null : list;
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -143,12 +150,16 @@ class OutlineBuilder extends StackListener {
|
||||
} else {
|
||||
int charOffset = pop();
|
||||
Object typeName = pop();
|
||||
push(new MetadataBuilder.fromConstructor(
|
||||
library.addConstructorReference(
|
||||
typeName, typeArguments, postfix, charOffset),
|
||||
arguments,
|
||||
library,
|
||||
beginToken.charOffset));
|
||||
if (typeName is ParserRecovery) {
|
||||
push(typeName);
|
||||
} else {
|
||||
push(new MetadataBuilder.fromConstructor(
|
||||
library.addConstructorReference(
|
||||
typeName, typeArguments, postfix, charOffset),
|
||||
arguments,
|
||||
library,
|
||||
beginToken.charOffset));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,15 +180,23 @@ class OutlineBuilder extends StackListener {
|
||||
@override
|
||||
void endHide(Token hideKeyword) {
|
||||
debugEvent("Hide");
|
||||
List<String> names = pop();
|
||||
push(new Combinator.hide(names, hideKeyword.charOffset, library.fileUri));
|
||||
Object names = pop();
|
||||
if (names is ParserRecovery) {
|
||||
push(names);
|
||||
} else {
|
||||
push(new Combinator.hide(names, hideKeyword.charOffset, library.fileUri));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void endShow(Token showKeyword) {
|
||||
debugEvent("Show");
|
||||
List<String> names = pop();
|
||||
push(new Combinator.show(names, showKeyword.charOffset, library.fileUri));
|
||||
Object names = pop();
|
||||
if (names is ParserRecovery) {
|
||||
push(names);
|
||||
} else {
|
||||
push(new Combinator.show(names, showKeyword.charOffset, library.fileUri));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -218,11 +237,13 @@ class OutlineBuilder extends StackListener {
|
||||
List<Combinator> combinators = pop();
|
||||
bool isDeferred = pop();
|
||||
int prefixOffset = pop();
|
||||
String prefix = pop(NullValue.Prefix);
|
||||
Object prefix = pop(NullValue.Prefix);
|
||||
List<Configuration> configurations = pop();
|
||||
int uriOffset = popCharOffset();
|
||||
String uri = pop(); // For a conditional import, this is the default URI.
|
||||
List<MetadataBuilder> metadata = pop();
|
||||
checkEmpty(importKeyword.charOffset);
|
||||
if (prefix is ParserRecovery) return;
|
||||
library.addImport(
|
||||
metadata,
|
||||
uri,
|
||||
@@ -234,7 +255,6 @@ class OutlineBuilder extends StackListener {
|
||||
prefixOffset,
|
||||
uriOffset,
|
||||
importIndex++);
|
||||
checkEmpty(importKeyword.charOffset);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -251,14 +271,23 @@ class OutlineBuilder extends StackListener {
|
||||
String uri = pop();
|
||||
if (equalSign != null) popCharOffset();
|
||||
String condition = popIfNotNull(equalSign) ?? "true";
|
||||
String dottedName = pop();
|
||||
push(new Configuration(charOffset, dottedName, condition, uri));
|
||||
Object dottedName = pop();
|
||||
if (dottedName is ParserRecovery) {
|
||||
push(dottedName);
|
||||
} else {
|
||||
push(new Configuration(charOffset, dottedName, condition, uri));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void handleDottedName(int count, Token firstIdentifier) {
|
||||
debugEvent("DottedName");
|
||||
push(popIdentifierList(count).join('.'));
|
||||
List<String> names = popIdentifierList(count);
|
||||
if (names == null) {
|
||||
push(new ParserRecovery(firstIdentifier.charOffset));
|
||||
} else {
|
||||
push(names.join('.'));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -300,8 +329,12 @@ class OutlineBuilder extends StackListener {
|
||||
if (context == IdentifierContext.enumValueDeclaration) {
|
||||
debugEvent("handleIdentifier");
|
||||
List<MetadataBuilder> metadata = pop();
|
||||
push(new EnumConstantInfo(metadata, token.lexeme, token.charOffset,
|
||||
getDocumentationComment(token)));
|
||||
if (token.isSynthetic) {
|
||||
push(new ParserRecovery(token.charOffset));
|
||||
} else {
|
||||
push(new EnumConstantInfo(metadata, token.lexeme, token.charOffset,
|
||||
getDocumentationComment(token)));
|
||||
}
|
||||
} else {
|
||||
super.handleIdentifier(token, context);
|
||||
push(token.charOffset);
|
||||
@@ -347,7 +380,12 @@ class OutlineBuilder extends StackListener {
|
||||
if (hasName) {
|
||||
// Pop the native clause which in this case is a StringLiteral.
|
||||
pop(); // Char offset.
|
||||
nativeMethodName = pop(); // String.
|
||||
Object name = pop();
|
||||
if (name is ParserRecovery) {
|
||||
nativeMethodName = '';
|
||||
} else {
|
||||
nativeMethodName = name; // String.
|
||||
}
|
||||
} else {
|
||||
nativeMethodName = '';
|
||||
}
|
||||
@@ -369,19 +407,26 @@ class OutlineBuilder extends StackListener {
|
||||
@override
|
||||
void handleIdentifierList(int count) {
|
||||
debugEvent("endIdentifierList");
|
||||
push(popIdentifierList(count) ?? NullValue.IdentifierList);
|
||||
push(popIdentifierList(count) ??
|
||||
(count == 0 ? NullValue.IdentifierList : new ParserRecovery(-1)));
|
||||
}
|
||||
|
||||
@override
|
||||
void handleQualified(Token period) {
|
||||
debugEvent("handleQualified");
|
||||
int suffixOffset = pop();
|
||||
String suffix = pop();
|
||||
assert(identical(suffix, period.next.lexeme));
|
||||
assert(suffixOffset == period.next.charOffset);
|
||||
Object suffix = pop();
|
||||
int offset = pop();
|
||||
var prefix = pop();
|
||||
push(new QualifiedName(prefix, period.next));
|
||||
Object prefix = pop();
|
||||
if (prefix is ParserRecovery) {
|
||||
push(prefix);
|
||||
} else if (suffix is ParserRecovery) {
|
||||
push(suffix);
|
||||
} else {
|
||||
assert(identical(suffix, period.next.lexeme));
|
||||
assert(suffixOffset == period.next.charOffset);
|
||||
push(new QualifiedName(prefix, period.next));
|
||||
}
|
||||
push(offset);
|
||||
}
|
||||
|
||||
@@ -393,7 +438,9 @@ class OutlineBuilder extends StackListener {
|
||||
Object name = pop();
|
||||
List<MetadataBuilder> metadata = pop();
|
||||
library.documentationComment = documentationComment;
|
||||
library.name = flattenName(name, offsetForToken(libraryKeyword), uri);
|
||||
if (name is! ParserRecovery) {
|
||||
library.name = flattenName(name, offsetForToken(libraryKeyword), uri);
|
||||
}
|
||||
library.metadata = metadata;
|
||||
}
|
||||
|
||||
@@ -474,7 +521,7 @@ class OutlineBuilder extends StackListener {
|
||||
debugEvent("handleMixinOn");
|
||||
push(const FixedNullableList<KernelNamedTypeBuilder>()
|
||||
.pop(stack, typeCount) ??
|
||||
NullValue.TypeList);
|
||||
new ParserRecovery(offsetForToken(onKeyword)));
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -483,15 +530,20 @@ class OutlineBuilder extends StackListener {
|
||||
String documentationComment = getDocumentationComment(beginToken);
|
||||
List<TypeBuilder> interfaces = pop(NullValue.TypeBuilderList);
|
||||
int supertypeOffset = pop();
|
||||
TypeBuilder supertype = pop();
|
||||
TypeBuilder supertype = nullIfParserRecovery(pop());
|
||||
int modifiers = pop();
|
||||
List<TypeVariableBuilder> typeVariables = pop();
|
||||
int charOffset = pop();
|
||||
String name = pop();
|
||||
Object name = pop();
|
||||
if (typeVariables != null && supertype is MixinApplicationBuilder) {
|
||||
supertype.typeVariables = typeVariables;
|
||||
}
|
||||
List<MetadataBuilder> metadata = pop();
|
||||
checkEmpty(beginToken.charOffset);
|
||||
if (name is ParserRecovery) {
|
||||
library.endNestedDeclaration("<syntax-error>");
|
||||
return;
|
||||
}
|
||||
|
||||
final int startCharOffset =
|
||||
metadata == null ? beginToken.charOffset : metadata.first.charOffset;
|
||||
@@ -508,7 +560,10 @@ class OutlineBuilder extends StackListener {
|
||||
charOffset,
|
||||
endToken.charOffset,
|
||||
supertypeOffset);
|
||||
checkEmpty(beginToken.charOffset);
|
||||
}
|
||||
|
||||
Object nullIfParserRecovery(Object node) {
|
||||
return node is ParserRecovery ? null : node;
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -516,14 +571,18 @@ class OutlineBuilder extends StackListener {
|
||||
debugEvent("endMixinDeclaration");
|
||||
String documentationComment = getDocumentationComment(mixinToken);
|
||||
List<TypeBuilder> interfaces = pop(NullValue.TypeBuilderList);
|
||||
List<KernelTypeBuilder> supertypeConstraints = pop();
|
||||
List<KernelTypeBuilder> supertypeConstraints = nullIfParserRecovery(pop());
|
||||
List<TypeVariableBuilder> typeVariables = pop(NullValue.TypeVariables);
|
||||
int nameOffset = pop();
|
||||
String name = pop();
|
||||
Object name = pop();
|
||||
List<MetadataBuilder> metadata = pop(NullValue.Metadata);
|
||||
checkEmpty(mixinToken.charOffset);
|
||||
if (name is ParserRecovery) {
|
||||
library.endNestedDeclaration("<syntax-error>");
|
||||
return;
|
||||
}
|
||||
int startOffset =
|
||||
metadata == null ? mixinToken.charOffset : metadata.first.charOffset;
|
||||
|
||||
TypeBuilder supertype;
|
||||
if (supertypeConstraints != null && supertypeConstraints.isNotEmpty) {
|
||||
if (supertypeConstraints.length == 1) {
|
||||
@@ -545,7 +604,6 @@ class OutlineBuilder extends StackListener {
|
||||
nameOffset,
|
||||
endToken.charOffset,
|
||||
-1);
|
||||
checkEmpty(mixinToken.charOffset);
|
||||
}
|
||||
|
||||
ProcedureKind computeProcedureKind(Token token) {
|
||||
@@ -570,7 +628,7 @@ class OutlineBuilder extends StackListener {
|
||||
int formalsOffset = pop();
|
||||
List<TypeVariableBuilder> typeVariables = pop();
|
||||
int charOffset = pop();
|
||||
String name = pop();
|
||||
Object name = pop();
|
||||
TypeBuilder returnType = pop();
|
||||
bool isAbstract = kind == MethodBody.Abstract;
|
||||
if (getOrSet != null && optional("set", getOrSet)) {
|
||||
@@ -585,13 +643,14 @@ class OutlineBuilder extends StackListener {
|
||||
modifiers |= abstractMask;
|
||||
}
|
||||
List<MetadataBuilder> metadata = pop();
|
||||
String documentationComment = getDocumentationComment(beginToken);
|
||||
checkEmpty(beginToken.charOffset);
|
||||
library
|
||||
.endNestedDeclaration("#method")
|
||||
.resolveTypes(typeVariables, library);
|
||||
if (name is ParserRecovery) return;
|
||||
final int startCharOffset =
|
||||
metadata == null ? beginToken.charOffset : metadata.first.charOffset;
|
||||
String documentationComment = getDocumentationComment(beginToken);
|
||||
library.addProcedure(
|
||||
documentationComment,
|
||||
metadata,
|
||||
@@ -655,8 +714,9 @@ class OutlineBuilder extends StackListener {
|
||||
Token varFinalOrConst, Token getOrSet, Token name) {
|
||||
inConstructor =
|
||||
name?.lexeme == library.currentDeclaration.name && getOrSet == null;
|
||||
List<Modifier> modifiers = <Modifier>[];
|
||||
List<Modifier> modifiers;
|
||||
if (externalToken != null) {
|
||||
modifiers ??= <Modifier>[];
|
||||
modifiers.add(External);
|
||||
}
|
||||
if (staticToken != null) {
|
||||
@@ -664,24 +724,29 @@ class OutlineBuilder extends StackListener {
|
||||
handleRecoverableError(
|
||||
messageStaticConstructor, staticToken, staticToken);
|
||||
} else {
|
||||
modifiers ??= <Modifier>[];
|
||||
modifiers.add(Static);
|
||||
}
|
||||
}
|
||||
if (covariantToken != null) {
|
||||
modifiers ??= <Modifier>[];
|
||||
modifiers.add(Covariant);
|
||||
}
|
||||
if (varFinalOrConst != null) {
|
||||
String lexeme = varFinalOrConst.lexeme;
|
||||
if (identical('var', lexeme)) {
|
||||
modifiers ??= <Modifier>[];
|
||||
modifiers.add(Var);
|
||||
} else if (identical('final', lexeme)) {
|
||||
modifiers ??= <Modifier>[];
|
||||
modifiers.add(Final);
|
||||
} else {
|
||||
modifiers ??= <Modifier>[];
|
||||
modifiers.add(Const);
|
||||
}
|
||||
}
|
||||
push(varFinalOrConst?.charOffset ?? -1);
|
||||
push(modifiers);
|
||||
push(modifiers ?? NullValue.Modifiers);
|
||||
library.beginNestedDeclaration("#method", hasMembers: false);
|
||||
}
|
||||
|
||||
@@ -698,7 +763,7 @@ class OutlineBuilder extends StackListener {
|
||||
int formalsOffset = pop();
|
||||
List<TypeVariableBuilder> typeVariables = pop();
|
||||
int charOffset = pop();
|
||||
dynamic nameOrOperator = pop();
|
||||
Object nameOrOperator = pop();
|
||||
if (Operator.subtract == nameOrOperator && formals == null) {
|
||||
nameOrOperator = Operator.unaryMinus;
|
||||
}
|
||||
@@ -767,6 +832,11 @@ class OutlineBuilder extends StackListener {
|
||||
library
|
||||
.endNestedDeclaration("#method")
|
||||
.resolveTypes(typeVariables, library);
|
||||
if (name is ParserRecovery) {
|
||||
nativeMethodName = null;
|
||||
inConstructor = false;
|
||||
return;
|
||||
}
|
||||
String constructorName =
|
||||
kind == ProcedureKind.Getter || kind == ProcedureKind.Setter
|
||||
? null
|
||||
@@ -828,10 +898,16 @@ class OutlineBuilder extends StackListener {
|
||||
@override
|
||||
void handleNamedMixinApplicationWithClause(Token withKeyword) {
|
||||
debugEvent("NamedMixinApplicationWithClause");
|
||||
List<TypeBuilder> mixins = pop();
|
||||
TypeBuilder supertype = pop();
|
||||
push(
|
||||
library.addMixinApplication(supertype, mixins, withKeyword.charOffset));
|
||||
Object mixins = pop();
|
||||
Object supertype = pop();
|
||||
if (mixins is ParserRecovery) {
|
||||
push(mixins);
|
||||
} else if (supertype is ParserRecovery) {
|
||||
push(supertype);
|
||||
} else {
|
||||
push(library.addMixinApplication(
|
||||
supertype, mixins, withKeyword.charOffset));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -840,15 +916,19 @@ class OutlineBuilder extends StackListener {
|
||||
debugEvent("endNamedMixinApplication");
|
||||
String documentationComment = getDocumentationComment(beginToken);
|
||||
List<TypeBuilder> interfaces = popIfNotNull(implementsKeyword);
|
||||
TypeBuilder mixinApplication = pop();
|
||||
Object mixinApplication = pop();
|
||||
int modifiers = pop();
|
||||
List<TypeVariableBuilder> typeVariables = pop();
|
||||
int charOffset = pop();
|
||||
String name = pop();
|
||||
Object name = pop();
|
||||
List<MetadataBuilder> metadata = pop();
|
||||
checkEmpty(beginToken.charOffset);
|
||||
if (name is ParserRecovery || mixinApplication is ParserRecovery) {
|
||||
library.endNestedDeclaration("<syntax-error>");
|
||||
return;
|
||||
}
|
||||
library.addNamedMixinApplication(documentationComment, metadata, name,
|
||||
typeVariables, modifiers, mixinApplication, interfaces, charOffset);
|
||||
checkEmpty(beginToken.charOffset);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -869,14 +949,18 @@ class OutlineBuilder extends StackListener {
|
||||
List<TypeBuilder> arguments = pop();
|
||||
int charOffset = pop();
|
||||
Object name = pop();
|
||||
push(library.addNamedType(name, arguments, charOffset));
|
||||
if (name is ParserRecovery) {
|
||||
push(name);
|
||||
} else {
|
||||
push(library.addNamedType(name, arguments, charOffset));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void endTypeList(int count) {
|
||||
debugEvent("TypeList");
|
||||
push(const FixedNullableList<KernelNamedTypeBuilder>().pop(stack, count) ??
|
||||
NullValue.TypeList);
|
||||
new ParserRecovery(-1));
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -903,12 +987,16 @@ class OutlineBuilder extends StackListener {
|
||||
Token nameToken, FormalParameterKind kind, MemberKind memberKind) {
|
||||
debugEvent("FormalParameter");
|
||||
int charOffset = pop();
|
||||
String name = pop();
|
||||
TypeBuilder type = pop();
|
||||
Object name = pop();
|
||||
TypeBuilder type = nullIfParserRecovery(pop());
|
||||
int modifiers = pop();
|
||||
List<MetadataBuilder> metadata = pop();
|
||||
push(library.addFormalParameter(
|
||||
metadata, modifiers, type, name, thisKeyword != null, charOffset));
|
||||
if (name is ParserRecovery) {
|
||||
push(name);
|
||||
} else {
|
||||
push(library.addFormalParameter(
|
||||
metadata, modifiers, type, name, thisKeyword != null, charOffset));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -946,12 +1034,15 @@ class OutlineBuilder extends StackListener {
|
||||
// case, however, then [beginOptionalFormalParameters] wouldn't always be
|
||||
// matched by this method.
|
||||
List<FormalParameterBuilder> parameters =
|
||||
const FixedNullableList<FormalParameterBuilder>().pop(stack, count) ??
|
||||
new List<FormalParameterBuilder>(0);
|
||||
for (FormalParameterBuilder parameter in parameters) {
|
||||
parameter.kind = kind;
|
||||
const FixedNullableList<FormalParameterBuilder>().pop(stack, count);
|
||||
if (parameters == null) {
|
||||
push(new ParserRecovery(offsetForToken(beginToken)));
|
||||
} else {
|
||||
for (FormalParameterBuilder parameter in parameters) {
|
||||
parameter.kind = kind;
|
||||
}
|
||||
push(parameters);
|
||||
}
|
||||
push(parameters);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -963,7 +1054,7 @@ class OutlineBuilder extends StackListener {
|
||||
Object last = pop();
|
||||
if (last is List<FormalParameterBuilder>) {
|
||||
formals = last;
|
||||
} else {
|
||||
} else if (last is! ParserRecovery) {
|
||||
assert(last != null);
|
||||
formals = new List<FormalParameterBuilder>(1);
|
||||
formals[0] = last;
|
||||
@@ -971,7 +1062,9 @@ class OutlineBuilder extends StackListener {
|
||||
} else if (count > 1) {
|
||||
Object last = pop();
|
||||
count--;
|
||||
if (last is List<FormalParameterBuilder>) {
|
||||
if (last is ParserRecovery) {
|
||||
discard(count);
|
||||
} else if (last is List<FormalParameterBuilder>) {
|
||||
formals = const FixedNullableList<FormalParameterBuilder>()
|
||||
.popPadded(stack, count, last.length);
|
||||
if (formals != null) {
|
||||
@@ -979,13 +1072,14 @@ class OutlineBuilder extends StackListener {
|
||||
}
|
||||
} else {
|
||||
formals = const FixedNullableList<FormalParameterBuilder>()
|
||||
.popPadded(stack, count, last == null ? 0 : 1);
|
||||
if (formals != null && last != null) {
|
||||
.popPadded(stack, count, 1);
|
||||
if (formals != null) {
|
||||
formals[count] = last;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (formals != null) {
|
||||
assert(formals.isNotEmpty);
|
||||
if (formals.length == 2) {
|
||||
// The name may be null for generalized function types.
|
||||
if (formals[0].name != null && formals[0].name == formals[1].name) {
|
||||
@@ -1046,11 +1140,12 @@ class OutlineBuilder extends StackListener {
|
||||
List<EnumConstantInfo> enumConstantInfos =
|
||||
const FixedNullableList<EnumConstantInfo>().pop(stack, count);
|
||||
int charOffset = pop();
|
||||
String name = pop();
|
||||
Object name = pop();
|
||||
List<MetadataBuilder> metadata = pop();
|
||||
checkEmpty(enumKeyword.charOffset);
|
||||
if (name is ParserRecovery) return;
|
||||
library.addEnum(documentationComment, metadata, name, enumConstantInfos,
|
||||
charOffset, leftBrace?.endGroup?.charOffset);
|
||||
checkEmpty(enumKeyword.charOffset);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1098,7 +1193,7 @@ class OutlineBuilder extends StackListener {
|
||||
debugEvent("endFunctionTypeAlias");
|
||||
String documentationComment = getDocumentationComment(typedefKeyword);
|
||||
List<TypeVariableBuilder> typeVariables;
|
||||
String name;
|
||||
Object name;
|
||||
int charOffset;
|
||||
FunctionTypeBuilder functionType;
|
||||
if (equals == null) {
|
||||
@@ -1110,6 +1205,11 @@ class OutlineBuilder extends StackListener {
|
||||
TypeBuilder returnType = pop();
|
||||
// Create a nested declaration that is ended below by
|
||||
// `library.addFunctionType`.
|
||||
if (name is ParserRecovery) {
|
||||
pop(); // Metadata.
|
||||
library.endNestedDeclaration("<syntax-error>");
|
||||
return;
|
||||
}
|
||||
library.beginNestedDeclaration("#function_type", hasMembers: false);
|
||||
functionType =
|
||||
library.addFunctionType(returnType, null, formals, charOffset);
|
||||
@@ -1118,6 +1218,11 @@ class OutlineBuilder extends StackListener {
|
||||
typeVariables = pop();
|
||||
charOffset = pop();
|
||||
name = pop();
|
||||
if (name is ParserRecovery) {
|
||||
pop(); // Metadata.
|
||||
library.endNestedDeclaration("<syntax-error>");
|
||||
return;
|
||||
}
|
||||
if (type is FunctionTypeBuilder) {
|
||||
// TODO(ahe): We need to start a nested declaration when parsing the
|
||||
// formals and return type so we can correctly bind
|
||||
@@ -1131,9 +1236,9 @@ class OutlineBuilder extends StackListener {
|
||||
}
|
||||
}
|
||||
List<MetadataBuilder> metadata = pop();
|
||||
checkEmpty(typedefKeyword.charOffset);
|
||||
library.addFunctionTypeAlias(documentationComment, metadata, name,
|
||||
typeVariables, functionType, charOffset);
|
||||
checkEmpty(typedefKeyword.charOffset);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1141,15 +1246,16 @@ class OutlineBuilder extends StackListener {
|
||||
Token varFinalOrConst, int count, Token beginToken, Token endToken) {
|
||||
debugEvent("endTopLevelFields");
|
||||
List<FieldInfo> fieldInfos = popFieldInfos(count);
|
||||
TypeBuilder type = pop();
|
||||
TypeBuilder type = nullIfParserRecovery(pop());
|
||||
int modifiers = (staticToken != null ? staticMask : 0) |
|
||||
(covariantToken != null ? covariantMask : 0) |
|
||||
Modifier.validateVarFinalOrConst(varFinalOrConst?.lexeme);
|
||||
List<MetadataBuilder> metadata = pop();
|
||||
checkEmpty(beginToken.charOffset);
|
||||
if (fieldInfos == null) return;
|
||||
String documentationComment = getDocumentationComment(beginToken);
|
||||
library.addFields(
|
||||
documentationComment, metadata, modifiers, type, fieldInfos);
|
||||
checkEmpty(beginToken.charOffset);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1169,6 +1275,7 @@ class OutlineBuilder extends StackListener {
|
||||
modifiers &= ~constMask;
|
||||
}
|
||||
List<MetadataBuilder> metadata = pop();
|
||||
if (fieldInfos == null) return;
|
||||
String documentationComment = getDocumentationComment(beginToken);
|
||||
library.addFields(
|
||||
documentationComment, metadata, modifiers, type, fieldInfos);
|
||||
@@ -1177,44 +1284,54 @@ class OutlineBuilder extends StackListener {
|
||||
List<FieldInfo> popFieldInfos(int count) {
|
||||
if (count == 0) return null;
|
||||
List<FieldInfo> fieldInfos = new List<FieldInfo>(count);
|
||||
bool isParserRecovery = false;
|
||||
for (int i = count - 1; i != -1; i--) {
|
||||
Token beforeLast = pop();
|
||||
Token initializerTokenForInference = pop();
|
||||
int charOffset = pop();
|
||||
Object name = pop(NullValue.Identifier);
|
||||
fieldInfos[i] = new FieldInfo(
|
||||
name, charOffset, initializerTokenForInference, beforeLast);
|
||||
if (name is ParserRecovery) {
|
||||
isParserRecovery = true;
|
||||
} else {
|
||||
fieldInfos[i] = new FieldInfo(
|
||||
name, charOffset, initializerTokenForInference, beforeLast);
|
||||
}
|
||||
}
|
||||
return fieldInfos;
|
||||
return isParserRecovery ? null : fieldInfos;
|
||||
}
|
||||
|
||||
@override
|
||||
void beginTypeVariable(Token token) {
|
||||
debugEvent("beginTypeVariable");
|
||||
int charOffset = pop();
|
||||
String name = pop();
|
||||
Object name = pop();
|
||||
// TODO(paulberry): type variable metadata should not be ignored. See
|
||||
// dartbug.com/28981.
|
||||
/* List<MetadataBuilder> metadata = */ pop();
|
||||
|
||||
push(library.addTypeVariable(name, null, charOffset));
|
||||
if (name is ParserRecovery) {
|
||||
push(name);
|
||||
} else {
|
||||
push(library.addTypeVariable(name, null, charOffset));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void handleTypeVariablesDefined(Token token, int count) {
|
||||
debugEvent("TypeVariablesDefined");
|
||||
assert(count > 0);
|
||||
push(const FixedNullableList<TypeVariableBuilder>().pop(stack, count));
|
||||
push(const FixedNullableList<TypeVariableBuilder>().pop(stack, count) ??
|
||||
NullValue.TypeVariables);
|
||||
}
|
||||
|
||||
@override
|
||||
void endTypeVariable(Token token, int index, Token extendsOrSuper) {
|
||||
debugEvent("endTypeVariable");
|
||||
TypeBuilder bound = pop();
|
||||
TypeBuilder bound = nullIfParserRecovery(pop());
|
||||
// Peek to leave type parameters on top of stack.
|
||||
List typeParameters = peek();
|
||||
|
||||
typeParameters[index].bound = bound;
|
||||
List<TypeVariableBuilder> typeParameters = peek();
|
||||
if (typeParameters != null) {
|
||||
typeParameters[index].bound = bound;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1222,48 +1339,50 @@ class OutlineBuilder extends StackListener {
|
||||
debugEvent("endTypeVariables");
|
||||
|
||||
// Peek to leave type parameters on top of stack.
|
||||
List typeParameters = peek();
|
||||
List<TypeVariableBuilder> typeParameters = peek();
|
||||
|
||||
Map<String, TypeVariableBuilder> typeVariablesByName;
|
||||
for (TypeVariableBuilder builder in typeParameters) {
|
||||
if (builder.bound != null) {
|
||||
if (typeVariablesByName == null) {
|
||||
typeVariablesByName = new Map<String, TypeVariableBuilder>();
|
||||
for (TypeVariableBuilder builder in typeParameters) {
|
||||
typeVariablesByName[builder.name] = builder;
|
||||
if (typeParameters != null) {
|
||||
for (TypeVariableBuilder builder in typeParameters) {
|
||||
if (builder.bound != null) {
|
||||
if (typeVariablesByName == null) {
|
||||
typeVariablesByName = new Map<String, TypeVariableBuilder>();
|
||||
for (TypeVariableBuilder builder in typeParameters) {
|
||||
typeVariablesByName[builder.name] = builder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find cycle: If there's no cycle we can at most step through all
|
||||
// `typeParameters` (at which point the last builders bound will be
|
||||
// null).
|
||||
// If there is a cycle with `builder` 'inside' the steps to get back to
|
||||
// it will also be bound by `typeParameters.length`.
|
||||
// If there is a cycle without `builder` 'inside' we will just ignore it
|
||||
// for now. It will be reported when processing one of the `builder`s
|
||||
// that is in fact `inside` the cycle. This matches the cyclic class
|
||||
// hierarchy error.
|
||||
TypeVariableBuilder bound = builder;
|
||||
for (int steps = 0;
|
||||
bound.bound != null && steps < typeParameters.length;
|
||||
++steps) {
|
||||
bound = typeVariablesByName[bound.bound.name];
|
||||
if (bound == null || bound == builder) break;
|
||||
}
|
||||
if (bound == builder && bound.bound != null) {
|
||||
// Write out cycle.
|
||||
List<String> via = new List<String>();
|
||||
bound = typeVariablesByName[builder.bound.name];
|
||||
while (bound != builder) {
|
||||
via.add(bound.name);
|
||||
// Find cycle: If there's no cycle we can at most step through all
|
||||
// `typeParameters` (at which point the last builders bound will be
|
||||
// null).
|
||||
// If there is a cycle with `builder` 'inside' the steps to get back to
|
||||
// it will also be bound by `typeParameters.length`.
|
||||
// If there is a cycle without `builder` 'inside' we will just ignore it
|
||||
// for now. It will be reported when processing one of the `builder`s
|
||||
// that is in fact `inside` the cycle. This matches the cyclic class
|
||||
// hierarchy error.
|
||||
TypeVariableBuilder bound = builder;
|
||||
for (int steps = 0;
|
||||
bound.bound != null && steps < typeParameters.length;
|
||||
++steps) {
|
||||
bound = typeVariablesByName[bound.bound.name];
|
||||
if (bound == null || bound == builder) break;
|
||||
}
|
||||
if (bound == builder && bound.bound != null) {
|
||||
// Write out cycle.
|
||||
List<String> via = new List<String>();
|
||||
bound = typeVariablesByName[builder.bound.name];
|
||||
while (bound != builder) {
|
||||
via.add(bound.name);
|
||||
bound = typeVariablesByName[bound.bound.name];
|
||||
}
|
||||
String involvedString = via.join("', '");
|
||||
addProblem(
|
||||
templateCycleInTypeVariables.withArguments(
|
||||
builder.name, involvedString),
|
||||
builder.charOffset,
|
||||
builder.name.length);
|
||||
}
|
||||
String involvedString = via.join("', '");
|
||||
addProblem(
|
||||
templateCycleInTypeVariables.withArguments(
|
||||
builder.name, involvedString),
|
||||
builder.charOffset,
|
||||
builder.name.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1299,8 +1418,12 @@ class OutlineBuilder extends StackListener {
|
||||
List<TypeBuilder> typeArguments = pop();
|
||||
int charOffset = pop();
|
||||
Object name = pop();
|
||||
push(library.addConstructorReference(
|
||||
name, typeArguments, suffix, charOffset));
|
||||
if (name is ParserRecovery) {
|
||||
push(name);
|
||||
} else {
|
||||
push(library.addConstructorReference(
|
||||
name, typeArguments, suffix, charOffset));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1319,7 +1442,7 @@ class OutlineBuilder extends StackListener {
|
||||
MethodBody kind = pop();
|
||||
ConstructorReferenceBuilder redirectionTarget;
|
||||
if (kind == MethodBody.RedirectingFactoryBody) {
|
||||
redirectionTarget = pop();
|
||||
redirectionTarget = nullIfParserRecovery(pop());
|
||||
}
|
||||
List<FormalParameterBuilder> formals = pop();
|
||||
int formalsOffset = pop();
|
||||
@@ -1328,6 +1451,10 @@ class OutlineBuilder extends StackListener {
|
||||
Object name = pop();
|
||||
int modifiers = pop();
|
||||
List<MetadataBuilder> metadata = pop();
|
||||
if (name is ParserRecovery) {
|
||||
library.endNestedDeclaration("<syntax-error>");
|
||||
return;
|
||||
}
|
||||
String documentationComment = getDocumentationComment(beginToken);
|
||||
library.addFactoryMethod(
|
||||
documentationComment,
|
||||
@@ -1405,12 +1532,15 @@ class OutlineBuilder extends StackListener {
|
||||
void handleClassWithClause(Token withKeyword) {
|
||||
debugEvent("ClassWithClause");
|
||||
|
||||
List<TypeBuilder> mixins = pop();
|
||||
Object mixins = pop();
|
||||
int extendsOffset = pop();
|
||||
TypeBuilder supertype = pop();
|
||||
|
||||
push(
|
||||
library.addMixinApplication(supertype, mixins, withKeyword.charOffset));
|
||||
Object supertype = pop();
|
||||
if (supertype is ParserRecovery || mixins is ParserRecovery) {
|
||||
push(new ParserRecovery(withKeyword.charOffset));
|
||||
} else {
|
||||
push(library.addMixinApplication(
|
||||
supertype, mixins, withKeyword.charOffset));
|
||||
}
|
||||
push(extendsOffset);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@ import '../scope.dart' show Scope;
|
||||
|
||||
import 'stack_listener.dart' show NullValue, StackListener;
|
||||
|
||||
export 'stack_listener.dart' show FixedNullableList, GrowableList, NullValue;
|
||||
export 'stack_listener.dart'
|
||||
show FixedNullableList, GrowableList, NullValue, ParserRecovery;
|
||||
|
||||
enum JumpTargetKind {
|
||||
Break,
|
||||
|
||||
@@ -116,8 +116,13 @@ class SourceClassBuilder extends KernelClassBuilder {
|
||||
void buildBuilders(String name, Declaration declaration) {
|
||||
do {
|
||||
if (declaration.parent != this) {
|
||||
unexpected(
|
||||
"$fileUri", "${declaration.parent.fileUri}", charOffset, fileUri);
|
||||
if (fileUri != declaration.parent.fileUri) {
|
||||
unexpected("$fileUri", "${declaration.parent.fileUri}", charOffset,
|
||||
fileUri);
|
||||
} else {
|
||||
unexpected(fullNameForErrors, declaration.parent?.fullNameForErrors,
|
||||
charOffset, fileUri);
|
||||
}
|
||||
} else if (declaration is KernelFieldBuilder) {
|
||||
// TODO(ahe): It would be nice to have a common interface for the
|
||||
// build method to avoid duplicating these two cases.
|
||||
|
||||
@@ -180,7 +180,8 @@ abstract class SourceLibraryBuilder<T extends TypeBuilder, R>
|
||||
assert(
|
||||
(name?.startsWith(currentDeclaration.name) ??
|
||||
(name == currentDeclaration.name)) ||
|
||||
currentDeclaration.name == "operator",
|
||||
currentDeclaration.name == "operator" ||
|
||||
identical(name, "<syntax-error>"),
|
||||
"${name} != ${currentDeclaration.name}");
|
||||
DeclarationBuilder<T> previous = currentDeclaration;
|
||||
currentDeclaration = currentDeclaration.parent;
|
||||
@@ -477,6 +478,9 @@ abstract class SourceLibraryBuilder<T extends TypeBuilder, R>
|
||||
// TODO(ahe): Set the parent correctly here. Could then change the
|
||||
// implementation of MemberBuilder.isTopLevel to test explicitly for a
|
||||
// LibraryBuilder.
|
||||
if (name == null) {
|
||||
unhandled("null", "name", charOffset, fileUri);
|
||||
}
|
||||
if (currentDeclaration == libraryDeclaration) {
|
||||
if (declaration is MemberBuilder) {
|
||||
declaration.parent = this;
|
||||
|
||||
@@ -54,6 +54,7 @@ enum NullValue {
|
||||
Identifier,
|
||||
IdentifierList,
|
||||
Initializers,
|
||||
Labels,
|
||||
Metadata,
|
||||
Modifiers,
|
||||
ParameterDefaultValue,
|
||||
@@ -76,6 +77,12 @@ abstract class StackListener extends Listener {
|
||||
@override
|
||||
Uri get uri;
|
||||
|
||||
void discard(int n) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
pop();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(ahe): This doesn't belong here. Only implemented by body_builder.dart
|
||||
// and ast_builder.dart.
|
||||
void finishFunction(covariant List<Object> annotations, covariant formals,
|
||||
@@ -150,7 +157,14 @@ abstract class StackListener extends Listener {
|
||||
@override
|
||||
void handleIdentifier(Token token, IdentifierContext context) {
|
||||
debugEvent("handleIdentifier");
|
||||
push(token.lexeme);
|
||||
if (!token.isSynthetic) {
|
||||
push(token.lexeme);
|
||||
} else {
|
||||
// This comes from a synthetic token which is inserted by the parser in
|
||||
// an attempt to recover. This almost always means that the parser has
|
||||
// gotten very confused and we need to ignore the results.
|
||||
push(new ParserRecovery(token.charOffset));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -410,6 +424,7 @@ class Stack {
|
||||
final List<Object> array = this.array;
|
||||
final int length = arrayLength;
|
||||
final int startIndex = length - count;
|
||||
bool isParserRecovery = false;
|
||||
for (int i = 0; i < count; i++) {
|
||||
int arrayIndex = startIndex + i;
|
||||
final Object value = array[arrayIndex];
|
||||
@@ -417,13 +432,18 @@ class Stack {
|
||||
if (value is NullValue && nullValue == null ||
|
||||
identical(value, nullValue)) {
|
||||
list[i] = null;
|
||||
} else if (value is ParserRecovery) {
|
||||
isParserRecovery = true;
|
||||
} else {
|
||||
if (value is NullValue) {
|
||||
print(value);
|
||||
}
|
||||
list[i] = value;
|
||||
}
|
||||
}
|
||||
arrayLength -= count;
|
||||
|
||||
return list;
|
||||
return isParserRecovery ? null : list;
|
||||
}
|
||||
|
||||
List<Object> get values {
|
||||
@@ -469,3 +489,10 @@ class GrowableList<T> {
|
||||
count, new List<T>.filled(count, null, growable: true), nullValue);
|
||||
}
|
||||
}
|
||||
|
||||
class ParserRecovery {
|
||||
final int charOffset;
|
||||
ParserRecovery(this.charOffset);
|
||||
|
||||
String toString() => "ParserRecovery(charOffset)";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user