blob: 2df49113496b65d2057530e69619b5c1a3413031 [file] [log] [blame]
// Copyright (c) 2023, 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 '../back_end/code_writer.dart';
import '../constants.dart';
import 'piece.dart';
/// A piece for a series of statements or members inside a block or declaration
/// body or at the top level of a program.
///
/// Constructed using a [SequenceBuilder].
class SequencePiece extends Piece {
/// The series of members or statements.
final List<SequenceElementPiece> _elements;
SequencePiece(this._elements);
@override
void format(CodeWriter writer, State state) {
writer.pushIndent(Indent.none);
for (var i = 0; i < _elements.length; i++) {
var element = _elements[i];
writer.format(element, separate: true);
if (i < _elements.length - 1) {
writer.popIndent();
writer.pushIndent(_elements[i + 1]._indent);
writer.newline(blank: element.blankAfter);
}
}
writer.popIndent();
}
@override
void forEachChild(void Function(Piece piece) callback) {
for (var element in _elements) {
callback(element);
}
}
/// If there are multiple elements, there are newlines between them.
@override
bool calculateContainsHardNewline() => _elements.length > 1;
@override
String get debugName => 'Seq';
}
/// A piece for a non-empty brace-delimited series of statements or members
/// inside a block or declaration body.
///
/// Unlike [ListPiece], always splits between the elements.
///
/// Constructed using a [SequenceBuilder].
class BlockPiece extends Piece {
/// The opening delimiter.
final Piece _leftBracket;
/// The series of members or statements.
final SequencePiece _elements;
/// The closing delimiter.
final Piece _rightBracket;
BlockPiece(this._leftBracket, this._elements, this._rightBracket);
@override
void format(CodeWriter writer, State state) {
writer.format(_leftBracket);
writer.pushIndent(Indent.block);
writer.newline();
writer.format(_elements);
writer.popIndent();
writer.newline();
writer.format(_rightBracket);
}
@override
void forEachChild(void Function(Piece piece) callback) {
callback(_leftBracket);
callback(_elements);
callback(_rightBracket);
}
/// A [BlockPiece] is never empty and always splits between the delimiters.
@override
bool calculateContainsHardNewline() => true;
@override
String get debugName => 'Block';
}
/// An element inside a [SequencePiece].
///
/// Tracks the underlying [Piece] along with surrounding whitespace.
class SequenceElementPiece extends Piece {
/// The number of spaces of indentation on the line before this element,
/// relative to the surrounding [Piece].
final int _indent;
/// The [Piece] for the element.
final Piece piece;
/// The comments that should appear at the end of this element's line.
final List<Piece> hangingComments = [];
/// Whether there should be a blank line after this element.
bool blankAfter = false;
SequenceElementPiece(this._indent, this.piece);
@override
void format(CodeWriter writer, State state) {
writer.format(piece);
for (var comment in hangingComments) {
writer.space();
writer.format(comment);
}
}
@override
void forEachChild(void Function(Piece piece) callback) {
callback(piece);
for (var comment in hangingComments) {
callback(comment);
}
}
@override
String get debugName => 'SeqElem';
}