blob: 54e0648ff8fc18442702cf70f221405f26fa3bc3 [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.
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:kernel/ast.dart';
import '../../api_prototype/experimental_flags.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;
LibraryFeatures get libraryFeatures => libraryBuilder.libraryFeatures;
@override
Uri get importUri => libraryBuilder.importUri;
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.
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.
@override
Never internalProblem(Message message, int charOffset, Uri uri) {
return problems.internalProblem(message, charOffset, uri);
}
/// Used to report an unexpected situation encountered in the stack
/// listener.
Never unhandled(String what, String where, int charOffset, Uri? uri) {
return problems.unhandled(what, where, charOffset, uri);
}
void reportMissingNonNullableSupport(Token token) {
assert(!libraryBuilder.isNonNullableByDefault);
// ignore: unnecessary_null_comparison
assert(token != null);
if (libraryFeatures.nonNullable.isSupported) {
if (libraryBuilder.languageVersion.isExplicit) {
addProblem(
templateNullSafetyOptOutExplicit.withArguments(
libraryFeatures.nonNullable.enabledVersion.toText()),
token.charOffset,
token.charCount,
context: <LocatedMessage>[
messageNullSafetyOptOutComment.withLocation(
libraryBuilder.languageVersion.fileUri!,
libraryBuilder.languageVersion.charOffset,
libraryBuilder.languageVersion.charCount)
]);
} else {
addProblem(
templateNullSafetyOptOutImplicit.withArguments(
libraryFeatures.nonNullable.enabledVersion.toText()),
token.charOffset,
token.charCount);
}
} else {
if (libraryBuilder.languageVersion.version <
libraryFeatures.nonNullable.enabledVersion) {
addProblem(
templateNullSafetyDisabledInvalidLanguageVersion.withArguments(
libraryFeatures.nonNullable.enabledVersion.toText()),
token.offset,
noLength);
} else {
addProblem(templateExperimentDisabled.withArguments('non-nullable'),
token.offset, noLength);
}
}
}
/// Reports an error if [feature] is not enabled, using [charOffset] and
/// [length] for the location of the message.
///
/// Return `true` if the [feature] is not enabled.
bool reportIfNotEnabled(LibraryFeature feature, int charOffset, int length) {
if (!feature.isEnabled) {
libraryBuilder.reportFeatureNotEnabled(feature, uri, charOffset, length);
return true;
}
return false;
}
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;
}