blob: 9e6844413a44f5fc80efdad2656c1649900778cf [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.
///
/// Usually constructed using a [SequenceBuilder].
class SequencePiece extends Piece {
/// The opening delimiter, if any.
final Piece? _leftBracket;
/// The series of members or statements.
final List<SequenceElement> _elements;
SequencePiece(this._elements, {Piece? leftBracket, Piece? rightBracket})
: _leftBracket = leftBracket,
_rightBracket = rightBracket;
/// The closing delimiter, if any.
final Piece? _rightBracket;
@override
List<State> get additionalStates => [if (_elements.isNotEmpty) State.split];
@override
void format(CodeWriter writer, State state) {
writer.setAllowNewlines(state == State.split);
if (_leftBracket case var leftBracket?) {
writer.format(leftBracket);
writer.splitIf(state == State.split,
space: false, indent: _elements.firstOrNull?.indent ?? 0);
}
for (var i = 0; i < _elements.length; i++) {
var element = _elements[i];
writer.format(element.piece);
for (var comment in element.hangingComments) {
writer.space();
writer.format(comment);
}
if (i < _elements.length - 1) {
writer.newline(
blank: element.blankAfter, indent: _elements[i + 1].indent);
}
}
if (_rightBracket case var rightBracket?) {
writer.splitIf(state == State.split, space: false, indent: Indent.none);
writer.format(rightBracket);
}
}
@override
void forEachChild(void Function(Piece piece) callback) {
if (_leftBracket case var leftBracket?) callback(leftBracket);
for (var element in _elements) {
callback(element.piece);
for (var comment in element.hangingComments) {
callback(comment);
}
}
if (_rightBracket case var rightBracket?) callback(rightBracket);
}
@override
String get debugName => 'Seq';
}
/// An element inside a [SequencePiece].
///
/// Tracks the underlying [Piece] along with surrounding whitespace.
class SequenceElement {
/// 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;
SequenceElement(this.indent, this.piece);
}