blob: 5aae40db3c890446c8c24c32ca356ec294f0ed7d [file]
// 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.
part of 'internal_ast.dart';
/// Base class for all elements in a list, set or map literal.
sealed class InternalElement({required super.fileOffset}) extends InternalNode {
/// Dispatch method called during inference to infer the type of this element.
ElementInferenceResult acceptInference(
InferenceVisitorImpl visitor,
ElementInferenceContext context,
);
}
/// An expression occurring as an element.
class ExpressionElement({
/// The expression of the element.
required final InternalExpression expression,
required super.fileOffset,
}) extends InternalElement {
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
expression.toTextInternal(printer);
}
@override
ElementInferenceResult acceptInference(
InferenceVisitorImpl visitor,
ElementInferenceContext context,
) {
return visitor.visitExpressionElement(this, context);
}
}
/// A spread element in a list, set, or map literal.
class SpreadElement({
/// The spread expression.
required final InternalExpression expression,
/// Whether the spread is null-aware, i.e. using `...?` instead of `...`.
required final bool isNullAware,
required super.fileOffset,
}) extends InternalElement {
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
printer.write('...');
if (isNullAware) {
printer.write('?');
}
expression.toTextInternal(printer);
}
@override
ElementInferenceResult acceptInference(
InferenceVisitorImpl visitor,
ElementInferenceContext context,
) {
return visitor.visitSpreadElement(this, context);
}
}
/// A null-aware element in a list, set, or map literal.
class NullAwareElement({
/// The null-guarded expression of the element.
required final InternalExpression expression,
required super.fileOffset,
}) extends InternalElement {
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
printer.write('?');
expression.toTextInternal(printer);
}
@override
ElementInferenceResult acceptInference(
InferenceVisitorImpl visitor,
ElementInferenceContext context,
) {
return visitor.visitNullAwareElement(this, context);
}
}
/// An 'if' element in a list, set, or map literal.
class IfElement({
/// The condition expression of the if-element.
required final InternalExpression condition,
/// The then part of the if-element.
required final InternalElement then,
/// The else part of the if-element, if present.
required final InternalElement? otherwise,
required super.fileOffset,
}) extends InternalElement {
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
printer.write('if (');
condition.toTextInternal(printer);
printer.write(') ');
then.toTextInternal(printer);
if (otherwise != null) {
printer.write(' else ');
otherwise!.toTextInternal(printer);
}
}
@override
ElementInferenceResult acceptInference(
InferenceVisitorImpl visitor,
ElementInferenceContext context,
) {
return visitor.visitIfElement(this, context);
}
}
/// Base class for [ForElement] and [PatternForElement].
sealed class ForElementBase({
/// The variables declared in the for-element initializer.
required final List<InternalVariableDeclaration> variables,
/// The condition expression of the for-element, if present.
required final InternalExpression? condition,
/// The expressions occurring in the updates part of the for-element.
required final List<InternalExpression> updates,
/// The body of the for-element.
required final InternalElement body,
required super.fileOffset,
}) extends InternalElement;
/// A 'for' element in a list, set, or map literal.
class ForElement({
required super.variables,
required super.condition,
required super.updates,
required super.body,
required super.fileOffset,
}) extends ForElementBase {
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
printer.write('for (');
for (int index = 0; index < variables.length; index++) {
if (index > 0) {
printer.write(', ');
}
variables[index].variable.toTextInternal(
printer,
includeModifiersAndType: index == 0,
initializer: variables[index].initializer,
);
}
printer.write('; ');
if (condition != null) {
condition!.toTextInternal(printer);
}
printer.write('; ');
updates.toTextInternal(printer);
printer.write(') ');
body.toTextInternal(printer);
}
@override
ElementInferenceResult acceptInference(
InferenceVisitorImpl visitor,
ElementInferenceContext context,
) {
return visitor.visitForElement(this, context);
}
}
/// A 'for-in' element in a list, set, or map literal.
class ForInElement({
/// The element declaration in the for-in element.
required final InternalForInElement element,
/// The iterable expression of the for-in element.
required final InternalExpression iterable,
/// The body of the for-in element
required final InternalElement body,
/// Whether the for-in element is async, i.e. `await for` instead of `for`.
required final bool isAsync,
required super.fileOffset,
/// File offset for the `for` keyword.
required final int forOffset,
}) extends InternalElement {
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
if (isAsync) {
printer.write('async ');
}
printer.write('for (');
element.toTextInternal(printer);
printer.write(' in ');
iterable.toTextInternal(printer);
printer.write(') ');
body.toTextInternal(printer);
}
@override
ElementInferenceResult acceptInference(
InferenceVisitorImpl visitor,
ElementInferenceContext context,
) {
return visitor.visitForInElement(this, context);
}
}
/// An if-case element in a list, set, or map literal.
class IfCaseElement({
/// The case expression of the if-case element.
required final InternalExpression expression,
/// The pattern and optional guard of the if-case element.
required final InternalPatternGuard patternGuard,
/// The then part of the if-case-element.
required final InternalElement then,
/// The else part of the if-case-element, if present.
required final InternalElement? otherwise,
required super.fileOffset,
}) extends InternalElement {
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
printer.write('if (');
expression.toTextInternal(printer);
printer.write(' case ');
patternGuard.toTextInternal(printer);
printer.write(') ');
then.toTextInternal(printer);
if (otherwise != null) {
printer.write(' else ');
otherwise!.toTextInternal(printer);
}
}
@override
ElementInferenceResult acceptInference(
InferenceVisitorImpl visitor,
ElementInferenceContext context,
) {
return visitor.visitIfCaseElement(this, context);
}
}
/// A for loop with a pattern variable declaration in a list, set, or map
/// literal.
class PatternForElement({
/// The pattern variable declaration occurring in the for element initializer.
required final InternalPatternVariableDeclaration patternVariableDeclaration,
/// Intermediate variables needed for the lowering of the pattern for-element.
required final List<InternalVariableDeclaration> intermediateVariables,
required super.variables,
required super.condition,
required super.updates,
required super.body,
required super.fileOffset,
}) extends ForElementBase {
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
patternVariableDeclaration.toTextInternal(printer);
printer.write('for (');
for (int index = 0; index < variables.length; index++) {
if (index > 0) {
printer.write(', ');
}
variables[index].variable.toTextInternal(
printer,
includeModifiersAndType: index == 0,
initializer: variables[index].initializer,
);
}
printer.write('; ');
if (condition != null) {
condition!.toTextInternal(printer);
}
printer.write('; ');
updates.toTextInternal(printer);
printer.write(') ');
body.toTextInternal(printer);
}
@override
ElementInferenceResult acceptInference(
InferenceVisitorImpl visitor,
ElementInferenceContext context,
) {
return visitor.visitPatternForElement(this, context);
}
}
/// A map entry in a list, set, or map literal.
class MapEntryElement({
/// `true` if the key expression is null-aware, that is, marked with `?`.
required final bool isKeyNullAware,
/// The key expression of the map entry.
required final InternalExpression key,
/// `true` if the value expression is null-aware, that is, marked with `?`.
required final bool isValueNullAware,
/// The value expression of the map entry.
required final InternalExpression value,
required super.fileOffset,
}) extends InternalElement {
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
if (isKeyNullAware) {
printer.write('?');
}
key.toTextInternal(printer);
printer.write(': ');
if (isValueNullAware) {
printer.write('?');
}
value.toTextInternal(printer);
}
@override
ElementInferenceResult acceptInference(
InferenceVisitorImpl visitor,
ElementInferenceContext context,
) {
return visitor.visitMapEntryElement(this, context);
}
}