d7f200b97d
(Part of https://github.com/dart-lang/sdk/issues/63288) This change migrates the kernel package to use the new constructor declaration syntax, described in https://github.com/dart-lang/language/blob/main/accepted/future-releases/primary-constructors/feature-specification.md#abbreviations-of-in-body-constructor-declarations. This change was performed in an automated fashion, by (a) bumping the package's SDK constraint to `3.13.0-0`, (b) enabling the lints `unnecessary_type_name_in_constructor` and `unnecessary_const_in_enum_constructor`, (c) fixing the resulting lint failures using `dart fix`, and then (d) reformatting the affected files. To ease code review, I've reverted unrelated formatting changes. Change-Id: I8d32a0b26450a44dfa2ebd9fe2dff9df6a6a6964 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/508426 Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
701 lines
21 KiB
Dart
701 lines
21 KiB
Dart
// Copyright (c) 2020, 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.
|
|
|
|
import '../ast.dart';
|
|
import 'text_util.dart';
|
|
|
|
/// AST printer strategy used by default in `Node.toString`.
|
|
///
|
|
/// Don't use this for testing. Instead use [astTextStrategyForTesting] or
|
|
/// make an explicit strategy for the test to avoid test dependency on the
|
|
/// `Node.toString` implementation.
|
|
const AstTextStrategy defaultAstTextStrategy = const AstTextStrategy();
|
|
|
|
/// Strategy used for printing AST nodes.
|
|
///
|
|
/// This is used to avoid dependency on the `Node.toString` implementations
|
|
/// in testing.
|
|
const AstTextStrategy astTextStrategyForTesting = const AstTextStrategy(
|
|
includeLibraryNamesInMembers: true,
|
|
includeLibraryNamesInTypes: true,
|
|
includeAuxiliaryProperties: false,
|
|
useMultiline: false,
|
|
);
|
|
|
|
class AstTextStrategy {
|
|
/// If `true`, references to classes and typedefs in types are prefixed by the
|
|
/// name of their enclosing library.
|
|
final bool includeLibraryNamesInTypes;
|
|
|
|
/// If `true`, references to members, classes and typedefs are prefixed by the
|
|
/// name of their enclosing library.
|
|
final bool includeLibraryNamesInMembers;
|
|
|
|
/// If `true`, auxiliary node properties are on include in the textual
|
|
/// representation.
|
|
final bool includeAuxiliaryProperties;
|
|
|
|
/// If `true`, only [Nullability.nullable] is shown on types.
|
|
final bool showNullableOnly;
|
|
|
|
/// If `true`, type parameter names qualified by the name of the declaring
|
|
/// class or function.
|
|
final bool useQualifiedTypeParameterNames;
|
|
|
|
/// If `true`, type parameter names qualified also by local functions
|
|
/// (if named).
|
|
final bool useQualifiedTypeParameterNamesRecurseOnNamedLocalFunctions;
|
|
|
|
/// If `true`, newlines are used to separate statements.
|
|
final bool useMultiline;
|
|
|
|
/// If [useMultiline] is `true`, [indentation] is used for indentation.
|
|
final String indentation;
|
|
|
|
/// If non-null, a maximum of [maxStatementDepth] nested statements are
|
|
/// printed. If exceeded, '...' is printed instead.
|
|
final int? maxStatementDepth;
|
|
|
|
/// If non-null, a maximum of [maxStatementsLength] statements are printed
|
|
/// within the same block.
|
|
final int? maxStatementsLength;
|
|
|
|
/// If non-null, a maximum of [maxExpressionDepth] nested expression are
|
|
/// printed. If exceeded, '...' is printed instead.
|
|
final int? maxExpressionDepth;
|
|
|
|
/// If non-null, a maximum of [maxExpressionsLength] expression are printed
|
|
/// within the same list of expressions, for instance in list/set literals.
|
|
/// If exceeded, '...' is printed instead.
|
|
final int? maxExpressionsLength;
|
|
|
|
/// If non-null, a maximum of [maxConstantDepth] nested constants are
|
|
/// printed. If exceeded, '...' is printed instead.
|
|
final int? maxConstantDepth;
|
|
|
|
const new({
|
|
this.includeLibraryNamesInTypes = false,
|
|
this.includeLibraryNamesInMembers = false,
|
|
this.includeAuxiliaryProperties = false,
|
|
this.showNullableOnly = false,
|
|
this.useQualifiedTypeParameterNames = true,
|
|
this.useQualifiedTypeParameterNamesRecurseOnNamedLocalFunctions = false,
|
|
this.useMultiline = true,
|
|
this.indentation = ' ',
|
|
this.maxStatementDepth = 50,
|
|
this.maxStatementsLength = null,
|
|
this.maxExpressionDepth = 50,
|
|
this.maxExpressionsLength = null,
|
|
this.maxConstantDepth = 10,
|
|
});
|
|
}
|
|
|
|
class AstPrinter {
|
|
final AstTextStrategy _strategy;
|
|
final StringBuffer _sb = new StringBuffer();
|
|
int _statementLevel = 0;
|
|
int _expressionLevel = 0;
|
|
int _constantLevel = 0;
|
|
int _indentationLevel = 0;
|
|
late final Map<LabeledStatement, String> _labelNames = {};
|
|
late final Map<Variable, String> _variableDeclarationNames = {};
|
|
late final Map<VariableBase, String> _variableNames = {};
|
|
|
|
new(this._strategy);
|
|
|
|
bool get includeAuxiliaryProperties => _strategy.includeAuxiliaryProperties;
|
|
|
|
void incIndentation() {
|
|
_indentationLevel++;
|
|
}
|
|
|
|
void decIndentation() {
|
|
_indentationLevel--;
|
|
}
|
|
|
|
void write(String value) {
|
|
_sb.write(value);
|
|
}
|
|
|
|
void writeClassName(Reference? reference, {bool forType = false}) {
|
|
_sb.write(
|
|
qualifiedClassNameToStringByReference(
|
|
reference,
|
|
includeLibraryName: forType
|
|
? _strategy.includeLibraryNamesInTypes
|
|
: _strategy.includeLibraryNamesInMembers,
|
|
),
|
|
);
|
|
}
|
|
|
|
void writeTypedefName(Reference? reference) {
|
|
_sb.write(
|
|
qualifiedTypedefNameToStringByReference(
|
|
reference,
|
|
includeLibraryName: _strategy.includeLibraryNamesInTypes,
|
|
),
|
|
);
|
|
}
|
|
|
|
void writeExtensionName(Reference? reference) {
|
|
_sb.write(
|
|
qualifiedExtensionNameToStringByReference(
|
|
reference,
|
|
includeLibraryName: _strategy.includeLibraryNamesInMembers,
|
|
),
|
|
);
|
|
}
|
|
|
|
void writeExtensionTypeDeclarationName(Reference? reference) {
|
|
_sb.write(
|
|
qualifiedExtensionTypeDeclarationNameToStringByReference(
|
|
reference,
|
|
includeLibraryName: _strategy.includeLibraryNamesInMembers,
|
|
),
|
|
);
|
|
}
|
|
|
|
void writeQualifiedCanonicalNameToString(CanonicalName canonicalName) {
|
|
_sb.write(
|
|
qualifiedCanonicalNameToString(
|
|
canonicalName,
|
|
includeLibraryName: _strategy.includeLibraryNamesInMembers,
|
|
includeLibraryNamesInTypes: _strategy.includeLibraryNamesInTypes,
|
|
),
|
|
);
|
|
}
|
|
|
|
void writeMemberName(Reference? reference) {
|
|
_sb.write(
|
|
qualifiedMemberNameToStringByReference(
|
|
reference,
|
|
includeLibraryName: _strategy.includeLibraryNamesInMembers,
|
|
),
|
|
);
|
|
}
|
|
|
|
void writeInterfaceMemberName(Reference? reference, Name? name) {
|
|
if (name != null && (reference == null || reference.node == null)) {
|
|
writeName(name);
|
|
} else {
|
|
write('{');
|
|
_sb.write(
|
|
qualifiedMemberNameToStringByReference(
|
|
reference,
|
|
includeLibraryName: _strategy.includeLibraryNamesInMembers,
|
|
),
|
|
);
|
|
write('}');
|
|
}
|
|
}
|
|
|
|
void writeLibraryReference(Reference reference) {
|
|
_sb.write(libraryReferenceToString(reference));
|
|
}
|
|
|
|
void writeName(Name? name) {
|
|
_sb.write(
|
|
nameToString(
|
|
name,
|
|
includeLibraryName: _strategy.includeLibraryNamesInMembers,
|
|
),
|
|
);
|
|
}
|
|
|
|
void writeNamedType(NamedType node) {
|
|
node.toTextInternal(this);
|
|
}
|
|
|
|
void writeTypeParameterName(TypeParameter parameter) {
|
|
_sb.write(
|
|
_strategy.useQualifiedTypeParameterNames
|
|
? qualifiedTypeParameterNameToString(
|
|
parameter,
|
|
includeLibraryName: _strategy.includeLibraryNamesInTypes,
|
|
recurseOnLocalFunction: _strategy
|
|
.useQualifiedTypeParameterNamesRecurseOnNamedLocalFunctions,
|
|
)
|
|
: typeParameterNameToString(parameter),
|
|
);
|
|
}
|
|
|
|
void writeStructuralParameterName(StructuralParameter parameter) {
|
|
_sb.write(
|
|
_strategy.useQualifiedTypeParameterNames
|
|
? qualifiedStructuralParameterNameToString(
|
|
parameter,
|
|
includeLibraryName: _strategy.includeLibraryNamesInTypes,
|
|
)
|
|
: structuralParameterNameToString(parameter),
|
|
);
|
|
}
|
|
|
|
void newLine() {
|
|
if (_strategy.useMultiline) {
|
|
_sb.writeln();
|
|
_sb.write(_strategy.indentation * _indentationLevel);
|
|
} else {
|
|
_sb.write(' ');
|
|
}
|
|
}
|
|
|
|
String getLabelName(LabeledStatement node) {
|
|
return _labelNames[node] ??= 'label${_labelNames.length}';
|
|
}
|
|
|
|
String getVariableName(VariableBase node) {
|
|
switch (node) {
|
|
case NamedParameter(parameterName: var name):
|
|
case PositionalParameter(cosmeticName: var name?):
|
|
case TypeVariable(cosmeticName: var name?):
|
|
case LocalVariable(cosmeticName: var name?):
|
|
case LateVariable(cosmeticName: var name?):
|
|
return name;
|
|
case ThisVariable():
|
|
return 'this';
|
|
case PositionalParameter(cosmeticName: null):
|
|
case TypeVariable(cosmeticName: null):
|
|
case LocalVariable(cosmeticName: null):
|
|
case LateVariable(cosmeticName: null):
|
|
case SyntheticVariable():
|
|
return _variableNames[node] ??= '#${_variableNames.length}';
|
|
case CatchVariable(catchVariableName: var name):
|
|
return name;
|
|
case LegacyVariable(:var name):
|
|
if (name != null) {
|
|
return name;
|
|
}
|
|
return _variableDeclarationNames[node as Variable] ??=
|
|
'#${_variableDeclarationNames.length}';
|
|
}
|
|
}
|
|
|
|
String getSwitchCaseName(SwitchCase node) {
|
|
if (node.isDefault) {
|
|
return '"default:"';
|
|
} else {
|
|
return '"case ${node.expressions.first.toText(_strategy)}:"';
|
|
}
|
|
}
|
|
|
|
void writeStatement(Statement node) {
|
|
int oldStatementLevel = _statementLevel;
|
|
_statementLevel++;
|
|
if (_strategy.maxStatementDepth != null &&
|
|
_statementLevel > _strategy.maxStatementDepth!) {
|
|
_sb.write('...');
|
|
} else {
|
|
node.toTextInternal(this);
|
|
}
|
|
_statementLevel = oldStatementLevel;
|
|
}
|
|
|
|
void writeExpression(Expression node, {int? minimumPrecedence}) {
|
|
int oldExpressionLevel = _expressionLevel;
|
|
_expressionLevel++;
|
|
if (_strategy.maxExpressionDepth != null &&
|
|
_expressionLevel > _strategy.maxExpressionDepth!) {
|
|
_sb.write('...');
|
|
} else {
|
|
bool needsParentheses =
|
|
minimumPrecedence != null && node.precedence < minimumPrecedence;
|
|
if (needsParentheses) {
|
|
_sb.write('(');
|
|
}
|
|
node.toTextInternal(this);
|
|
if (needsParentheses) {
|
|
_sb.write(')');
|
|
}
|
|
}
|
|
_expressionLevel = oldExpressionLevel;
|
|
}
|
|
|
|
void writeNamedExpression(NamedExpression node) {
|
|
node.toTextInternal(this);
|
|
}
|
|
|
|
void writeCatch(Catch node) {
|
|
node.toTextInternal(this);
|
|
}
|
|
|
|
void writeSwitchCase(SwitchCase node) {
|
|
node.toTextInternal(this);
|
|
}
|
|
|
|
void writeType(DartType node) {
|
|
node.toTextInternal(this);
|
|
}
|
|
|
|
void writeNullability(Nullability nullability) {
|
|
if (!_strategy.showNullableOnly || nullability == Nullability.nullable) {
|
|
write(nullabilityToString(nullability));
|
|
}
|
|
}
|
|
|
|
void writeConstant(Constant node) {
|
|
int oldConstantLevel = _constantLevel;
|
|
_constantLevel++;
|
|
if (_strategy.maxConstantDepth != null &&
|
|
_constantLevel > _strategy.maxConstantDepth!) {
|
|
_sb.write('...');
|
|
} else {
|
|
node.toTextInternal(this);
|
|
}
|
|
_constantLevel = oldConstantLevel;
|
|
}
|
|
|
|
void writeMapEntry(MapLiteralEntry node) {
|
|
node.toTextInternal(this);
|
|
}
|
|
|
|
/// Writes [types] to the printer buffer separated by ', '.
|
|
void writeTypes(List<DartType> types) {
|
|
for (int index = 0; index < types.length; index++) {
|
|
if (index > 0) {
|
|
_sb.write(', ');
|
|
}
|
|
writeType(types[index]);
|
|
}
|
|
}
|
|
|
|
/// If [types] is non-empty, writes [types] to the printer buffer delimited by
|
|
/// '<' and '>', and separated by ', '.
|
|
void writeTypeArguments(List<DartType> types) {
|
|
if (types.isNotEmpty) {
|
|
_sb.write('<');
|
|
writeTypes(types);
|
|
_sb.write('>');
|
|
}
|
|
}
|
|
|
|
/// If [typeParameters] is non-empty, writes [typeParameters] to the printer
|
|
/// buffer delimited by '<' and '>', and separated by ', '.
|
|
///
|
|
/// The bound of a type parameter is included, as 'T extends Bound', if the
|
|
/// bound is neither `Object?` nor `Object*`.
|
|
void writeTypeParameters(List<TypeParameter> typeParameters) {
|
|
if (typeParameters.isNotEmpty) {
|
|
_sb.write("<");
|
|
String comma = "";
|
|
for (TypeParameter typeParameter in typeParameters) {
|
|
_sb.write(comma);
|
|
_sb.write(typeParameter.name);
|
|
DartType bound = typeParameter.bound;
|
|
|
|
bool isTopObject(DartType type) {
|
|
if (type is InterfaceType &&
|
|
type.classReference.node != null &&
|
|
type.classNode.name == 'Object') {
|
|
Uri uri = type.classNode.enclosingLibrary.importUri;
|
|
return uri.isScheme('dart') &&
|
|
uri.path == 'core' &&
|
|
type.nullability == Nullability.nullable;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if (!isTopObject(bound) || isTopObject(typeParameter.defaultType)) {
|
|
// Include explicit bounds only.
|
|
_sb.write(' extends ');
|
|
writeType(bound);
|
|
}
|
|
comma = ", ";
|
|
}
|
|
_sb.write(">");
|
|
}
|
|
}
|
|
|
|
/// If [typeParameters] is non-empty, writes [typeParameters] to the printer
|
|
/// buffer delimited by '<' and '>', and separated by ', '.
|
|
///
|
|
/// The bound of a type parameter is included, as 'T extends Bound', if the
|
|
/// bound is neither `Object?` nor `Object*`.
|
|
void writeStructuralParameters(List<StructuralParameter> typeParameters) {
|
|
if (typeParameters.isNotEmpty) {
|
|
_sb.write("<");
|
|
String comma = "";
|
|
for (StructuralParameter typeParameter in typeParameters) {
|
|
_sb.write(comma);
|
|
_sb.write(typeParameter.name);
|
|
DartType bound = typeParameter.bound;
|
|
|
|
bool isTopObject(DartType type) {
|
|
if (type is InterfaceType &&
|
|
type.classReference.node != null &&
|
|
type.classNode.name == 'Object') {
|
|
Uri uri = type.classNode.enclosingLibrary.importUri;
|
|
return uri.isScheme('dart') &&
|
|
uri.path == 'core' &&
|
|
type.nullability == Nullability.nullable;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if (!isTopObject(bound) || isTopObject(typeParameter.defaultType)) {
|
|
// Include explicit bounds only.
|
|
_sb.write(' extends ');
|
|
writeType(bound);
|
|
}
|
|
comma = ", ";
|
|
}
|
|
_sb.write(">");
|
|
}
|
|
}
|
|
|
|
/// Writes [expressions] to the printer buffer separated by ', '.
|
|
void writeExpressions(List<Expression> expressions) {
|
|
if (expressions.isNotEmpty &&
|
|
_strategy.maxExpressionDepth != null &&
|
|
_expressionLevel + 1 > _strategy.maxExpressionDepth!) {
|
|
// The maximum expression depth will be exceeded for all [expressions].
|
|
// Print the list as one occurrence '...' instead one per expression.
|
|
_sb.write('...');
|
|
} else if (_strategy.maxExpressionsLength != null &&
|
|
expressions.length > _strategy.maxExpressionsLength!) {
|
|
_sb.write('...');
|
|
} else {
|
|
for (int index = 0; index < expressions.length; index++) {
|
|
if (index > 0) {
|
|
_sb.write(', ');
|
|
}
|
|
writeExpression(expressions[index]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Writes [statements] to the printer buffer delimited by '{' and '}'.
|
|
///
|
|
/// If using a multiline strategy, the statements printed on separate lines
|
|
/// that are indented one level.
|
|
void writeBlock(List<Statement> statements) {
|
|
if (statements.isEmpty) {
|
|
write('{}');
|
|
} else {
|
|
write('{');
|
|
incIndentation();
|
|
writeStatements(statements);
|
|
decIndentation();
|
|
newLine();
|
|
write('}');
|
|
}
|
|
}
|
|
|
|
/// Writes [statements] to the printer buffer.
|
|
///
|
|
/// If using a multiline strategy, the statements printed on separate lines
|
|
/// that are indented one level.
|
|
void writeStatements(List<Statement> statements) {
|
|
if (statements.isNotEmpty &&
|
|
_strategy.maxStatementDepth != null &&
|
|
_statementLevel + 1 > _strategy.maxStatementDepth!) {
|
|
// The maximum statement depth will be exceeded for all [statements].
|
|
// Print the list as one occurrence '...' instead one per statement.
|
|
_sb.write(' ...');
|
|
} else if (_strategy.maxStatementsLength != null &&
|
|
statements.length > _strategy.maxStatementsLength!) {
|
|
_sb.write(' ...');
|
|
} else {
|
|
for (Statement statement in statements) {
|
|
newLine();
|
|
writeStatement(statement);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Writes arguments [node] to the printer buffer.
|
|
///
|
|
/// If [includeTypeArguments] is `true` type arguments in [node] are included.
|
|
/// Otherwise only the positional and named arguments are included.
|
|
void writeArguments(Arguments node, {bool includeTypeArguments = true}) {
|
|
node.toTextInternal(this, includeTypeArguments: includeTypeArguments);
|
|
}
|
|
|
|
/// Writes the [VariableDeclaration] [node] to the printer buffer.
|
|
///
|
|
/// If [includeModifiersAndType] is `true`, the declaration is prefixed by
|
|
/// the modifiers and declared type of the variable. Otherwise only the
|
|
/// name and the initializer, if present, are included.
|
|
///
|
|
/// If [isLate] and [type] are provided, these values are used instead of
|
|
/// the corresponding properties on [node].
|
|
void writeVariableDeclaration(
|
|
VariableDeclaration node, {
|
|
bool includeModifiersAndType = true,
|
|
bool? isLate,
|
|
DartType? type,
|
|
bool includeInitializer = true,
|
|
bool isImplicitlyTyped = false,
|
|
}) {
|
|
writeVariableInitialization(
|
|
node.variable,
|
|
includeModifiersAndType: includeModifiersAndType,
|
|
isLate: isLate,
|
|
type: type,
|
|
includeInitializer: includeInitializer,
|
|
isImplicitlyTyped: isImplicitlyTyped,
|
|
);
|
|
}
|
|
|
|
/// Writes the [VariableInitialization] [node] to the printer buffer.
|
|
///
|
|
/// If [includeModifiersAndType] is `true`, the declaration is prefixed by
|
|
/// the modifiers and declared type of the variable. Otherwise only the
|
|
/// name and the initializer, if present, are included.
|
|
///
|
|
/// If [isLate] and [type] are provided, these values are used instead of
|
|
/// the corresponding properties on [node].
|
|
void writeVariableInitialization(
|
|
Variable node, {
|
|
bool includeModifiersAndType = true,
|
|
bool? isLate,
|
|
DartType? type,
|
|
bool includeInitializer = true,
|
|
bool isImplicitlyTyped = false,
|
|
}) {
|
|
if (includeModifiersAndType) {
|
|
if (node.isRequired) {
|
|
_sb.write('required ');
|
|
}
|
|
if (isLate ?? node.isLate) {
|
|
_sb.write('late ');
|
|
}
|
|
if (node.isFinal) {
|
|
_sb.write('final ');
|
|
}
|
|
if (node.isConst) {
|
|
_sb.write('const ');
|
|
}
|
|
if (isImplicitlyTyped) {
|
|
_sb.write('var ');
|
|
} else {
|
|
writeType(type ?? node.type);
|
|
_sb.write(' ');
|
|
}
|
|
}
|
|
_sb.write(getVariableName(node.variable));
|
|
if (includeInitializer && node.initializer != null && !node.isRequired) {
|
|
_sb.write(' = ');
|
|
writeExpression(node.initializer!);
|
|
}
|
|
}
|
|
|
|
/// Writes the variable declaration [node] to the printer buffer.
|
|
///
|
|
/// If [includeModifiersAndType] is `true`, the declaration is prefixed by
|
|
/// the modifiers and declared type of the variable. Otherwise only the
|
|
/// name and the initializer, if present, are included.
|
|
///
|
|
/// If [isLate] and [type] are provided, these values are used instead of
|
|
/// the corresponding properties on [node].
|
|
void writeExpressionVariable(
|
|
Variable node, {
|
|
bool includeModifiersAndType = true,
|
|
bool? isLate,
|
|
DartType? type,
|
|
}) {
|
|
if (includeModifiersAndType) {
|
|
if (node is FunctionParameter && node.isRequired) {
|
|
_sb.write('required ');
|
|
}
|
|
if (isLate ?? (node is! FunctionParameter && node.isLate)) {
|
|
_sb.write('late ');
|
|
}
|
|
if (node is! FunctionParameter && node.isFinal) {
|
|
_sb.write('final ');
|
|
}
|
|
if (node is! FunctionParameter && node.isConst) {
|
|
_sb.write('const ');
|
|
}
|
|
writeType(type ?? node.type);
|
|
_sb.write(' ');
|
|
}
|
|
_sb.write(getVariableName(node));
|
|
}
|
|
|
|
void writeFunctionNode(FunctionNode node, String name) {
|
|
writeType(node.returnType);
|
|
_sb.write(' ');
|
|
_sb.write(name);
|
|
if (node.typeParameters.isNotEmpty) {
|
|
_sb.write('<');
|
|
for (int index = 0; index < node.typeParameters.length; index++) {
|
|
if (index > 0) {
|
|
_sb.write(', ');
|
|
}
|
|
_sb.write(node.typeParameters[index].name);
|
|
_sb.write(' extends ');
|
|
writeType(node.typeParameters[index].bound);
|
|
}
|
|
_sb.write('>');
|
|
}
|
|
_sb.write('(');
|
|
for (int index = 0; index < node.positionalParameters.length; index++) {
|
|
if (index > 0) {
|
|
_sb.write(', ');
|
|
}
|
|
if (index == node.requiredParameterCount) {
|
|
_sb.write('[');
|
|
}
|
|
writeVariableInitialization(node.positionalParameters[index]);
|
|
}
|
|
if (node.requiredParameterCount < node.positionalParameters.length) {
|
|
_sb.write(']');
|
|
}
|
|
if (node.namedParameters.isNotEmpty) {
|
|
if (node.positionalParameters.isNotEmpty) {
|
|
_sb.write(', ');
|
|
}
|
|
_sb.write('{');
|
|
for (int index = 0; index < node.namedParameters.length; index++) {
|
|
if (index > 0) {
|
|
_sb.write(', ');
|
|
}
|
|
writeVariableInitialization(node.namedParameters[index]);
|
|
}
|
|
_sb.write('}');
|
|
}
|
|
_sb.write(')');
|
|
Statement? body = node.body;
|
|
if (body != null) {
|
|
if (body is ReturnStatement) {
|
|
_sb.write(' => ');
|
|
writeExpression(body.expression!);
|
|
} else {
|
|
_sb.write(' ');
|
|
writeStatement(body);
|
|
}
|
|
} else {
|
|
_sb.write(';');
|
|
}
|
|
}
|
|
|
|
void writeConstantMapEntry(ConstantMapEntry node) {
|
|
node.toTextInternal(this);
|
|
}
|
|
|
|
/// Returns the text written to this printer.
|
|
String getText() => _sb.toString();
|
|
}
|
|
|
|
class MarkingAstPrinter extends AstPrinter {
|
|
Set<TreeNode> markThis;
|
|
new(super.strategy, this.markThis);
|
|
|
|
@override
|
|
void writeStatement(Statement node) {
|
|
bool mark = markThis.contains(node);
|
|
if (mark) write("***");
|
|
super.writeStatement(node);
|
|
if (mark) write("***");
|
|
}
|
|
|
|
@override
|
|
void writeExpression(Expression node, {int? minimumPrecedence}) {
|
|
bool mark = markThis.contains(node);
|
|
if (mark) write("***");
|
|
super.writeExpression(node, minimumPrecedence: minimumPrecedence);
|
|
if (mark) write("***");
|
|
}
|
|
}
|