blob: 12c8559e77e5b34bb2c9d2916f9ac2714d41d334 [file] [log] [blame]
// Copyright (c) 2019, 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.
// @dart = 2.9
library fasta.stack_listener_impl;
import 'package:_fe_analyzer_shared/src/parser/parser.dart' show Parser;
import 'package:_fe_analyzer_shared/src/parser/stack_listener.dart';
import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' show Token;
import 'package:front_end/src/api_prototype/experimental_flags.dart';
import 'package:kernel/ast.dart';
import '../fasta_codes.dart';
import '../problems.dart' as problems
show internalProblem, unhandled, unsupported;
import 'source_library_builder.dart';
abstract class StackListenerImpl extends StackListener {
SourceLibraryBuilder get libraryBuilder;
AsyncMarker asyncMarkerFromTokens(Token asyncToken, Token starToken) {
if (asyncToken == null || identical(asyncToken.stringValue, "sync")) {
if (starToken == null) {
return AsyncMarker.Sync;
} else {
assert(identical(starToken.stringValue, "*"));
return AsyncMarker.SyncStar;
}
} else if (identical(asyncToken.stringValue, "async")) {
if (starToken == null) {
return AsyncMarker.Async;
} else {
assert(identical(starToken.stringValue, "*"));
return AsyncMarker.AsyncStar;
}
} else {
return unhandled(asyncToken.lexeme, "asyncMarkerFromTokens",
asyncToken.charOffset, null);
}
}
// TODO(ahe): This doesn't belong here. Only implemented by body_builder.dart
// and ast_builder.dart.
void finishFunction(
covariant formals, AsyncMarker asyncModifier, covariant body) {
return problems.unsupported("finishFunction", -1, uri);
}
// TODO(ahe): This doesn't belong here. Only implemented by body_builder.dart
// and ast_builder.dart.
dynamic finishFields() {
return problems.unsupported("finishFields", -1, uri);
}
// TODO(ahe): This doesn't belong here. Only implemented by body_builder.dart
// and ast_builder.dart.
List<Expression> finishMetadata(Annotatable parent) {
return problems.unsupported("finishMetadata", -1, uri);
}
// TODO(ahe): This doesn't belong here. Only implemented by body_builder.dart
// and ast_builder.dart.
void exitLocalScope() => problems.unsupported("exitLocalScope", -1, uri);
// TODO(ahe): This doesn't belong here. Only implemented by body_builder.dart.
dynamic parseSingleExpression(
Parser parser, Token token, FunctionNode parameters) {
return problems.unsupported("finishSingleExpression", -1, uri);
}
/// Used to report an internal error encountered in the stack listener.
internalProblem(Message message, int charOffset, Uri uri) {
return problems.internalProblem(message, charOffset, uri);
}
/// Used to report an unexpected situation encountered in the stack
/// listener.
dynamic unhandled(String what, String where, int charOffset, Uri uri) {
return problems.unhandled(what, where, charOffset, uri);
}
void reportMissingNonNullableSupport(Token token) {
assert(!libraryBuilder.isNonNullableByDefault);
assert(token != null);
if (libraryBuilder.enableNonNullableInLibrary) {
if (libraryBuilder.languageVersion.isExplicit) {
addProblem(
templateNonNullableOptOutExplicit.withArguments(
libraryBuilder.enableNonNullableVersionInLibrary.toText()),
token.charOffset,
token.charCount,
context: <LocatedMessage>[
messageNonNullableOptOutComment.withLocation(
libraryBuilder.languageVersion.fileUri,
libraryBuilder.languageVersion.charOffset,
libraryBuilder.languageVersion.charCount)
]);
} else {
addProblem(
templateNonNullableOptOutImplicit.withArguments(
libraryBuilder.enableNonNullableVersionInLibrary.toText()),
token.charOffset,
token.charCount);
}
} else if (libraryBuilder.loader.target
.isExperimentEnabledByDefault(ExperimentalFlag.nonNullable)) {
if (libraryBuilder.languageVersion.version <
libraryBuilder.enableNonNullableVersionInLibrary) {
addProblem(
templateExperimentDisabledInvalidLanguageVersion.withArguments(
libraryBuilder.enableNonNullableVersionInLibrary.toText()),
token.offset,
noLength);
} else {
addProblem(templateExperimentDisabled.withArguments('non-nullable'),
token.offset, noLength);
}
} else if (!libraryBuilder.loader.target
.isExperimentEnabledGlobally(ExperimentalFlag.nonNullable)) {
if (libraryBuilder.languageVersion.version <
libraryBuilder.enableNonNullableVersionInLibrary) {
addProblem(
templateExperimentNotEnabledNoFlagInvalidLanguageVersion
.withArguments(
libraryBuilder.enableNonNullableVersionInLibrary.toText()),
token.offset,
noLength);
} else {
addProblem(messageExperimentNotEnabledNoFlag, token.offset, noLength);
}
} else {
addProblem(
templateExperimentNotEnabled.withArguments('non-nullable',
libraryBuilder.enableNonNullableVersionInLibrary.toText()),
token.offset,
noLength);
}
}
void reportErrorIfNullableType(Token questionMark) {
if (questionMark != null) {
reportMissingNonNullableSupport(questionMark);
}
}
void reportNonNullableModifierError(Token modifierToken) {
assert(!libraryBuilder.isNonNullableByDefault);
if (modifierToken != null) {
reportMissingNonNullableSupport(modifierToken);
}
}
void reportNonNullAssertExpressionNotEnabled(Token bang) {
reportMissingNonNullableSupport(bang);
}
}
/// A null-aware alternative to `token.offset`. If [token] is `null`, returns
/// `TreeNode.noOffset`.
int offsetForToken(Token token) {
return token == null ? TreeNode.noOffset : token.offset;
}