From 5485ef206ffd79dd657a23fc54631cb5f3477305 Mon Sep 17 00:00:00 2001 From: Rich McKeever Date: Mon, 22 Jun 2026 11:36:25 -0700 Subject: [PATCH] Make the DSLX Formatter class overridable and refactor standalone helpers. The immediate use case is to provide an option to convert procs to the new syntax, which will be implemented in a follow-up by passing in an overridden Formatter from the dslx_fmt entry point. PiperOrigin-RevId: 936165408 --- xls/dslx/fmt/ast_fmt.cc | 2102 ++++++++++++++++------------------ xls/dslx/fmt/ast_fmt.h | 211 +++- xls/dslx/fmt/ast_fmt_test.cc | 59 +- 3 files changed, 1218 insertions(+), 1154 deletions(-) diff --git a/xls/dslx/fmt/ast_fmt.cc b/xls/dslx/fmt/ast_fmt.cc index 1d9208fda9..18440007dc 100644 --- a/xls/dslx/fmt/ast_fmt.cc +++ b/xls/dslx/fmt/ast_fmt.cc @@ -51,7 +51,6 @@ #include "xls/dslx/frontend/ast.h" #include "xls/dslx/frontend/ast_cloner.h" #include "xls/dslx/frontend/ast_node.h" -#include "xls/dslx/frontend/ast_utils.h" #include "xls/dslx/frontend/comment_data.h" #include "xls/dslx/frontend/module.h" #include "xls/dslx/frontend/pos.h" @@ -63,15 +62,14 @@ #include "xls/ir/format_strings.h" namespace xls::dslx { -namespace { // Note: if a comment doc is emitted (i.e. return value has_value()) it does not // have a trailing hard-line. This is for consistency with other emission // routines which generally don't emit any whitespace afterwards, just their // doc. -std::optional EmitCommentsBetween( - std::optional start_pos, const Pos& limit_pos, Comments& comments, - DocArena& arena, std::optional* last_comment_span) { +std::optional Formatter::FormatCommentsBetween( + std::optional start_pos, const Pos& limit_pos, + std::optional* last_comment_span) { if (!start_pos.has_value()) { start_pos = Pos(limit_pos.fileno(), 0, 0); } @@ -83,17 +81,17 @@ std::optional EmitCommentsBetween( } const Span span(start_pos.value(), limit_pos); - const FileTable& file_table = arena.file_table(); + const FileTable& file_table = arena_.file_table(); VLOG(3) << "Looking for comments in span: " << span.ToString(file_table); std::vector pieces; - std::vector items = comments.GetComments(span); + std::vector items = comments_.GetComments(span); VLOG(3) << "Found " << items.size() << " comment data items"; std::optional previous_comment_span; for (size_t i = 0; i < items.size(); ++i) { const CommentData* comment_data = items[i]; - comments.PlaceComment(comment_data); + comments_.PlaceComment(comment_data); // If the previous comment line and this comment line are abutted (i.e. // contiguous lines with comments), we don't put a newline between them. @@ -105,15 +103,15 @@ std::optional EmitCommentsBetween( << " this comment span: " << comment_data->span.ToString(file_table) << " -- inserting hard line"; - pieces.push_back(arena.hard_line()); + pieces.push_back(arena_.hard_line()); } - pieces.push_back(arena.MakePrefixedReflow( + pieces.push_back(arena_.MakePrefixedReflow( "//", std::string{absl::StripTrailingAsciiWhitespace(comment_data->text)})); if (i + 1 != items.size()) { - pieces.push_back(arena.hard_line()); + pieces.push_back(arena_.hard_line()); } previous_comment_span = comment_data->span; @@ -126,7 +124,7 @@ std::optional EmitCommentsBetween( return std::nullopt; } - return ConcatN(arena, pieces); + return ConcatN(arena_, pieces); } // If there is a '.' modifier in the attribute given by s (e.g. if it's of the @@ -135,7 +133,7 @@ std::optional EmitCommentsBetween( // // TODO(https://github.com/google/xls/issues/1029): 2023-12-05 Ideally we'd have // proc references and avoid strange modifiers on identifiers. -std::string StripAnyDotModifier(std::string_view s) { +static std::string StripAnyDotModifier(std::string_view s) { CHECK_LE(std::count(s.begin(), s.end(), '.'), 1); // Check for special identifier for proc config, which is ProcName.config // internally, but in spawns we just want to say ProcName. @@ -146,118 +144,84 @@ std::string StripAnyDotModifier(std::string_view s) { return std::string(s); } -// Forward decls. -// keep-sorted start -DocRef Fmt(const ColonRef& n, Comments& comments, DocArena& arena); -DocRef Fmt(const Expr& n, Comments& comments, DocArena& arena); -DocRef Fmt(const NameDefTree& n, Comments& comments, DocArena& arena); -DocRef Fmt(const TypeAnnotation& n, Comments& comments, DocArena& arena); -DocRef FmtBlockedExprLeader(const Expr& e, Comments& comments, DocArena& arena); -DocRef FmtExpr(const Expr& n, Comments& comments, DocArena& arena, - bool suppress_parens); -DocRef FmtExprOrType(const ExprOrType& n, Comments& comments, DocArena& arena); -// keep-sorted end - // A parametric argument, as in parametric instantiation: // // f() // ^^^^^^^^^^~~~ parametric argument, expr or types can go here generally -DocRef FmtParametricArg(const ExprOrType& n, Comments& comments, - DocArena& arena) { +DocRef Formatter::FormatParametricArg(const ExprOrType& n) { return absl::visit( Visitor{ [&](const Expr* n) { - DocRef guts = Fmt(*n, comments, arena); + DocRef guts = FormatExpr(*n); if (dynamic_cast(n) != nullptr || dynamic_cast(n) != nullptr || dynamic_cast(n) != nullptr) { return guts; // No need for enclosing curlies. } - return ConcatN(arena, {arena.ocurl(), guts, arena.ccurl()}); + return ConcatN(arena_, {arena_.ocurl(), guts, arena_.ccurl()}); }, - [&](const TypeAnnotation* n) { return Fmt(*n, comments, arena); }, + [&](const TypeAnnotation* n) { return FormatTypeAnnotation(*n); }, }, n); } -DocRef FmtExprPtr(const Expr* n, Comments& comments, DocArena& arena) { +DocRef Formatter::Format(const Expr* n) { CHECK(n != nullptr); - return Fmt(*n, comments, arena); + return FormatExpr(*n); } -enum class Joiner : uint8_t { - kCommaSpace, - kCommaBreak1, - - kCommaHardlineTrailingCommaAlways, - - // Separates via a comma and break1, but groups the element with its - // delimiter. This is useful when we're packing member elements that we want - // to be reflowed across lines. - // - // Note that, in this mode, if we span multiple lines, we'll put a trailing - // comma as well. - kCommaBreak1AsGroupTrailingCommaOnBreak, - kCommaBreak1AsGroupTrailingCommaAlways, - kCommaBreak1AsGroupNoTrailingComma, - - kSpaceBarBreak, - kHardLine, -}; - // Helper for doing a "join via comma space" pattern with doc refs. // // This elides the "joiner" being present after the last item. template -DocRef FmtJoin(absl::Span items, Joiner joiner, - const std::function& fmt, - Comments& comments, DocArena& arena) { +DocRef Formatter::FormatJoin(absl::Span items, Joiner joiner, + const std::function& fmt) { std::vector pieces; for (size_t i = 0; i < items.size(); ++i) { const T& item = items[i]; // First we format the member into a doc and then decide the best way to put // it into the sequence. - DocRef member = fmt(item, comments, arena); + DocRef member = fmt(item); if (i + 1 != items.size()) { // Not the last item. switch (joiner) { case Joiner::kCommaSpace: pieces.push_back(member); - pieces.push_back(arena.comma()); - pieces.push_back(arena.space()); + pieces.push_back(arena_.comma()); + pieces.push_back(arena_.space()); break; case Joiner::kCommaHardlineTrailingCommaAlways: pieces.push_back(member); - pieces.push_back(arena.comma()); - pieces.push_back(arena.hard_line()); + pieces.push_back(arena_.comma()); + pieces.push_back(arena_.hard_line()); break; case Joiner::kCommaBreak1: pieces.push_back(member); - pieces.push_back(arena.comma()); - pieces.push_back(arena.break1()); + pieces.push_back(arena_.comma()); + pieces.push_back(arena_.break1()); break; case Joiner::kCommaBreak1AsGroupNoTrailingComma: case Joiner::kCommaBreak1AsGroupTrailingCommaOnBreak: case Joiner::kCommaBreak1AsGroupTrailingCommaAlways: { std::vector this_pieces; if (i != 0) { // If it's the first item we don't put a leading space. - this_pieces.push_back(arena.break1()); + this_pieces.push_back(arena_.break1()); } this_pieces.push_back(member); - this_pieces.push_back(arena.comma()); - pieces.push_back(ConcatNGroup(arena, this_pieces)); + this_pieces.push_back(arena_.comma()); + pieces.push_back(ConcatNGroup(arena_, this_pieces)); break; } case Joiner::kSpaceBarBreak: pieces.push_back(member); - pieces.push_back(arena.space()); - pieces.push_back(arena.bar()); - pieces.push_back(arena.break1()); + pieces.push_back(arena_.space()); + pieces.push_back(arena_.bar()); + pieces.push_back(arena_.break1()); break; case Joiner::kHardLine: pieces.push_back(member); - pieces.push_back(arena.hard_line()); + pieces.push_back(arena_.hard_line()); break; } } else { // Last item, generally "no trailing delimiter". @@ -270,22 +234,22 @@ DocRef FmtJoin(absl::Span items, Joiner joiner, if (i == 0) { pieces.push_back(member); } else { - pieces.push_back(ConcatNGroup(arena, {arena.break1(), member})); + pieces.push_back(ConcatNGroup(arena_, {arena_.break1(), member})); } if (joiner == Joiner::kCommaBreak1AsGroupTrailingCommaOnBreak) { // With this pattern if we're in break mode (implying we spanned // multiple lines), we allow a trailing comma. pieces.push_back( - arena.MakeFlatChoice(arena.empty(), arena.comma())); + arena_.MakeFlatChoice(arena_.empty(), arena_.comma())); } else if (joiner == Joiner::kCommaBreak1AsGroupTrailingCommaAlways) { - pieces.push_back(arena.comma()); + pieces.push_back(arena_.comma()); } break; } case Joiner::kCommaHardlineTrailingCommaAlways: pieces.push_back(member); - pieces.push_back(arena.comma()); + pieces.push_back(arena_.comma()); break; default: pieces.push_back(member); @@ -293,263 +257,248 @@ DocRef FmtJoin(absl::Span items, Joiner joiner, } } } - return ConcatNGroup(arena, pieces); + return ConcatNGroup(arena_, pieces); } -DocRef Fmt(const Lambda& n, Comments& comments, DocArena& arena) { - DocRef body = Fmt(*n.body(), comments, arena); - DocRef params = FmtJoin( +DocRef Formatter::FormatLambda(const Lambda& n) { + DocRef body = FormatExpr(*n.body()); + DocRef params = FormatJoin( n.params(), Joiner::kCommaBreak1AsGroupNoTrailingComma, - [](const Param* param, Comments& comments, DocArena& arena) { - DocRef id = arena.MakeText(param->identifier()); + [this](const Param* param) { + DocRef id = arena_.MakeText(param->identifier()); if (auto* tvta = dynamic_cast( param->type_annotation()); tvta != nullptr && tvta->internal()) { return id; } - DocRef type = Fmt(*param->type_annotation(), comments, arena); - return ConcatN(arena, {id, arena.colon(), arena.space(), type}); - }, - comments, arena); + DocRef type = FormatTypeAnnotation(*param->type_annotation()); + return ConcatN(arena_, {id, arena_.colon(), arena_.space(), type}); + }); - std::vector pieces = {arena.bar(), params, arena.bar(), - arena.space()}; + std::vector pieces = {arena_.bar(), params, arena_.bar(), + arena_.space()}; if (n.ExplicitReturn()) { - pieces.push_back(arena.arrow()); - pieces.push_back(arena.space()); - pieces.push_back(Fmt(*n.return_type(), comments, arena)); - pieces.push_back(arena.space()); + pieces.push_back(arena_.arrow()); + pieces.push_back(arena_.space()); + pieces.push_back(FormatTypeAnnotation(*n.return_type())); + pieces.push_back(arena_.space()); } pieces.push_back(body); - return ConcatNGroup(arena, pieces); -} - -DocRef Fmt(const BuiltinTypeAnnotation& n, Comments& comments, - DocArena& arena) { - return arena.MakeText(BuiltinTypeToString(n.builtin_type())); + return ConcatNGroup(arena_, pieces); } -DocRef Fmt(const VerbatimNode& n, Comments& comments, DocArena& arena) { - return Formatter(comments, arena).Format(n); +DocRef Formatter::FormatBuiltinTypeAnnotation(const BuiltinTypeAnnotation& n) { + return arena_.MakeText(BuiltinTypeToString(n.builtin_type())); } -DocRef Fmt(const ArrayTypeAnnotation& n, Comments& comments, DocArena& arena) { - DocRef elem = Fmt(*n.element_type(), comments, arena); - DocRef dim = Fmt(*n.dim(), comments, arena); - +DocRef Formatter::FormatArrayTypeAnnotation(const ArrayTypeAnnotation& n) { return ConcatNGroup( - arena, {elem, arena.obracket(), arena.MakeAlign(dim), arena.cbracket()}); + arena_, {FormatTypeAnnotation(*n.element_type()), arena_.obracket(), + arena_.MakeAlign(FormatExpr(*n.dim())), arena_.cbracket()}); } -DocRef FmtTypeAnnotationPtr(const TypeAnnotation* n, Comments& comments, - DocArena& arena) { +DocRef Formatter::Format(const TypeAnnotation* n) { CHECK(n != nullptr); - return Fmt(*n, comments, arena); + return FormatTypeAnnotation(*n); } -DocRef Fmt(const TupleTypeAnnotation& n, Comments& comments, DocArena& arena) { - DocRef guts = FmtJoin( +DocRef Formatter::FormatTupleTypeAnnotation(const TupleTypeAnnotation& n) { + DocRef guts = FormatJoin( n.members(), Joiner::kCommaBreak1AsGroupNoTrailingComma, - FmtTypeAnnotationPtr, comments, arena); + [this](const TypeAnnotation* t) { return Format(t); }); return ConcatNGroup( - arena, { - arena.oparen(), - arena.MakeFlatChoice( - /*on_flat=*/guts, - /*on_break=*/ConcatNGroup(arena, - { - arena.hard_line(), - arena.MakeNest(guts), - arena.hard_line(), - })), - arena.cparen(), - }); -} - -DocRef Fmt(const TypeRef& n, Comments& comments, DocArena& arena) { + arena_, { + arena_.oparen(), + arena_.MakeFlatChoice( + /*on_flat=*/guts, + /*on_break=*/ConcatNGroup(arena_, + { + arena_.hard_line(), + arena_.MakeNest(guts), + arena_.hard_line(), + })), + arena_.cparen(), + }); +} +DocRef Formatter::FormatTypeRef(const TypeRef& n) { return absl::visit( Visitor{ - [&](const ColonRef* n) { return Fmt(*n, comments, arena); }, + [&](const ColonRef* n) { return FormatColonRef(*n); }, [&](const UseTreeEntry* n) { std::string_view identifier = n->GetLeafNameDef().value()->identifier(); - return arena.MakeText(std::string(identifier)); + return arena_.MakeText(std::string(identifier)); }, - [&](const auto* n) { return arena.MakeText(n->identifier()); }, + [&](const auto* n) { return arena_.MakeText(n->identifier()); }, }, n.type_definition()); } -DocRef Fmt(const TypeRefTypeAnnotation& n, Comments& comments, - DocArena& arena) { - std::vector pieces = {Fmt(*n.type_ref(), comments, arena)}; +DocRef Formatter::FormatTypeRefTypeAnnotation(const TypeRefTypeAnnotation& n) { + std::vector pieces = {FormatTypeRef(*n.type_ref())}; if (!n.parametrics().empty()) { - pieces.push_back(arena.oangle()); - pieces.push_back(FmtJoin(absl::MakeConstSpan(n.parametrics()), - Joiner::kCommaSpace, FmtParametricArg, - comments, arena)); - pieces.push_back(arena.cangle()); + pieces.push_back(arena_.oangle()); + pieces.push_back(FormatJoin( + absl::MakeConstSpan(n.parametrics()), Joiner::kCommaSpace, + [this](const ExprOrType& e) { return FormatParametricArg(e); })); + pieces.push_back(arena_.cangle()); } - - return ConcatNGroup(arena, pieces); + return ConcatNGroup(arena_, pieces); } -DocRef Fmt(const ChannelTypeAnnotation& n, Comments& comments, - DocArena& arena) { +DocRef Formatter::FormatChannelTypeAnnotation(const ChannelTypeAnnotation& n) { std::vector pieces = { - arena.Make(Keyword::kChan), - arena.oangle(), - Fmt(*n.payload(), comments, arena), - arena.cangle(), + arena_.Make(Keyword::kChan), + arena_.oangle(), + FormatTypeAnnotation(*n.payload()), + arena_.cangle(), }; if (n.dims().has_value()) { + pieces.reserve(pieces.size() + 3 * n.dims()->size()); for (const Expr* dim : *n.dims()) { - pieces.push_back(arena.obracket()); - pieces.push_back(Fmt(*dim, comments, arena)); - pieces.push_back(arena.cbracket()); + pieces.push_back(arena_.obracket()); + pieces.push_back(FormatExpr(*dim)); + pieces.push_back(arena_.cbracket()); } } - pieces.push_back(arena.space()); - pieces.push_back(arena.Make( + pieces.push_back(arena_.space()); + pieces.push_back(arena_.Make( n.direction() == ChannelDirection::kIn ? Keyword::kIn : Keyword::kOut)); - return ConcatNGroup(arena, pieces); + return ConcatNGroup(arena_, pieces); } -DocRef Fmt(const TypeVariableTypeAnnotation& n, Comments& comments, - DocArena& arena) { - std::vector pieces = {Fmt(*n.type_variable(), comments, arena)}; - return ConcatNGroup(arena, pieces); +DocRef Formatter::FormatTypeVariableTypeAnnotation( + const TypeVariableTypeAnnotation& n) { + std::vector pieces = {FormatNameRef(*n.type_variable())}; + return ConcatNGroup(arena_, pieces); } -DocRef Fmt(const TypeAnnotation& n, Comments& comments, DocArena& arena) { +DocRef Formatter::FormatTypeAnnotation(const TypeAnnotation& n) { if (auto* t = dynamic_cast(&n)) { - return Fmt(*t, comments, arena); + return FormatBuiltinTypeAnnotation(*t); } if (auto* t = dynamic_cast(&n)) { - return Fmt(*t, comments, arena); + return FormatTupleTypeAnnotation(*t); } if (auto* t = dynamic_cast(&n)) { - return Fmt(*t, comments, arena); + return FormatArrayTypeAnnotation(*t); } if (auto* t = dynamic_cast(&n)) { - return Fmt(*t, comments, arena); + return FormatTypeRefTypeAnnotation(*t); } if (auto* t = dynamic_cast(&n)) { - return Fmt(*t, comments, arena); + return FormatChannelTypeAnnotation(*t); } if (auto* t = dynamic_cast(&n)) { - return Fmt(*t, comments, arena); + return FormatTypeVariableTypeAnnotation(*t); } if (dynamic_cast(&n)) { - return arena.Make(Keyword::kType); + return arena_.Make(Keyword::kType); } if (dynamic_cast(&n)) { - return arena.Make(Keyword::kSelfType); + return arena_.Make(Keyword::kSelfType); } LOG(FATAL) << "handle type annotation: " << n.ToString() << " type: " << n.GetNodeTypeName(); } - -DocRef JoinWithAttrs(absl::Span attrs, DocRef rest, - DocArena& arena) { +DocRef Formatter::FormatJoinWithAttrs(absl::Span attrs, + DocRef rest) { if (attrs.empty()) { return rest; } - return arena.MakeConcat(ConcatNGroup(arena, attrs), rest); + return arena_.MakeConcat(ConcatNGroup(arena_, attrs), rest); } -DocRef JoinWithAttr(std::optional attr, DocRef rest, DocArena& arena) { +DocRef Formatter::FormatJoinWithAttr(std::optional attr, DocRef rest) { std::vector attrs; if (attr.has_value()) { attrs.push_back(*attr); } - return JoinWithAttrs(attrs, rest, arena); + return FormatJoinWithAttrs(attrs, rest); } -DocRef FmtAttribute(const Attribute& attribute, DocArena& arena) { +DocRef Formatter::FormatAttribute(const Attribute& n) { std::vector pieces; - pieces.push_back(arena.MakeText("#")); - pieces.push_back(arena.obracket()); - pieces.push_back( - arena.MakeText(AttributeKindToString(attribute.attribute_kind()))); + pieces.push_back(arena_.MakeText("#")); + pieces.push_back(arena_.obracket()); + pieces.push_back(arena_.MakeText(AttributeKindToString(n.attribute_kind()))); - if (!attribute.args().empty()) { - pieces.push_back(arena.oparen()); - const std::vector& args = attribute.args(); + if (!n.args().empty()) { + pieces.push_back(arena_.oparen()); + const std::vector& args = n.args(); for (size_t i = 0; i < args.size(); ++i) { const AttributeData::Argument& arg = args[i]; absl::visit( Visitor{ - [&](std::string str) { pieces.push_back(arena.MakeText(str)); }, + [&](std::string str) { pieces.push_back(arena_.MakeText(str)); }, [&](AttributeData::StringLiteralArgument arg) { pieces.push_back( - arena.MakeText(absl::Substitute("\"$0\"", arg.text))); + arena_.MakeText(absl::Substitute("\"$0\"", arg.text))); }, [&](AttributeData::IntKeyValueArgument arg) { - pieces.push_back(arena.MakeText( + pieces.push_back(arena_.MakeText( absl::Substitute("$0=$1", arg.first, arg.second))); }, [&](AttributeData::StringKeyValueArgument arg) { if (arg.is_backticked) { - pieces.push_back(arena.MakeText( + pieces.push_back(arena_.MakeText( absl::Substitute("$0=`$1`", arg.first, arg.second))); } else { - pieces.push_back(arena.MakeText( + pieces.push_back(arena_.MakeText( absl::Substitute("$0=$1", arg.first, arg.second))); } }, }, arg); if (i < args.size() - 1) { - pieces.push_back(arena.comma()); - pieces.push_back(arena.space()); + pieces.push_back(arena_.comma()); + pieces.push_back(arena_.space()); } } - pieces.push_back(arena.cparen()); + pieces.push_back(arena_.cparen()); } - pieces.push_back(arena.cbracket()); - pieces.push_back(arena.hard_line()); - return ConcatNGroup(arena, pieces); + pieces.push_back(arena_.cbracket()); + pieces.push_back(arena_.hard_line()); + return ConcatNGroup(arena_, pieces); } -DocRef FmtChannelAttribute(const ChannelConfig& config, DocArena& arena) { +DocRef Formatter::FormatChannelConfig(const ChannelConfig& n) { std::vector pieces{ - arena.MakeText("#"), - arena.obracket(), - arena.MakeText("channel"), - arena.oparen(), + arena_.MakeText("#"), + arena_.obracket(), + arena_.MakeText("channel"), + arena_.oparen(), }; - for (const auto& [idx, key_value] : - ::iter::enumerate(config.GetDslxKwargs())) { + for (const auto& [idx, key_value] : ::iter::enumerate(n.GetDslxKwargs())) { const auto& [key, value] = key_value; - pieces.push_back(arena.MakeText(key)); - pieces.push_back(arena.equals()); - pieces.push_back(arena.MakeText(value)); - if (idx < config.GetDslxKwargs().size() - 1) { - pieces.push_back(arena.comma()); - pieces.push_back(arena.space()); + pieces.push_back(arena_.MakeText(key)); + pieces.push_back(arena_.equals()); + pieces.push_back(arena_.MakeText(value)); + if (idx < n.GetDslxKwargs().size() - 1) { + pieces.push_back(arena_.comma()); + pieces.push_back(arena_.space()); } } - pieces.push_back(arena.cparen()); - pieces.push_back(arena.cbracket()); - pieces.push_back(arena.hard_line()); - return ConcatNGroup(arena, pieces); + pieces.push_back(arena_.cparen()); + pieces.push_back(arena_.cbracket()); + pieces.push_back(arena_.hard_line()); + return ConcatNGroup(arena_, pieces); } -DocRef Fmt(const NameDef& n, Comments& comments, DocArena& arena) { - return arena.MakeText(n.identifier()); +DocRef Formatter::FormatNameDef(const NameDef& n) { + return arena_.MakeText(n.identifier()); } -DocRef Fmt(const NameRef& n, Comments& comments, DocArena& arena) { - return arena.MakeText(StripAnyDotModifier(n.identifier())); +DocRef Formatter::FormatNameRef(const NameRef& n) { + return arena_.MakeText(StripAnyDotModifier(n.identifier())); } -DocRef Fmt(const Number& n, Comments& comments, DocArena& arena) { +DocRef Formatter::FormatNumber(const Number& n) { DocRef num_text; if (n.number_kind() == NumberKind::kCharacter) { // Note: we don't need to escape double quote because this is going to end @@ -560,133 +509,132 @@ DocRef Fmt(const Number& n, Comments& comments, DocArena& arena) { } else { guts = Escape(n.text()); // Everything else we do normal C-string escape. } - num_text = arena.MakeText(absl::StrFormat("'%s'", guts)); + num_text = arena_.MakeText(absl::StrFormat("'%s'", guts)); } else { - num_text = arena.MakeText(n.text()); + num_text = arena_.MakeText(n.text()); } if (const TypeAnnotation* type = n.type_annotation()) { - return ConcatNGroup(arena, - {Fmt(*type, comments, arena), arena.colon(), num_text}); + return ConcatNGroup( + arena_, {FormatTypeAnnotation(*type), arena_.colon(), num_text}); } return num_text; } -DocRef Fmt(const WildcardPattern& n, Comments& comments, DocArena& arena) { - return arena.underscore(); +DocRef Formatter::FormatWildcardPattern(const WildcardPattern& n) { + return arena_.underscore(); } -DocRef Fmt(const RestOfTuple& n, Comments& comments, DocArena& arena) { - return arena.dot_dot(); +DocRef Formatter::FormatRestOfTuple(const RestOfTuple& n) { + return arena_.dot_dot(); } -DocRef MakeArrayLeader(const Array& n, Comments& comments, DocArena& arena) { +DocRef Formatter::FormatMakeArrayLeader(const Array& n) { const TypeAnnotation* t = n.type_annotation(); if (t == nullptr) { - return arena.obracket(); + return arena_.obracket(); } std::vector pieces; - pieces.push_back(Fmt(*t, comments, arena)); - pieces.push_back(arena.colon()); - pieces.push_back(arena.obracket()); - return ConcatN(arena, pieces); + pieces.push_back(FormatTypeAnnotation(*t)); + pieces.push_back(arena_.colon()); + pieces.push_back(arena_.obracket()); + return ConcatN(arena_, pieces); } -DocRef FmtFlatBody(const Array& n, Comments& comments, DocArena& arena) { +DocRef Formatter::FormatFlatBody(const Array& n) { std::vector flat_pieces; - flat_pieces.push_back(FmtJoin(n.members(), Joiner::kCommaSpace, - FmtExprPtr, comments, arena)); + flat_pieces.push_back( + FormatJoin(n.members(), Joiner::kCommaSpace, + [this](const Expr* e) { return Format(e); })); if (n.has_ellipsis()) { // Note: while zero members with ellipsis is invalid at type checking, we // may choose not to flag it as a parse-time error, in which case we could // have it in the AST. if (!n.members().empty()) { - flat_pieces.push_back(arena.comma()); + flat_pieces.push_back(arena_.comma()); } - flat_pieces.push_back(arena.space()); - flat_pieces.push_back(arena.MakeText("...")); + flat_pieces.push_back(arena_.space()); + flat_pieces.push_back(arena_.MakeText("...")); } - flat_pieces.push_back(arena.cbracket()); - return ConcatN(arena, flat_pieces); + flat_pieces.push_back(arena_.cbracket()); + return ConcatN(arena_, flat_pieces); } -DocRef FmtBreakBody(const Array& n, Comments& comments, DocArena& arena) { +DocRef Formatter::FormatBreakBody(const Array& n) { std::vector rest; - rest.push_back(arena.break0()); + rest.push_back(arena_.break0()); std::vector member_pieces; - member_pieces.push_back(FmtJoin( - n.members(), Joiner::kCommaBreak1AsGroupTrailingCommaAlways, FmtExprPtr, - comments, arena)); + member_pieces.push_back(FormatJoin( + n.members(), Joiner::kCommaBreak1AsGroupTrailingCommaAlways, + [this](const Expr* e) { return Format(e); })); if (n.has_ellipsis()) { member_pieces.push_back( - ConcatNGroup(arena, {arena.break1(), arena.MakeText("...")})); + ConcatNGroup(arena_, {arena_.break1(), arena_.MakeText("...")})); } - DocRef inner = ConcatNGroup(arena, member_pieces); - rest.push_back(arena.MakeFlatChoice(inner, arena.MakeNest(inner))); - rest.push_back(arena.break0()); - rest.push_back(arena.cbracket()); + DocRef inner = ConcatNGroup(arena_, member_pieces); + rest.push_back(arena_.MakeFlatChoice(inner, arena_.MakeNest(inner))); + rest.push_back(arena_.break0()); + rest.push_back(arena_.cbracket()); - return ConcatNGroup(arena, rest); + return ConcatNGroup(arena_, rest); } -DocRef Fmt(const Array& n, Comments& comments, DocArena& arena) { - DocRef on_break_body = FmtBreakBody(n, comments, arena); - DocRef on_flat_body = FmtFlatBody(n, comments, arena); +DocRef Formatter::FormatArray(const Array& n) { + DocRef on_break_body = FormatBreakBody(n); + DocRef on_flat_body = FormatFlatBody(n); - DocRef body = arena.MakeGroup(arena.MakeFlatChoice( + DocRef body = arena_.MakeGroup(arena_.MakeFlatChoice( /*on_flat=*/on_flat_body, /*on_break=*/on_break_body)); - return arena.MakeConcat(MakeArrayLeader(n, comments, arena), body); + return arena_.MakeConcat(FormatMakeArrayLeader(n), body); } -DocRef Fmt(const Attr& n, Comments& comments, DocArena& arena) { +DocRef Formatter::FormatAttr(const Attr& n) { Precedence op_precedence = n.GetPrecedenceWithoutParens(); const Expr& lhs = *n.lhs(); Precedence lhs_precedence = lhs.GetPrecedence(); std::vector pieces; if (WeakerThan(lhs_precedence, op_precedence) && IsInfix(lhs_precedence)) { - pieces.push_back(arena.oparen()); - pieces.push_back(Fmt(lhs, comments, arena)); - pieces.push_back(arena.cparen()); + pieces.push_back(arena_.oparen()); + pieces.push_back(FormatExpr(lhs)); + pieces.push_back(arena_.cparen()); } else { - pieces.push_back(Fmt(lhs, comments, arena)); + pieces.push_back(FormatExpr(lhs)); } - pieces.push_back(arena.dot()); - pieces.push_back(arena.MakeText(std::string{n.attr()})); - return ConcatNGroup(arena, pieces); + pieces.push_back(arena_.dot()); + pieces.push_back(arena_.MakeText(std::string{n.attr()})); + return ConcatNGroup(arena_, pieces); } -std::optional EmitCommentsNested(const Pos start, const Pos limit, - Comments& comments, DocArena& arena) { +std::optional Formatter::FormatCommentsNested(const Pos start, + const Pos limit) { std::vector items = - comments.GetComments(Span(start, limit)); + comments_.GetComments(Span(start, limit)); if (items.empty()) { return std::nullopt; } std::vector pieces; // Add the first comment "in line" - auto first = - EmitCommentsBetween(start, items[0]->span.limit(), comments, arena, - /*last_comment_span=*/nullptr); + auto first = FormatCommentsBetween(start, items[0]->span.limit(), + /*last_comment_span=*/nullptr); pieces.push_back(*first); - pieces.push_back(arena.hard_line()); + pieces.push_back(arena_.hard_line()); if (items.size() > 1) { // Add the nth through last comment as a new nested document. - auto nested_comments = - EmitCommentsBetween(items[1]->span.start(), limit, comments, arena, - /*last_comment_span=*/nullptr); + auto nested_comments = FormatCommentsBetween(items[1]->span.start(), limit, + /*last_comment_span=*/nullptr); // EmitCommentsBetween doesn't indent (or nest) the 2nd through Nth // comments, so we have to do it manually here. - pieces.push_back(arena.MakeNest(*nested_comments)); - pieces.push_back(arena.hard_line()); + pieces.push_back(arena_.MakeNest(*nested_comments)); + pieces.push_back(arena_.hard_line()); } - return ConcatN(arena, pieces); + return ConcatN(arena_, pieces); } -DocRef Fmt(const Binop& n, Comments& comments, DocArena& arena) { +DocRef Formatter::FormatBinop(const Binop& n) { Precedence op_precedence = n.GetPrecedenceWithoutParens(); const Expr& lhs = *n.lhs(); const Expr& rhs = *n.rhs(); @@ -694,11 +642,11 @@ DocRef Fmt(const Binop& n, Comments& comments, DocArena& arena) { auto emit = [&](const Expr& e, bool parens, std::vector& pieces) { if (parens) { - pieces.push_back(arena.oparen()); - pieces.push_back(Fmt(e, comments, arena)); - pieces.push_back(arena.cparen()); + pieces.push_back(arena_.oparen()); + pieces.push_back(FormatExpr(e)); + pieces.push_back(arena_.cparen()); } else { - pieces.push_back(Fmt(e, comments, arena)); + pieces.push_back(FormatExpr(e)); } }; @@ -723,38 +671,38 @@ DocRef Fmt(const Binop& n, Comments& comments, DocArena& arena) { emit(lhs, /*parens=*/false, lhs_pieces); } - DocRef lhs_ref = ConcatN(arena, lhs_pieces); + DocRef lhs_ref = ConcatN(arena_, lhs_pieces); bool nest_rhs = false; // If there are comments between the LHS and the operator, we want to emit // them before the operator. - if (std::optional comments_doc = EmitCommentsNested( - lhs.span().limit(), n.op_span().start(), comments, arena)) { - lhs_ref = ConcatN(arena, {lhs_ref, arena.space(), *comments_doc}); + if (std::optional comments_doc = + FormatCommentsNested(lhs.span().limit(), n.op_span().start())) { + lhs_ref = ConcatN(arena_, {lhs_ref, arena_.space(), *comments_doc}); nest_rhs = true; } bool emitted_op = false; // If there are comments between the operator and the RHS, emit them now. if (nest_rhs) { - if (std::optional comments_doc = EmitCommentsBetween( - n.op_span().limit(), rhs.span().start(), comments, arena, - /*last_comment_span=*/nullptr)) { + if (std::optional comments_doc = + FormatCommentsBetween(n.op_span().limit(), rhs.span().start(), + /*last_comment_span=*/nullptr)) { // If the RHS is already being nested, don't nest the comments. probably. lhs_ref = ConcatN( - arena, + arena_, {lhs_ref, - arena.MakeNest(ConcatN( - arena, {arena.MakeText(BinopKindFormat(n.binop_kind())), - arena.space(), *comments_doc, arena.hard_line()}))}); + arena_.MakeNest(ConcatN( + arena_, {arena_.MakeText(BinopKindFormat(n.binop_kind())), + arena_.space(), *comments_doc, arena_.hard_line()}))}); emitted_op = true; } - } else if (std::optional comments_doc = EmitCommentsNested( - n.op_span().limit(), rhs.span().start(), comments, arena)) { + } else if (std::optional comments_doc = FormatCommentsNested( + n.op_span().limit(), rhs.span().start())) { // The space is needed since we didn't nest the RHS yet - lhs_ref = ConcatN(arena, {lhs_ref, arena.space(), - arena.MakeText(BinopKindFormat(n.binop_kind())), - arena.space(), *comments_doc}); + lhs_ref = ConcatN(arena_, {lhs_ref, arena_.space(), + arena_.MakeText(BinopKindFormat(n.binop_kind())), + arena_.space(), *comments_doc}); emitted_op = true; nest_rhs = true; } @@ -771,28 +719,28 @@ DocRef Fmt(const Binop& n, Comments& comments, DocArena& arena) { // the left hand term then when we enter break mode the nested RHS terms all // end up on their own lines. See `ModuleFmtTest.NestedBinopLogicalOr` for a // case study. - DocRef rhs_ref = ConcatN(arena, rhs_pieces); + DocRef rhs_ref = ConcatN(arena_, rhs_pieces); std::vector more_rhs_pieces; if (!nest_rhs) { // If we didn't nest the RHS, we need to add a space to separate it from the // operator. - more_rhs_pieces.push_back(arena.space()); + more_rhs_pieces.push_back(arena_.space()); } if (!emitted_op) { // If we didn't emit the operator, we need to add it now. - more_rhs_pieces.push_back(arena.MakeText(BinopKindFormat(n.binop_kind()))); - more_rhs_pieces.push_back(arena.break1()); + more_rhs_pieces.push_back(arena_.MakeText(BinopKindFormat(n.binop_kind()))); + more_rhs_pieces.push_back(arena_.break1()); } more_rhs_pieces.push_back(rhs_ref); - rhs_ref = ConcatNGroup(arena, more_rhs_pieces); + rhs_ref = ConcatNGroup(arena_, more_rhs_pieces); if (nest_rhs) { - rhs_ref = arena.MakeNest(rhs_ref); + rhs_ref = arena_.MakeNest(rhs_ref); } - return ConcatN(arena, { - lhs_ref, - rhs_ref, - }); + return ConcatN(arena_, { + lhs_ref, + rhs_ref, + }); } // EOL-terminated comments we say, in the AST, that the entity's limit was at @@ -802,7 +750,7 @@ DocRef Fmt(const Binop& n, Comments& comments, DocArena& arena) { // // Since we don't record the limit column number for each line to query here, we // just use an absurdly large number (int32_t max). -Pos AdjustCommentLimit(const Span& comment_span, DocArena& arena, +Pos AdjustCommentLimit(const Span& comment_span, DocArena& arena_, DocRef comment_doc) { CHECK_EQ(comment_span.limit().colno(), 0); CHECK_GT(comment_span.limit().lineno(), 0); @@ -812,68 +760,61 @@ Pos AdjustCommentLimit(const Span& comment_span, DocArena& arena, // Looks for inline comments after the `prev_limit` and adds relevant `DocRef` // to `pieces`. Returns `last_entity_pos`, updated if comments were found. -Pos CollectInlineComments(const Pos& prev_limit, const Pos& last_entity_pos, - Comments& comments, DocArena& arena, - std::vector& pieces, - std::optional last_comment_span) { +Pos Formatter::FormatCollectInlineComments( + const Pos& prev_limit, const Pos& last_entity_pos, + std::vector& pieces, std::optional last_comment_span) { const Pos next_line(prev_limit.fileno(), prev_limit.lineno() + 1, 0); - if (std::optional comments_doc = EmitCommentsBetween( - last_entity_pos, next_line, comments, arena, &last_comment_span)) { + if (std::optional comments_doc = FormatCommentsBetween( + last_entity_pos, next_line, &last_comment_span)) { VLOG(3) << "Saw inline comment: " - << arena.ToDebugString(comments_doc.value()) + << arena_.ToDebugString(comments_doc.value()) << " last_comment_span: " - << last_comment_span.value().ToString(arena.file_table()); - pieces.push_back(arena.space()); - pieces.push_back(arena.space()); - pieces.push_back(arena.MakeAlign(comments_doc.value())); + << last_comment_span.value().ToString(arena_.file_table()); + pieces.push_back(arena_.space()); + pieces.push_back(arena_.space()); + pieces.push_back(arena_.MakeAlign(comments_doc.value())); - return AdjustCommentLimit(last_comment_span.value(), arena, + return AdjustCommentLimit(last_comment_span.value(), arena_, comments_doc.value()); } return last_entity_pos; } -DocRef Fmt(const Statement& n, Comments& comments, DocArena& arena, - bool trailing_semi) { - return Formatter(comments, arena).Format(n, trailing_semi); -} - -DocRef FmtSingleStatementBlockInline(const StatementBlock& n, - Comments& comments, bool add_curls, - DocArena& arena) { +DocRef Formatter::FormatSingleStatementBlockInline(const StatementBlock& n, + bool add_curls) { std::vector pieces; if (add_curls) { - pieces = {arena.ocurl(), arena.break1()}; + pieces = {arena_.ocurl(), arena_.break1()}; } - pieces.push_back(Fmt(*n.statements()[0], comments, arena, - /*trailing_semi=*/n.trailing_semi())); + pieces.push_back( + FormatStatement(*n.statements()[0], /*trailing_semi=*/n.trailing_semi())); if (add_curls) { - pieces.push_back(arena.break1()); - pieces.push_back(arena.ccurl()); + pieces.push_back(arena_.break1()); + pieces.push_back(arena_.ccurl()); } - DocRef block_group = ConcatNGroup(arena, pieces); - return arena.MakeFlatChoice(block_group, arena.MakeNest(block_group)); + DocRef block_group = ConcatNGroup(arena_, pieces); + return arena_.MakeFlatChoice(block_group, arena_.MakeNest(block_group)); } // Note: we only add leading/trailing spaces in the block if add_curls is true. -DocRef FmtBlock(const StatementBlock& n, Comments& comments, DocArena& arena, - bool add_curls, bool force_multiline = false) { - bool has_comments = comments.HasComments(n.span()); +DocRef Formatter::FormatBlock(const StatementBlock& n, bool add_curls, + bool force_multiline) { + bool has_comments = comments_.HasComments(n.span()); if (n.statements().empty() && !has_comments) { if (add_curls) { - return ConcatNGroup(arena, - {arena.ocurl(), arena.break0(), arena.ccurl()}); + return ConcatNGroup(arena_, + {arena_.ocurl(), arena_.break0(), arena_.ccurl()}); } - return arena.break0(); + return arena_.break0(); } // We only want to flatten single-statement blocks -- multi-statement blocks // we always make line breaks between the statements. if (n.statements().size() == 1 && !force_multiline && !has_comments) { - return FmtSingleStatementBlockInline(n, comments, add_curls, arena); + return FormatSingleStatementBlockInline(n, add_curls); } // Emit a '{' then nest to emit statements with semis, then emit a '}' outside @@ -881,8 +822,8 @@ DocRef FmtBlock(const StatementBlock& n, Comments& comments, DocArena& arena, std::vector top; if (add_curls) { - top.push_back(arena.ocurl()); - top.push_back(arena.hard_line()); + top.push_back(arena_.ocurl()); + top.push_back(arena_.hard_line()); } // For our initial condition, we say the last entity we emitted is right after @@ -905,33 +846,33 @@ DocRef FmtBlock(const StatementBlock& n, Comments& comments, DocArena& arena, const Pos& stmt_limit = stmt_span->limit(); VLOG(5) << "stmt: `" << stmt->ToString() - << "` span: " << stmt_span.value().ToString(arena.file_table()) + << "` span: " << stmt_span.value().ToString(arena_.file_table()) << " last_entity_pos: " << last_entity_pos; std::optional last_comment_span; - if (std::optional comments_doc = EmitCommentsBetween( - last_entity_pos, stmt_start, comments, arena, &last_comment_span)) { + if (std::optional comments_doc = FormatCommentsBetween( + last_entity_pos, stmt_start, &last_comment_span)) { VLOG(5) << "emitting comment ahead of: `" << stmt->ToString() << "`" << " last entity position: " << last_entity_pos << " last_comment_span: " - << last_comment_span.value().ToString(arena.file_table()); + << last_comment_span.value().ToString(arena_.file_table()); // If there's a line break between the last entity and this comment, we // retain it in the output (i.e. in paragraph style). if (last_entity_pos != start_entity_pos && last_entity_pos.lineno() + 1 < last_comment_span->start().lineno()) { - stmt_pieces.push_back(arena.hard_line()); + stmt_pieces.push_back(arena_.hard_line()); } stmt_pieces.push_back(comments_doc.value()); - stmt_pieces.push_back(arena.hard_line()); + stmt_pieces.push_back(arena_.hard_line()); - last_entity_pos = AdjustCommentLimit(last_comment_span.value(), arena, + last_entity_pos = AdjustCommentLimit(last_comment_span.value(), arena_, comments_doc.value()); // See if we want a line break between the comment we just emitted and the // statement we're about to emit. if (last_entity_pos.lineno() + 1 < stmt_start.lineno()) { - stmt_pieces.push_back(arena.hard_line()); + stmt_pieces.push_back(arena_.hard_line()); } } else { // No comments to emit ahead of the statement. @@ -939,27 +880,26 @@ DocRef FmtBlock(const StatementBlock& n, Comments& comments, DocArena& arena, // If there's a line break between the last entity and this statement, we // retain it in the output (i.e. in paragraph style). if (last_entity_pos.lineno() + 1 < stmt_start.lineno()) { - stmt_pieces.push_back(arena.hard_line()); + stmt_pieces.push_back(arena_.hard_line()); } } // Here we emit the formatted statement. bool last_stmt = i + 1 == n.statements().size(); std::vector stmt_semi = { - Fmt(*stmt, comments, arena, n.trailing_semi() || !last_stmt)}; + FormatStatement(*stmt, n.trailing_semi() || !last_stmt)}; // Now we reflect the emission of the statement. last_entity_pos = stmt_limit; - stmt_pieces.push_back(ConcatNGroup(arena, stmt_semi)); - statements.push_back(ConcatN(arena, stmt_pieces)); + stmt_pieces.push_back(ConcatNGroup(arena_, stmt_semi)); + statements.push_back(ConcatN(arena_, stmt_pieces)); - last_entity_pos = - CollectInlineComments(stmt_limit, last_entity_pos, comments, arena, - statements, last_comment_span); + last_entity_pos = FormatCollectInlineComments( + stmt_limit, last_entity_pos, statements, last_comment_span); if (!last_stmt) { - statements.push_back(arena.hard_line()); + statements.push_back(arena_.hard_line()); } } @@ -970,22 +910,21 @@ DocRef FmtBlock(const StatementBlock& n, Comments& comments, DocArena& arena, // See if there are any comments to emit after the last statement to the end // of the block. std::optional last_comment_span; - if (std::optional comments_doc = - EmitCommentsBetween(last_entity_pos, n.span().limit(), comments, - arena, &last_comment_span)) { + if (std::optional comments_doc = FormatCommentsBetween( + last_entity_pos, n.span().limit(), &last_comment_span)) { VLOG(5) << "last entity position: " << last_entity_pos << " last_comment_span.start: " << last_comment_span->start(); // If there's a line break between the last entity and this comment, we // retain it in the output (i.e. in paragraph style). if (last_entity_pos.lineno() + 1 < last_comment_span->start().lineno()) { - statements.push_back(arena.hard_line()); + statements.push_back(arena_.hard_line()); } if (!last_stmt_was_verbatim) { // Skip the hard line before the last comment if the last one was a // verbatim, because it already included one. - statements.push_back(arena.hard_line()); + statements.push_back(arena_.hard_line()); } statements.push_back(comments_doc.value()); @@ -994,275 +933,273 @@ DocRef FmtBlock(const StatementBlock& n, Comments& comments, DocArena& arena, needs_hardline = true; } - top.push_back(arena.MakeNest(ConcatN(arena, statements))); + top.push_back(arena_.MakeNest(ConcatN(arena_, statements))); if (add_curls) { if (needs_hardline) { - top.push_back(arena.hard_line()); + top.push_back(arena_.hard_line()); } - top.push_back(arena.ccurl()); + top.push_back(arena_.ccurl()); } else { // If we're not putting hard lines in we want to at least check that we'll // force this all into break mode for multi-line emission. // // Note that the "inline block" case is handled specially above. - top.push_back(arena.force_break_mode()); + top.push_back(arena_.force_break_mode()); } - return ConcatNGroup(arena, top); -} - -DocRef Fmt(const StatementBlock& n, Comments& comments, DocArena& arena) { - return FmtBlock(n, comments, arena, /*add_curls=*/n.has_braces()); + return ConcatNGroup(arena_, top); } -DocRef Fmt(const Cast& n, Comments& comments, DocArena& arena) { - DocRef lhs = Fmt(*n.expr(), comments, arena); +DocRef Formatter::FormatCast(const Cast& n) { + DocRef lhs = FormatExpr(*n.expr()); Precedence arg_precedence = n.expr()->GetPrecedence(); if (WeakerThan(arg_precedence, Precedence::kAs)) { - lhs = ConcatN(arena, {arena.oparen(), lhs, arena.cparen()}); + lhs = ConcatN(arena_, {arena_.oparen(), lhs, arena_.cparen()}); } return ConcatNGroup( - arena, {lhs, arena.space(), arena.Make(Keyword::kAs), arena.break1(), - Fmt(*n.type_annotation(), comments, arena)}); + arena_, {lhs, arena_.space(), arena_.Make(Keyword::kAs), arena_.break1(), + FormatTypeAnnotation(*n.type_annotation())}); } -DocRef Fmt(const ChannelDecl& n, Comments& comments, DocArena& arena) { +DocRef Formatter::FormatChannelDecl(const ChannelDecl& n) { std::optional channel_attribute; if (n.channel_config().has_value()) { - channel_attribute = FmtChannelAttribute(*n.channel_config(), arena); + channel_attribute = FormatChannelConfig(*n.channel_config()); } std::vector pieces{ - channel_attribute.value_or(arena.empty()), - arena.Make(Keyword::kChan), - arena.oangle(), - Fmt(*n.type(), comments, arena), + channel_attribute.value_or(arena_.empty()), + arena_.Make(Keyword::kChan), + arena_.oangle(), + FormatTypeAnnotation(*n.type()), }; // channel_config().has_value() -> fifo_config().has_value(), but we've // already handled it above. if (!n.channel_config().has_value() && n.fifo_depth().has_value()) { - pieces.push_back(arena.comma()); - pieces.push_back(arena.space()); - pieces.push_back(Fmt(*n.fifo_depth().value(), comments, arena)); + pieces.push_back(arena_.comma()); + pieces.push_back(arena_.space()); + pieces.push_back(FormatExpr(*n.fifo_depth().value())); } - pieces.push_back(arena.cangle()); + pieces.push_back(arena_.cangle()); if (n.dims().has_value()) { for (const Expr* dim : *n.dims()) { - pieces.push_back(arena.obracket()); - pieces.push_back(Fmt(*dim, comments, arena)); - pieces.push_back(arena.cbracket()); + pieces.push_back(arena_.obracket()); + pieces.push_back(FormatExpr(*dim)); + pieces.push_back(arena_.cbracket()); } } - pieces.push_back(arena.oparen()); - pieces.push_back(Fmt(n.channel_name_expr(), comments, arena)); - pieces.push_back(arena.cparen()); - return ConcatNGroup(arena, pieces); + pieces.push_back(arena_.oparen()); + pieces.push_back(FormatExpr(n.channel_name_expr())); + pieces.push_back(arena_.cparen()); + return ConcatNGroup(arena_, pieces); } -DocRef Fmt(const ColonRef& n, Comments& comments, DocArena& arena) { +DocRef Formatter::FormatColonRef(const ColonRef& n) { DocRef subject = absl::visit( - Visitor{[&](const auto* n) { return Fmt(*n, comments, arena); }}, + Visitor{ + [&](const Expr* n) { return FormatExpr(*n); }, + [&](const TypeAnnotation* n) { return FormatTypeAnnotation(*n); }, + }, n.subject()); - return ConcatNGroup(arena, {subject, arena.colon_colon(), - arena.MakeText(StripAnyDotModifier(n.attr()))}); + return ConcatNGroup(arena_, {subject, arena_.colon_colon(), + arena_.MakeText(StripAnyDotModifier(n.attr()))}); } -DocRef FmtForLoopBaseLeader(Keyword keyword, DocRef names_ref, - const ForLoopBase& n, Comments& comments, - DocArena& arena, bool is_const_for) { +DocRef Formatter::FormatForLoopBaseLeader(Keyword keyword, DocRef names_ref, + const ForLoopBase& n, + bool is_const_for) { std::vector pieces; if (is_const_for) { - pieces.push_back(arena.Make(Keyword::kConst)); - pieces.push_back(arena.space()); + pieces.push_back(arena_.Make(Keyword::kConst)); + pieces.push_back(arena_.space()); } - pieces.push_back(arena.Make(keyword)); - pieces.push_back(arena.MakeNestIfFlatFits( + pieces.push_back(arena_.Make(keyword)); + pieces.push_back(arena_.MakeNestIfFlatFits( /*on_nested_flat_ref=*/names_ref, - /*on_other_ref=*/arena.MakeConcat(arena.space(), names_ref))); + /*on_other_ref=*/arena_.MakeConcat(arena_.space(), names_ref))); if (n.type_annotation() != nullptr) { - pieces.push_back(arena.colon()); - pieces.push_back(arena.space()); - pieces.push_back(Fmt(*n.type_annotation(), comments, arena)); + pieces.push_back(arena_.colon()); + pieces.push_back(arena_.space()); + pieces.push_back(FormatTypeAnnotation(*n.type_annotation())); } - pieces.push_back(arena.space()); - pieces.push_back(arena.Make(Keyword::kIn)); + pieces.push_back(arena_.space()); + pieces.push_back(arena_.Make(Keyword::kIn)); - DocRef iterable_ref = Fmt(*n.iterable(), comments, arena); - pieces.push_back(arena.MakeNestIfFlatFits( + DocRef iterable_ref = FormatExpr(*n.iterable()); + pieces.push_back(arena_.MakeNestIfFlatFits( /*on_nested_flat_ref=*/iterable_ref, - /*on_other_ref=*/arena.MakeConcat(arena.space(), iterable_ref))); + /*on_other_ref=*/arena_.MakeConcat(arena_.space(), iterable_ref))); - pieces.push_back(arena.space()); - pieces.push_back(arena.ocurl()); - return ConcatN(arena, pieces); + pieces.push_back(arena_.space()); + pieces.push_back(arena_.ocurl()); + return ConcatN(arena_, pieces); } -DocRef FmtForLoopBase(Keyword keyword, const ForLoopBase& n, Comments& comments, - DocArena& arena, bool is_const_for) { +DocRef Formatter::FormatForLoopBase(Keyword keyword, const ForLoopBase& n, + bool is_const_for) { CHECK(keyword == Keyword::kFor || keyword == Keyword::kUnrollFor) << static_cast>(keyword); - DocRef names_ref = Fmt(*n.names(), comments, arena); - DocRef leader = FmtForLoopBaseLeader(keyword, names_ref, n, comments, arena, - is_const_for); + DocRef names_ref = FormatNameDefTree(*n.names()); + DocRef leader = FormatForLoopBaseLeader(keyword, names_ref, n, is_const_for); std::vector body_pieces; - body_pieces.push_back(arena.hard_line()); - body_pieces.push_back(FmtBlock(*n.body(), comments, arena, - /*add_curls=*/false, - /*force_multiline=*/true)); - body_pieces.push_back(arena.hard_line()); - body_pieces.push_back(arena.ccurl()); + body_pieces.push_back(arena_.hard_line()); + body_pieces.push_back(FormatBlock(*n.body(), + /*add_curls=*/false, + /*force_multiline=*/true)); + body_pieces.push_back(arena_.hard_line()); + body_pieces.push_back(arena_.ccurl()); body_pieces.push_back(ConcatNGroup( - arena, - {arena.oparen(), Fmt(*n.init(), comments, arena), arena.cparen()})); + arena_, {arena_.oparen(), FormatExpr(*n.init()), arena_.cparen()})); - return arena.MakeConcat(leader, ConcatN(arena, body_pieces)); + return arena_.MakeConcat(leader, ConcatN(arena_, body_pieces)); } -DocRef Fmt(const ConstFor& n, Comments& comments, DocArena& arena) { +DocRef Formatter::FormatConstFor(const ConstFor& n) { Keyword keyword = n.IsUnrollFor() ? Keyword::kUnrollFor : Keyword::kFor; - return FmtForLoopBase(keyword, n, comments, arena, !n.IsUnrollFor()); + return FormatForLoopBase(keyword, n, !n.IsUnrollFor()); } -DocRef Fmt(const For& n, Comments& comments, DocArena& arena) { - return FmtForLoopBase(Keyword::kFor, n, comments, arena, - /*is_const_for=*/false); +DocRef Formatter::FormatFor(const For& n) { + return FormatForLoopBase(Keyword::kFor, n, /*is_const_for=*/false); } -DocRef Fmt(const FormatMacro& n, Comments& comments, DocArena& arena) { - std::vector pieces = {arena.MakeText(n.macro()), arena.oparen()}; +DocRef Formatter::FormatFormatMacro(const FormatMacro& n) { + std::vector pieces = {arena_.MakeText(n.macro()), arena_.oparen()}; if (n.condition().has_value()) { - pieces.push_back(Fmt(**n.condition(), comments, arena)); - pieces.push_back(arena.comma()); - pieces.push_back(arena.break1()); + pieces.push_back(FormatExpr(**n.condition())); + pieces.push_back(arena_.comma()); + pieces.push_back(arena_.break1()); } if (n.verbosity().has_value()) { - pieces.push_back(Fmt(**n.verbosity(), comments, arena)); - pieces.push_back(arena.comma()); - pieces.push_back(arena.break1()); + pieces.push_back(FormatExpr(**n.verbosity())); + pieces.push_back(arena_.comma()); + pieces.push_back(arena_.break1()); } - pieces.push_back(arena.MakeText( + pieces.push_back(arena_.MakeText( absl::StrCat("\"", StepsToXlsFormatString(n.format()), "\""))); if (!n.args().empty()) { - pieces.push_back(arena.comma()); - pieces.push_back(arena.break1()); + pieces.push_back(arena_.comma()); + pieces.push_back(arena_.break1()); } - pieces.push_back(FmtJoin(n.args(), Joiner::kCommaSpace, - FmtExprPtr, comments, arena)); - pieces.push_back(arena.cparen()); - return ConcatNGroup(arena, pieces); + pieces.push_back( + FormatJoin(n.args(), Joiner::kCommaSpace, + [this](const Expr* e) { return Format(e); })); + pieces.push_back(arena_.cparen()); + return ConcatNGroup(arena_, pieces); } -DocRef Fmt(const Slice& n, Comments& comments, DocArena& arena) { +DocRef Formatter::FormatSlice(const Slice& n) { std::vector pieces; if (n.start() != nullptr) { - pieces.push_back(Fmt(*n.start(), comments, arena)); + pieces.push_back(FormatExpr(*n.start())); } - pieces.push_back(arena.break0()); - pieces.push_back(arena.colon()); + pieces.push_back(arena_.break0()); + pieces.push_back(arena_.colon()); if (n.limit() != nullptr) { - pieces.push_back(Fmt(*n.limit(), comments, arena)); + pieces.push_back(FormatExpr(*n.limit())); } - return ConcatNGroup(arena, pieces); + return ConcatNGroup(arena_, pieces); } -DocRef Fmt(const WidthSlice& n, Comments& comments, DocArena& arena) { - return ConcatNGroup(arena, { - Fmt(*n.start(), comments, arena), - arena.break0(), - arena.plus_colon(), - arena.break0(), - Fmt(*n.width(), comments, arena), - }); +DocRef Formatter::FormatWidthSlice(const WidthSlice& n) { + return ConcatNGroup(arena_, { + FormatExpr(*n.start()), + arena_.break0(), + arena_.plus_colon(), + arena_.break0(), + FormatTypeAnnotation(*n.width()), + }); } -DocRef Fmt(const IndexRhs& n, Comments& comments, DocArena& arena) { +DocRef Formatter::FormatIndexRhs(const IndexRhs& n) { return absl::visit( Visitor{ - [&](const Expr* n) { return Fmt(*n, comments, arena); }, - [&](const Slice* n) { return Fmt(*n, comments, arena); }, - [&](const WidthSlice* n) { return Fmt(*n, comments, arena); }, + [&](const Expr* n) { return FormatExpr(*n); }, + [&](const Slice* n) { return FormatSlice(*n); }, + [&](const WidthSlice* n) { return FormatWidthSlice(*n); }, }, n); } -DocRef Fmt(const Index& n, Comments& comments, DocArena& arena) { +DocRef Formatter::FormatIndex(const Index& n) { std::vector pieces; if (WeakerThan(n.lhs()->GetPrecedence(), n.GetPrecedence())) { - pieces.push_back(arena.oparen()); - pieces.push_back(Fmt(*n.lhs(), comments, arena)); - pieces.push_back(arena.cparen()); + pieces.push_back(arena_.oparen()); + pieces.push_back(FormatExpr(*n.lhs())); + pieces.push_back(arena_.cparen()); } else { - pieces.push_back(Fmt(*n.lhs(), comments, arena)); + pieces.push_back(FormatExpr(*n.lhs())); } - pieces.push_back(arena.obracket()); - pieces.push_back(arena.MakeAlign(Fmt(n.rhs(), comments, arena))); - pieces.push_back(arena.cbracket()); - return ConcatNGroup(arena, pieces); + pieces.push_back(arena_.obracket()); + pieces.push_back(arena_.MakeAlign(FormatIndexRhs(n.rhs()))); + pieces.push_back(arena_.cbracket()); + return ConcatNGroup(arena_, pieces); } -DocRef FmtExprOrType(const ExprOrType& n, Comments& comments, DocArena& arena) { +DocRef Formatter::FormatExprOrType(const ExprOrType& n) { return absl::visit( Visitor{ - [&](const Expr* n) { return Fmt(*n, comments, arena); }, - [&](const TypeAnnotation* n) { return Fmt(*n, comments, arena); }, + [&](const Expr* n) { return FormatExpr(*n); }, + [&](const TypeAnnotation* n) { return FormatTypeAnnotation(*n); }, }, n); } -std::optional FmtExplicitParametrics( - absl::Span parametrics, Comments& comments, - DocArena& arena) { +std::optional Formatter::FormatExplicitParametrics( + absl::Span parametrics) { if (parametrics.empty()) { return std::nullopt; } - return ConcatNGroup(arena, - {arena.oangle(), arena.break0(), - FmtJoin(parametrics, Joiner::kCommaSpace, - FmtParametricArg, comments, arena), - arena.cangle()}); + return ConcatNGroup(arena_, + {arena_.oangle(), arena_.break0(), + FormatJoin(parametrics, Joiner::kCommaSpace, + [this](const ExprOrType& e) { + return FormatParametricArg(e); + }), + arena_.cangle()}); } -DocRef Fmt(const FunctionRef& n, Comments& comments, DocArena& arena) { - DocRef callee_doc = Fmt(*n.callee(), comments, arena); - std::optional parametrics_doc = FmtExplicitParametrics( - absl::MakeConstSpan(n.explicit_parametrics()), comments, arena); +DocRef Formatter::FormatFunctionRef(const FunctionRef& n) { + DocRef callee_doc = FormatExpr(*n.callee()); + std::optional parametrics_doc = + FormatExplicitParametrics(absl::MakeConstSpan(n.explicit_parametrics())); return parametrics_doc.has_value() - ? ConcatN(arena, {callee_doc, *parametrics_doc}) + ? ConcatN(arena_, {callee_doc, *parametrics_doc}) : callee_doc; } -DocRef Fmt(const Invocation& n, Comments& comments, DocArena& arena) { - DocRef callee_doc = Fmt(*n.callee(), comments, arena); +DocRef Formatter::FormatInvocation(const Invocation& n) { + DocRef callee_doc = FormatExpr(*n.callee()); std::optional parametrics_doc = - FmtExplicitParametrics(n.explicit_parametrics(), comments, arena); + FormatExplicitParametrics(n.explicit_parametrics()); - DocRef args_doc_internal = - FmtJoin(n.args(), Joiner::kCommaBreak1AsGroupNoTrailingComma, - FmtExprPtr, comments, arena); + DocRef args_doc_internal = FormatJoin( + n.args(), Joiner::kCommaBreak1AsGroupNoTrailingComma, + [this](const Expr* e) { return Format(e); }); // Group for the args tokens. std::vector arg_pieces = { - arena.MakeNestIfFlatFits( + arena_.MakeNestIfFlatFits( /*on_nested_flat_ref=*/args_doc_internal, - /*on_other_ref=*/arena.MakeAlign(args_doc_internal)), - arena.cparen()}; - DocRef args_doc = ConcatNGroup(arena, arg_pieces); - DocRef args_doc_nested = arena.MakeNest(args_doc); + /*on_other_ref=*/arena_.MakeAlign(args_doc_internal)), + arena_.cparen()}; + DocRef args_doc = ConcatNGroup(arena_, arg_pieces); + DocRef args_doc_nested = arena_.MakeNest(args_doc); // This is the flat version -- it simply concats the pieces together. DocRef flat = parametrics_doc.has_value() - ? ConcatN(arena, {callee_doc, parametrics_doc.value(), - arena.oparen(), args_doc}) - : ConcatN(arena, {callee_doc, arena.oparen(), args_doc}); + ? ConcatN(arena_, {callee_doc, parametrics_doc.value(), + arena_.oparen(), args_doc}) + : ConcatN(arena_, {callee_doc, arena_.oparen(), args_doc}); // This doc ref is for the "I can emit *the leader* flat" case; i.e. the // callee (or the callee with parametric args). @@ -1272,75 +1209,73 @@ DocRef Fmt(const Invocation& n, Comments& comments, DocArena& arena) { // that can be triggered. DocRef leader_flat = parametrics_doc.has_value() - ? ConcatN(arena, {callee_doc, arena.MakeNest(parametrics_doc.value()), - arena.oparen(), arena.break0(), args_doc_nested}) - : ConcatN(arena, {callee_doc, arena.oparen(), arena.break0(), - args_doc_nested}); + ? ConcatN(arena_, + {callee_doc, arena_.MakeNest(parametrics_doc.value()), + arena_.oparen(), arena_.break0(), args_doc_nested}) + : ConcatN(arena_, {callee_doc, arena_.oparen(), arena_.break0(), + args_doc_nested}); - DocRef result = arena.MakeGroup( - arena.MakeFlatChoice(/*on_flat=*/flat, /*on_break=*/leader_flat)); + DocRef result = arena_.MakeGroup( + arena_.MakeFlatChoice(/*on_flat=*/flat, /*on_break=*/leader_flat)); return result; } -DocRef FmtNameDefTreePtr(const NameDefTree* n, Comments& comments, - DocArena& arena) { - return Fmt(*n, comments, arena); -} +DocRef Formatter::Format(const NameDefTree* n) { return FormatNameDefTree(*n); } -DocRef FmtMatchArm(const MatchArm& n, Comments& comments, DocArena& arena) { +DocRef Formatter::FormatMatchArm(const MatchArm& n) { std::vector pieces; - pieces.push_back( - FmtJoin(n.patterns(), Joiner::kSpaceBarBreak, - FmtNameDefTreePtr, comments, arena)); - pieces.push_back(arena.space()); - pieces.push_back(arena.fat_arrow()); + pieces.push_back(FormatJoin( + n.patterns(), Joiner::kSpaceBarBreak, + [this](const NameDefTree* n) { return Format(n); })); + pieces.push_back(arena_.space()); + pieces.push_back(arena_.fat_arrow()); const Pos& rhs_start = n.expr()->span().start(); - DocRef rhs_doc = arena.MakeGroup(Fmt(*n.expr(), comments, arena)); + DocRef rhs_doc = arena_.MakeGroup(FormatExpr(*n.expr())); // Check for a comment between the arrow position and the RHS expression. This // can be needed when the RHS is not a block but an expression decorated with // a comment as if it were a block. std::optional last_comment_span; - if (std::optional comments_doc = EmitCommentsBetween( - n.span().start(), rhs_start, comments, arena, &last_comment_span)) { - pieces.push_back(arena.space()); - pieces.push_back(arena.space()); + if (std::optional comments_doc = FormatCommentsBetween( + n.span().start(), rhs_start, &last_comment_span)) { + pieces.push_back(arena_.space()); + pieces.push_back(arena_.space()); pieces.push_back(comments_doc.value()); - pieces.push_back(arena.hard_line()); - pieces.push_back(arena.MakeNest(rhs_doc)); + pieces.push_back(arena_.hard_line()); + pieces.push_back(arena_.MakeNest(rhs_doc)); } else { // If the RHS is a blocked expression, e.g. a struct instance, we don't // align it to the fat arrow indicated column. - if (n.expr()->IsBlockedExprAnyLeader()) { - pieces.push_back(arena.space()); - pieces.push_back(arena.MakeGroup(rhs_doc)); + if (IsBlockedExprNoLeader(*n.expr()) || + IsBlockedExprWithLeader(*n.expr())) { + pieces.push_back(arena_.space()); + pieces.push_back(arena_.MakeGroup(rhs_doc)); } else { - DocRef flat_choice_group = arena.MakeGroup(arena.MakeFlatChoice( - /*on_flat=*/arena.MakeConcat(arena.space(), rhs_doc), - /*on_break=*/arena.MakeConcat(arena.hard_line(), - arena.MakeNest(rhs_doc)))); + DocRef flat_choice_group = arena_.MakeGroup(arena_.MakeFlatChoice( + /*on_flat=*/arena_.MakeConcat(arena_.space(), rhs_doc), + /*on_break=*/arena_.MakeConcat(arena_.hard_line(), + arena_.MakeNest(rhs_doc)))); pieces.push_back(flat_choice_group); } } - return ConcatN(arena, pieces); + return ConcatN(arena_, pieces); } -DocRef Fmt(const Match& n, Comments& comments, DocArena& arena) { +DocRef Formatter::FormatMatch(const Match& n) { std::vector pieces; if (n.IsConst()) { - pieces.push_back(arena.Make(Keyword::kConst)); - pieces.push_back(arena.space()); + pieces.push_back(arena_.Make(Keyword::kConst)); + pieces.push_back(arena_.space()); } pieces.push_back(ConcatNGroup( - arena, - {arena.Make(Keyword::kMatch), arena.space(), - Fmt(n.matched(), comments, arena), arena.space(), arena.ocurl()})); + arena_, {arena_.Make(Keyword::kMatch), arena_.space(), + Format(n.matched()), arena_.space(), arena_.ocurl()})); - pieces.push_back(arena.hard_line()); + pieces.push_back(arena_.hard_line()); std::vector nested; @@ -1356,87 +1291,84 @@ DocRef Fmt(const Match& n, Comments& comments, DocArena& arena) { // See if there are comments above the match arm. std::optional last_comment_span; - if (std::optional comments_doc = - EmitCommentsBetween(last_member_pos, member_start, comments, arena, - &last_comment_span)) { + if (std::optional comments_doc = FormatCommentsBetween( + last_member_pos, member_start, &last_comment_span)) { nested.push_back(comments_doc.value()); - nested.push_back(arena.hard_line()); + nested.push_back(arena_.hard_line()); // If the comment abuts the member we don't put a newline in // between, we assume the comment is associated with the member. if (last_comment_span->limit().lineno() != member_start.lineno()) { - nested.push_back(arena.hard_line()); + nested.push_back(arena_.hard_line()); } } - nested.push_back(FmtMatchArm(*arm, comments, arena)); - nested.push_back(arena.comma()); + nested.push_back(FormatMatchArm(*arm)); + nested.push_back(arena_.comma()); last_member_pos = arm->span().limit(); // See if there are inline comments after the arm. - last_member_pos = - CollectInlineComments(member_limit, last_member_pos, comments, arena, - nested, last_comment_span); + last_member_pos = FormatCollectInlineComments(member_limit, last_member_pos, + nested, last_comment_span); if (i + 1 != n.arms().size()) { - nested.push_back(arena.hard_line()); + nested.push_back(arena_.hard_line()); } } - pieces.push_back(arena.MakeNest(ConcatN(arena, nested))); - pieces.push_back(arena.hard_line()); - pieces.push_back(arena.ccurl()); - return ConcatN(arena, pieces); + pieces.push_back(arena_.MakeNest(ConcatN(arena_, nested))); + pieces.push_back(arena_.hard_line()); + pieces.push_back(arena_.ccurl()); + return ConcatN(arena_, pieces); } -DocRef Fmt(const Spawn& n, Comments& comments, DocArena& arena) { - return ConcatNGroup(arena, {arena.MakeText("spawn"), arena.space(), - Fmt(*n.config(), comments, arena)} +DocRef Formatter::FormatSpawn(const Spawn& n) { + return ConcatNGroup(arena_, {arena_.MakeText("spawn"), arena_.space(), + FormatInvocation(*n.config())} ); } -DocRef FmtTupleWithoutComments(const XlsTuple& n, Comments& comments, - DocArena& arena) { +DocRef Formatter::FormatTupleWithoutComments(const XlsTuple& n) { // 1-element tuples are a special case- we always want a trailing comma and // never want it to be broken up. Handle separately here. if (n.members().size() == 1) { - return ConcatNGroup(arena, { - arena.oparen(), - Fmt(*n.members()[0], comments, arena), - arena.comma(), - arena.cparen(), - }); + return ConcatNGroup(arena_, { + arena_.oparen(), + FormatExpr(*n.members()[0]), + arena_.comma(), + arena_.cparen(), + }); } - DocRef guts = FmtJoin( - n.members(), Joiner::kCommaBreak1AsGroupTrailingCommaOnBreak, FmtExprPtr, - comments, arena); + DocRef guts = FormatJoin( + n.members(), Joiner::kCommaBreak1AsGroupTrailingCommaOnBreak, + [this](const Expr* e) { return Format(e); }); return ConcatNGroup( - arena, { - arena.oparen(), - arena.MakeFlatChoice( - /*on_flat=*/guts, - /*on_break=*/ConcatNGroup(arena, - { - arena.hard_line(), - arena.MakeNest(guts), - arena.hard_line(), - })), - arena.cparen(), - }); -} - -DocRef FmtTuple(const XlsTuple& n, Comments& comments, DocArena& arena) { + arena_, { + arena_.oparen(), + arena_.MakeFlatChoice( + /*on_flat=*/guts, + /*on_break=*/ConcatNGroup(arena_, + { + arena_.hard_line(), + arena_.MakeNest(guts), + arena_.hard_line(), + })), + arena_.cparen(), + }); +} + +DocRef Formatter::FormatTuple(const XlsTuple& n) { Span tuple_span = n.span(); // Detect if there are any comments in the span of the tuple. - bool any_comments = comments.HasComments(tuple_span); + bool any_comments = comments_.HasComments(tuple_span); if (!any_comments) { // Do it the old way. - return FmtTupleWithoutComments(n, comments, arena); + return FormatTupleWithoutComments(n); } // The general algorithm is: @@ -1453,76 +1385,67 @@ DocRef FmtTuple(const XlsTuple& n, Comments& comments, DocArena& arena) { const bool first_element = i == 0; const Span& span = item->span(); - // If there are comments between end of the last element we processed, - // and the start of this one, prepend them. - if (std::optional previous_comments = - EmitCommentsBetween(last_tuple_element_span_limit, span.start(), - comments, arena, nullptr)) { + // If there are comments between end of the last element we processed, and + // the start of this one, prepend them. + if (std::optional previous_comments = FormatCommentsBetween( + last_tuple_element_span_limit, span.start(), nullptr)) { if (!first_element) { - pieces.push_back(arena.comma()); - pieces.push_back(arena.space()); + pieces.push_back(arena_.comma()); + pieces.push_back(arena_.space()); } // TODO: davidplass - if the previous comment is not on the same line as // the previous element, insert a hard line before the comment. pieces.push_back(previous_comments.value()); - pieces.push_back(arena.hard_line()); + pieces.push_back(arena_.hard_line()); } else if (!first_element) { // No comments between there and here; append a newline to "terminate" the // previous element. - pieces.push_back(arena.comma()); - pieces.push_back(arena.hard_line()); + pieces.push_back(arena_.comma()); + pieces.push_back(arena_.hard_line()); } last_tuple_element_span_limit = span.limit(); // Format the element itself. - pieces.push_back(FmtExprPtr(item, comments, arena)); + pieces.push_back(Format(item)); } - DocRef guts = ConcatN(arena, pieces); + DocRef guts = ConcatN(arena_, pieces); // Append comments between the last element and the end of the tuple - if (std::optional terminal_comment = - EmitCommentsBetween(last_tuple_element_span_limit, tuple_span.limit(), - comments, arena, nullptr)) { + if (std::optional terminal_comment = FormatCommentsBetween( + last_tuple_element_span_limit, tuple_span.limit(), nullptr)) { // Add trailing comma before the terminal comment too. - guts = ConcatN( - arena, {guts, arena.comma(), arena.space(), terminal_comment.value()}); + guts = ConcatN(arena_, {guts, arena_.comma(), arena_.space(), + terminal_comment.value()}); } else if (n.members().size() == 1) { // No trailing comment, but add a comma if it's a singleton. - guts = ConcatN(arena, {guts, arena.comma()}); + guts = ConcatN(arena_, {guts, arena_.comma()}); } - return ConcatN(arena, { - arena.oparen(), - arena.hard_line(), - arena.MakeNest(guts), - arena.hard_line(), - arena.cparen(), - }); -} - -DocRef Fmt(const XlsTuple& n, Comments& comments, DocArena& arena) { - return FmtTuple(n, comments, arena); + return ConcatN(arena_, { + arena_.oparen(), + arena_.hard_line(), + arena_.MakeNest(guts), + arena_.hard_line(), + arena_.cparen(), + }); } // Note: this does not put any spacing characters after the '{' so we can // appropriately handle the case of an empty struct having no spacing in its // `S {}` style construct. -DocRef FmtStructLeader(const TypeAnnotation* struct_ref, Comments& comments, - DocArena& arena) { - return ConcatNGroup(arena, { - Fmt(*struct_ref, comments, arena), - arena.break1(), - arena.ocurl(), - }); -} - -DocRef FmtStructMembersFlat( - absl::Span> members, Comments& comments, - DocArena& arena) { - return FmtJoin>( - members, Joiner::kCommaSpace, - [](const auto& member, Comments& comments, DocArena& arena) { +DocRef Formatter::FormatStructLeader(const TypeAnnotation* struct_ref) { + return ConcatNGroup(arena_, { + FormatTypeAnnotation(*struct_ref), + arena_.break1(), + arena_.ocurl(), + }); +} + +DocRef Formatter::FormatStructMembersFlat( + absl::Span> members) { + return FormatJoin>( + members, Joiner::kCommaSpace, [this](const auto& member) { const auto& [name, expr] = member; // If the expression is an identifier that matches its corresponding // struct member name, we canonically use the shorthand notation of just @@ -1530,18 +1453,16 @@ DocRef FmtStructMembersFlat( // the same symbol. if (const NameRef* name_ref = dynamic_cast(expr); name_ref != nullptr && name_ref->identifier() == name) { - return arena.MakeText(name); + return arena_.MakeText(name); } - return ConcatN(arena, {arena.MakeText(name), arena.colon(), - arena.space(), Fmt(*expr, comments, arena)}); - }, - comments, arena); + return ConcatN(arena_, {arena_.MakeText(name), arena_.colon(), + arena_.space(), FormatExpr(*expr)}); + }); } -DocRef FmtStructMembersBreak( - Span struct_span, absl::Span> members, - Comments& comments, DocArena& arena) { +DocRef Formatter::FormatStructMembersBreak( + Span struct_span, absl::Span> members) { std::vector pieces; Pos previous_item_limit = struct_span.start(); for (size_t i = 0; i < members.size(); ++i) { @@ -1550,11 +1471,10 @@ DocRef FmtStructMembersBreak( // If there are comments between the last item and here, insert them. Span comment_span(previous_item_limit, expr->span().start()); - if (std::optional previous_comments = - EmitCommentsBetween(comment_span.start(), comment_span.limit(), - comments, arena, nullptr)) { + if (std::optional previous_comments = FormatCommentsBetween( + comment_span.start(), comment_span.limit(), nullptr)) { pieces.push_back(previous_comments.value()); - pieces.push_back(arena.hard_line()); + pieces.push_back(arena_.hard_line()); } previous_item_limit = expr->span().limit(); @@ -1565,11 +1485,11 @@ DocRef FmtStructMembersBreak( DocRef member_doc; if (const NameRef* name_ref = dynamic_cast(expr); name_ref != nullptr && name_ref->identifier() == field_name) { - member_doc = arena.MakeText(field_name); + member_doc = arena_.MakeText(field_name); } else { // First we format the member into a doc and then decide the best way to // put it into the sequence. - DocRef field_expr = Fmt(*expr, comments, arena); + DocRef field_expr = FormatExpr(*expr); // This is the document we want to emit both when we: // - Know it fits in flat mode @@ -1580,69 +1500,64 @@ DocRef FmtStructMembersBreak( // reassessment of whether to enter break mode for the field // expression. DocRef on_flat = - ConcatN(arena, {arena.MakeText(field_name), arena.colon(), - arena.break1(), arena.MakeGroup(field_expr)}); + ConcatN(arena_, {arena_.MakeText(field_name), arena_.colon(), + arena_.break1(), arena_.MakeGroup(field_expr)}); DocRef nest_field_expr = - ConcatN(arena, {arena.MakeText(field_name), arena.colon(), - arena.hard_line(), arena.MakeNest(field_expr)}); + ConcatN(arena_, {arena_.MakeText(field_name), arena_.colon(), + arena_.hard_line(), arena_.MakeNest(field_expr)}); DocRef on_other; if (expr->IsBlockedExprWithLeader()) { - DocRef leader = ConcatN( - arena, {arena.MakeText(field_name), arena.colon(), arena.space(), - FmtBlockedExprLeader(*expr, comments, arena)}); - on_other = arena.MakeModeSelect(leader, /*on_flat=*/on_flat, - /*on_break=*/nest_field_expr); + DocRef leader = + ConcatN(arena_, {arena_.MakeText(field_name), arena_.colon(), + arena_.space(), FormatBlockedExprLeader(*expr)}); + on_other = arena_.MakeModeSelect(leader, /*on_flat=*/on_flat, + /*on_break=*/nest_field_expr); } else { - on_other = arena.MakeFlatChoice(on_flat, nest_field_expr); + on_other = arena_.MakeFlatChoice(on_flat, nest_field_expr); } - member_doc = arena.MakeNestIfFlatFits(on_flat, on_other); + member_doc = arena_.MakeNestIfFlatFits(on_flat, on_other); } pieces.push_back(member_doc); - pieces.push_back(arena.comma()); + pieces.push_back(arena_.comma()); // TODO: https://github.com/google/xls/issues/1719 - if there is a comment // on the same line as this item, insert the comment first. if (i + 1 != members.size()) { // Not the last item, add a hardline - pieces.push_back(arena.hard_line()); + pieces.push_back(arena_.hard_line()); } } // Insert comments between the last item and the end of the struct. Span comment_span(previous_item_limit, struct_span.limit()); - if (std::optional previous_comments = - EmitCommentsBetween(comment_span.start(), comment_span.limit(), - comments, arena, nullptr)) { - pieces.push_back(arena.hard_line()); + if (std::optional previous_comments = FormatCommentsBetween( + comment_span.start(), comment_span.limit(), nullptr)) { + pieces.push_back(arena_.hard_line()); pieces.push_back(previous_comments.value()); } - return ConcatNGroup(arena, pieces); + return ConcatNGroup(arena_, pieces); } -DocRef FmtFlatRest(const StructInstance& n, Comments& comments, - DocArena& arena) { +DocRef Formatter::FormatFlatRest(const StructInstance& n) { return ConcatN( - arena, {arena.space(), - FmtStructMembersFlat(n.GetUnorderedMembers(), comments, arena), - arena.space(), arena.ccurl()}); + arena_, {arena_.space(), FormatStructMembersFlat(n.GetUnorderedMembers()), + arena_.space(), arena_.ccurl()}); } -DocRef FmtBreakRest(const StructInstance& n, Comments& comments, - DocArena& arena) { - return ConcatN(arena, - {arena.hard_line(), - arena.MakeNest(FmtStructMembersBreak( - n.span(), n.GetUnorderedMembers(), comments, arena)), - arena.hard_line(), arena.ccurl()}); +DocRef Formatter::FormatBreakRest(const StructInstance& n) { + return ConcatN(arena_, {arena_.hard_line(), + arena_.MakeNest(FormatStructMembersBreak( + n.span(), n.GetUnorderedMembers())), + arena_.hard_line(), arena_.ccurl()}); } -DocRef Fmt(const StructInstance& n, Comments& comments, DocArena& arena) { - DocRef leader = FmtStructLeader(n.struct_ref(), comments, arena); +DocRef Formatter::FormatStructInstance(const StructInstance& n) { + DocRef leader = FormatStructLeader(n.struct_ref()); if (n.GetUnorderedMembers().empty()) { // empty struct instance - return arena.MakeConcat(leader, arena.ccurl()); + return arena_.MakeConcat(leader, arena_.ccurl()); } // Implementation note: we cannot reorder members to be canonically the same @@ -1652,71 +1567,66 @@ DocRef Fmt(const StructInstance& n, Comments& comments, DocArena& arena) { // If there are comments within the span, we must go to break mode, because // newlines. - DocRef on_break = FmtBreakRest(n, comments, arena); - if (comments.HasComments(n.span())) { - return arena.MakeConcat(leader, on_break); + DocRef on_break = FormatBreakRest(n); + if (comments_.HasComments(n.span())) { + return arena_.MakeConcat(leader, on_break); } - DocRef on_flat = FmtFlatRest(n, comments, arena); - return arena.MakeConcat( - leader, arena.MakeGroup(arena.MakeFlatChoice(on_flat, on_break))); + DocRef on_flat = FormatFlatRest(n); + return arena_.MakeConcat( + leader, arena_.MakeGroup(arena_.MakeFlatChoice(on_flat, on_break))); } -DocRef Fmt(const SplatStructInstance& n, Comments& comments, DocArena& arena) { - DocRef leader = FmtStructLeader(n.struct_ref(), comments, arena); - DocRef splatted = Fmt(n.splatted(), comments, arena); +DocRef Formatter::FormatSplatStructInstance(const SplatStructInstance& n) { + DocRef leader = FormatStructLeader(n.struct_ref()); + DocRef splatted = Format(n.splatted()); if (n.members().empty()) { - return ConcatNGroup(arena, {leader, arena.break1(), arena.dot_dot(), - splatted, arena.break1(), arena.ccurl()}); + return ConcatNGroup(arena_, {leader, arena_.break1(), arena_.dot_dot(), + splatted, arena_.break1(), arena_.ccurl()}); } - DocRef on_flat = ConcatN( - arena, {arena.space(), FmtStructMembersFlat(n.members(), comments, arena), - arena.comma(), arena.space(), arena.dot_dot(), splatted, - arena.space(), arena.ccurl()}); + DocRef on_flat = + ConcatN(arena_, {arena_.space(), FormatStructMembersFlat(n.members()), + arena_.comma(), arena_.space(), arena_.dot_dot(), + splatted, arena_.space(), arena_.ccurl()}); DocRef on_break = ConcatN( - arena, {arena.hard_line(), - arena.MakeNest(ConcatN( - arena, {FmtStructMembersBreak(n.span(), n.members(), comments, - arena), - arena.hard_line(), arena.dot_dot(), splatted})), - arena.hard_line(), arena.ccurl()}); - return arena.MakeConcat( - leader, arena.MakeGroup(arena.MakeFlatChoice(on_flat, on_break))); + arena_, {arena_.hard_line(), + arena_.MakeNest(ConcatN( + arena_, {FormatStructMembersBreak(n.span(), n.members()), + arena_.hard_line(), arena_.dot_dot(), splatted})), + arena_.hard_line(), arena_.ccurl()}); + return arena_.MakeConcat( + leader, arena_.MakeGroup(arena_.MakeFlatChoice(on_flat, on_break))); } -DocRef Fmt(const String& n, Comments& comments, DocArena& arena) { - return arena.MakeText(n.ToString()); +DocRef Formatter::FormatString(const String& n) { + return arena_.MakeText(n.ToString()); } // Creates a doc that has the "test portion" of the conditional; i.e. // // if $test_expr { -DocRef MakeConditionalTest(const Conditional& n, Comments& comments, - DocArena& arena) { +DocRef Formatter::FormatMakeConditionalTest(const Conditional& n) { std::vector pieces; if (n.IsConst() && !n.IsElseIf()) { - pieces.push_back(arena.Make(Keyword::kConst)); - pieces.push_back(arena.space()); + pieces.push_back(arena_.Make(Keyword::kConst)); + pieces.push_back(arena_.space()); } - pieces.push_back(arena.Make(Keyword::kIf)); - pieces.push_back(arena.space()); - pieces.push_back( - FmtExpr(*n.test(), comments, arena, /*suppress_parens=*/true)); - pieces.push_back(arena.space()); - pieces.push_back(arena.ocurl()); + pieces.push_back(arena_.Make(Keyword::kIf)); + pieces.push_back(arena_.space()); + pieces.push_back(FormatExpr(*n.test(), /*suppress_parens=*/true)); + pieces.push_back(arena_.space()); + pieces.push_back(arena_.ocurl()); - return ConcatNGroup(arena, pieces); + return ConcatNGroup(arena_, pieces); } // When there's an else-if, or multiple statements inside of the blocks, we // force the formatting to be multi-line. -DocRef FmtConditionalMultiline(const Conditional& n, Comments& comments, - DocArena& arena) { +DocRef Formatter::FormatConditionalMultiline(const Conditional& n) { std::vector pieces = { - MakeConditionalTest(n, comments, arena), arena.hard_line(), - FmtBlock(*n.consequent(), comments, arena, /*add_curls=*/false), - arena.hard_line()}; + FormatMakeConditionalTest(n), arena_.hard_line(), + FormatBlock(*n.consequent(), /*add_curls=*/false), arena_.hard_line()}; bool has_else = n.HasElse(); std::variant alternate = n.alternate(); @@ -1724,179 +1634,175 @@ DocRef FmtConditionalMultiline(const Conditional& n, Comments& comments, Conditional* elseif = std::get(alternate); alternate = elseif->alternate(); has_else = elseif->HasElse(); - pieces.push_back(arena.ccurl()); - pieces.push_back(arena.space()); - pieces.push_back(arena.Make(Keyword::kElse)); - pieces.push_back(arena.space()); - pieces.push_back(MakeConditionalTest(*elseif, comments, arena)); - pieces.push_back(arena.hard_line()); - pieces.push_back( - FmtBlock(*elseif->consequent(), comments, arena, /*add_curls=*/false)); - pieces.push_back(arena.hard_line()); + pieces.push_back(arena_.ccurl()); + pieces.push_back(arena_.space()); + pieces.push_back(arena_.Make(Keyword::kElse)); + pieces.push_back(arena_.space()); + pieces.push_back(FormatMakeConditionalTest(*elseif)); + pieces.push_back(arena_.hard_line()); + pieces.push_back(FormatBlock(*elseif->consequent(), /*add_curls=*/false)); + pieces.push_back(arena_.hard_line()); } if (has_else) { CHECK(std::holds_alternative(alternate)); StatementBlock* else_block = std::get(alternate); - pieces.push_back(arena.ccurl()); - pieces.push_back(arena.space()); - pieces.push_back(arena.Make(Keyword::kElse)); - pieces.push_back(arena.space()); - pieces.push_back(arena.ocurl()); - pieces.push_back(arena.hard_line()); - pieces.push_back( - FmtBlock(*else_block, comments, arena, /*add_curls=*/false)); - pieces.push_back(arena.hard_line()); + pieces.push_back(arena_.ccurl()); + pieces.push_back(arena_.space()); + pieces.push_back(arena_.Make(Keyword::kElse)); + pieces.push_back(arena_.space()); + pieces.push_back(arena_.ocurl()); + pieces.push_back(arena_.hard_line()); + pieces.push_back(FormatBlock(*else_block, /*add_curls=*/false)); + pieces.push_back(arena_.hard_line()); } - pieces.push_back(arena.ccurl()); + pieces.push_back(arena_.ccurl()); - return ConcatNGroup(arena, pieces); + return ConcatNGroup(arena_, pieces); } -DocRef Fmt(const Conditional& n, Comments& comments, DocArena& arena) { +DocRef Formatter::FormatConditional(const Conditional& n) { // If there's an else-if clause or multi-statement blocks we force it to be // multi-line. if (n.HasElseIf() || n.HasMultiStatementBlocks()) { - return FmtConditionalMultiline(n, comments, arena); + return FormatConditionalMultiline(n); } - DocRef test = MakeConditionalTest(n, comments, arena); + DocRef test = FormatMakeConditionalTest(n); std::vector pieces = { test, - arena.break1(), - FmtBlock(*n.consequent(), comments, arena, /*add_curls=*/false), - arena.break1(), + arena_.break1(), + FormatBlock(*n.consequent(), /*add_curls=*/false), + arena_.break1(), }; if (n.HasElse()) { CHECK(std::holds_alternative(n.alternate())); const StatementBlock* else_block = std::get(n.alternate()); - pieces.push_back(arena.ccurl()); - pieces.push_back(arena.space()); - pieces.push_back(arena.Make(Keyword::kElse)); - pieces.push_back(arena.space()); - pieces.push_back(arena.ocurl()); - pieces.push_back(arena.break1()); - pieces.push_back( - FmtBlock(*else_block, comments, arena, /*add_curls=*/false)); - pieces.push_back(arena.break1()); + pieces.push_back(arena_.ccurl()); + pieces.push_back(arena_.space()); + pieces.push_back(arena_.Make(Keyword::kElse)); + pieces.push_back(arena_.space()); + pieces.push_back(arena_.ocurl()); + pieces.push_back(arena_.break1()); + pieces.push_back(FormatBlock(*else_block, /*add_curls=*/false)); + pieces.push_back(arena_.break1()); } - pieces.push_back(arena.ccurl()); - return ConcatNGroup(arena, pieces); + pieces.push_back(arena_.ccurl()); + return ConcatNGroup(arena_, pieces); } -DocRef Fmt(const TupleIndex& n, Comments& comments, DocArena& arena) { +DocRef Formatter::FormatTupleIndex(const TupleIndex& n) { std::vector pieces; if (WeakerThan(n.lhs()->GetPrecedence(), n.GetPrecedence())) { - pieces.push_back(arena.oparen()); - pieces.push_back(Fmt(*n.lhs(), comments, arena)); - pieces.push_back(arena.cparen()); + pieces.push_back(arena_.oparen()); + pieces.push_back(FormatExpr(*n.lhs())); + pieces.push_back(arena_.cparen()); } else { - pieces.push_back(Fmt(*n.lhs(), comments, arena)); + pieces.push_back(FormatExpr(*n.lhs())); } - pieces.push_back(arena.dot()); - pieces.push_back(Fmt(*n.index(), comments, arena)); - return ConcatNGroup(arena, pieces); + pieces.push_back(arena_.dot()); + pieces.push_back(FormatNumber(*n.index())); + return ConcatNGroup(arena_, pieces); } -DocRef Fmt(const ZeroMacro& n, Comments& comments, DocArena& arena) { - return ConcatNGroup(arena, { - arena.MakeText("zero!"), - arena.oangle(), - FmtExprOrType(n.type(), comments, arena), - arena.cangle(), - arena.oparen(), - arena.cparen(), - }); +DocRef Formatter::FormatZeroMacro(const ZeroMacro& n) { + return ConcatNGroup(arena_, { + arena_.MakeText("zero!"), + arena_.oangle(), + FormatExprOrType(n.type()), + arena_.cangle(), + arena_.oparen(), + arena_.cparen(), + }); } -DocRef Fmt(const AllOnesMacro& n, Comments& comments, DocArena& arena) { - return ConcatNGroup(arena, { - arena.MakeText("all_ones!"), - arena.oangle(), - FmtExprOrType(n.type(), comments, arena), - arena.cangle(), - arena.oparen(), - arena.cparen(), - }); +DocRef Formatter::FormatAllOnesMacro(const AllOnesMacro& n) { + return ConcatNGroup(arena_, { + arena_.MakeText("all_ones!"), + arena_.oangle(), + FormatExprOrType(n.type()), + arena_.cangle(), + arena_.oparen(), + arena_.cparen(), + }); } -DocRef Fmt(const Unop& n, Comments& comments, DocArena& arena) { - std::vector pieces = {arena.MakeText(UnopKindFormat(n.unop_kind()))}; +DocRef Formatter::FormatUnop(const Unop& n) { + std::vector pieces = {arena_.MakeText(UnopKindFormat(n.unop_kind()))}; if (WeakerThan(n.operand()->GetPrecedence(), n.GetPrecedence())) { - pieces.push_back(arena.oparen()); - pieces.push_back(Fmt(*n.operand(), comments, arena)); - pieces.push_back(arena.cparen()); + pieces.push_back(arena_.oparen()); + pieces.push_back(FormatExpr(*n.operand())); + pieces.push_back(arena_.cparen()); } else { - pieces.push_back(Fmt(n.operand(), comments, arena)); + pieces.push_back(FormatExpr(*n.operand())); } - return ConcatNGroup(arena, pieces); + return ConcatNGroup(arena_, pieces); } -DocRef Fmt(const Range& n, Comments& comments, DocArena& arena) { +DocRef Formatter::FormatRange(const Range& n) { if (n.inclusive_end()) { - return ConcatNGroup(arena, {Fmt(*n.start(), comments, arena), - arena.break0(), arena.dot_dot(), arena.equals(), - Fmt(*n.end(), comments, arena)}); + return ConcatNGroup( + arena_, {FormatExpr(*n.start()), arena_.break0(), arena_.dot_dot(), + arena_.equals(), FormatExpr(*n.end())}); } return ConcatNGroup( - arena, {Fmt(*n.start(), comments, arena), arena.break0(), arena.dot_dot(), - arena.break0(), Fmt(*n.end(), comments, arena)}); + arena_, {FormatExpr(*n.start()), arena_.break0(), arena_.dot_dot(), + arena_.break0(), FormatExpr(*n.end())}); } -DocRef Fmt(const NameDefTree::Leaf& n, Comments& comments, DocArena& arena) { +DocRef Formatter::FormatNameDefTreeLeaf(const NameDefTree::Leaf& n) { return absl::visit( Visitor{ - [&](const NameDef* n) { return Fmt(*n, comments, arena); }, - [&](const NameRef* n) { return Fmt(*n, comments, arena); }, - [&](const WildcardPattern* n) { return Fmt(*n, comments, arena); }, - [&](const RestOfTuple* n) { return Fmt(*n, comments, arena); }, - [&](const Number* n) { return Fmt(*n, comments, arena); }, - [&](const ColonRef* n) { return Fmt(*n, comments, arena); }, - [&](const Range* n) { return Fmt(*n, comments, arena); }, + [&](const NameDef* n) { return FormatNameDef(*n); }, + [&](const NameRef* n) { return FormatNameRef(*n); }, + [&](const WildcardPattern* n) { return FormatWildcardPattern(*n); }, + [&](const RestOfTuple* n) { return FormatRestOfTuple(*n); }, + [&](const Number* n) { return FormatNumber(*n); }, + [&](const ColonRef* n) { return FormatColonRef(*n); }, + [&](const Range* n) { return FormatRange(*n); }, }, n); } -DocRef Fmt(const NameDefTree& n, Comments& comments, DocArena& arena) { +DocRef Formatter::FormatNameDefTree(const NameDefTree& n) { if (n.is_leaf()) { - return Fmt(n.leaf(), comments, arena); + return FormatNameDefTreeLeaf(n.leaf()); } - std::vector pieces = {arena.oparen()}; + std::vector pieces = {arena_.oparen()}; std::vector> flattened = n.Flatten1(); for (size_t i = 0; i < flattened.size(); ++i) { const auto& item = flattened[i]; absl::visit(Visitor{ [&](const NameDefTree::Leaf& leaf) { - pieces.push_back(Fmt(leaf, comments, arena)); + pieces.push_back(FormatNameDefTreeLeaf(leaf)); }, [&](const NameDefTree* subtree) { - pieces.push_back(Fmt(*subtree, comments, arena)); + pieces.push_back(FormatNameDefTree(*subtree)); }, }, item); if (i + 1 != flattened.size()) { - pieces.push_back(arena.comma()); - pieces.push_back(arena.break1()); + pieces.push_back(arena_.comma()); + pieces.push_back(arena_.break1()); } } - pieces.push_back(arena.cparen()); - return ConcatNGroup(arena, pieces); + pieces.push_back(arena_.cparen()); + return ConcatNGroup(arena_, pieces); } class FmtExprVisitor : public ExprVisitor { public: - FmtExprVisitor(DocArena& arena, Comments& comments) - : arena_(arena), comments_(comments) {} + explicit FmtExprVisitor(Formatter& formatter) : formatter_(formatter) {} ~FmtExprVisitor() override = default; #define DEFINE_HANDLER(__type) \ absl::Status Handle##__type(const __type* expr) override { \ - result_ = Fmt(*expr, comments_, arena_); \ + result_ = formatter_.Format##__type(*expr); \ return absl::OkStatus(); \ } @@ -1907,20 +1813,18 @@ class FmtExprVisitor : public ExprVisitor { DocRef result() const { return result_.value(); } private: - DocArena& arena_; - Comments& comments_; + Formatter& formatter_; std::optional result_; }; // Note: suppress_parens just suppresses parentheses for the outermost // expression "n", not transitively. -DocRef FmtExpr(const Expr& n, Comments& comments, DocArena& arena, - bool suppress_parens) { - FmtExprVisitor v(arena, comments); +DocRef Formatter::FormatExpr(const Expr& n, bool suppress_parens) { + FmtExprVisitor v(*this); CHECK_OK(n.AcceptExpr(&v)); DocRef result = v.result(); if (n.in_parens() && !suppress_parens) { - return ConcatNGroup(arena, {arena.oparen(), result, arena.cparen()}); + return ConcatNGroup(arena_, {arena_.oparen(), result, arena_.cparen()}); } return result; } @@ -1929,74 +1833,61 @@ DocRef FmtExpr(const Expr& n, Comments& comments, DocArena& arena, // // Precondition: `e` must be a blocked expression with a leader component; e.g. // invocation (leader is callee), conditional (leader is test), etc. -DocRef FmtBlockedExprLeader(const Expr& e, Comments& comments, - DocArena& arena) { +DocRef Formatter::FormatBlockedExprLeader(const Expr& e) { CHECK(e.IsBlockedExprWithLeader()); switch (e.kind()) { case AstNodeKind::kInvocation: { - return arena.MakeConcat( - Fmt(static_cast(e).callee(), comments, arena), - arena.oparen()); + return arena_.MakeConcat( + Format(static_cast(e).callee()), arena_.oparen()); } case AstNodeKind::kConditional: { const Expr& test = *static_cast(e).test(); return ConcatN( - arena, {arena.Make(Keyword::kIf), arena.space(), - Fmt(test, comments, arena), arena.space(), arena.ocurl()}); + arena_, {arena_.Make(Keyword::kIf), arena_.space(), FormatExpr(test), + arena_.space(), arena_.ocurl()}); } case AstNodeKind::kMatch: { const Expr& test = *static_cast(e).matched(); - return ConcatN( - arena, {arena.Make(Keyword::kMatch), arena.space(), - Fmt(test, comments, arena), arena.space(), arena.ocurl()}); + return ConcatN(arena_, + {arena_.Make(Keyword::kMatch), arena_.space(), + FormatExpr(test), arena_.space(), arena_.ocurl()}); } case AstNodeKind::kArray: { const TypeAnnotation& type = *static_cast(e).type_annotation(); - return ConcatN( - arena, {Fmt(type, comments, arena), arena.colon(), arena.obracket()}); + return ConcatN(arena_, {FormatTypeAnnotation(type), arena_.colon(), + arena_.obracket()}); } case AstNodeKind::kStructInstance: { const StructInstance& n = static_cast(e); - return ConcatN(arena, {FmtStructLeader(n.struct_ref(), comments, arena), - arena.space(), arena.ocurl()}); + return ConcatN(arena_, {FormatStructLeader(n.struct_ref()), + arena_.space(), arena_.ocurl()}); } case AstNodeKind::kSplatStructInstance: { const SplatStructInstance& n = static_cast(e); - return ConcatN(arena, {FmtStructLeader(n.struct_ref(), comments, arena), - arena.space(), arena.ocurl()}); + return ConcatN(arena_, {FormatStructLeader(n.struct_ref()), + arena_.space(), arena_.ocurl()}); } case AstNodeKind::kFor: { const ForLoopBase& n = static_cast(e); - DocRef names_ref = Fmt(*n.names(), comments, arena); - return FmtForLoopBaseLeader(Keyword::kFor, names_ref, n, comments, arena, - /*is_const_for=*/false); + DocRef names_ref = FormatNameDefTree(*n.names()); + return FormatForLoopBaseLeader(Keyword::kFor, names_ref, n, + /*is_const_for=*/false); } case AstNodeKind::kConstFor: { const ConstFor& n = static_cast(e); Keyword keyword = n.IsUnrollFor() ? Keyword::kUnrollFor : Keyword::kFor; - DocRef names_ref = Fmt(*n.names(), comments, arena); - return FmtForLoopBaseLeader(keyword, names_ref, n, comments, arena, - !n.IsUnrollFor()); + DocRef names_ref = FormatNameDefTree(*n.names()); + return FormatForLoopBaseLeader(keyword, names_ref, n, !n.IsUnrollFor()); } default: LOG(FATAL) << "Unhandled node kind for FmtBlockedExprLeader: `" << e.ToString() << "` @ " - << e.span().ToString(arena.file_table()); + << e.span().ToString(arena_.file_table()); } } -DocRef Fmt(const Expr& n, Comments& comments, DocArena& arena) { - return FmtExpr(n, comments, arena, /*suppress_parens=*/false); -} - -} // namespace - -DocRef Formatter::Format(const Expr& n) { - return FmtExpr(n, comments_, arena_, /*suppress_parens=*/false); -} - -DocRef Formatter::Format(const ConstantDef& n) { +DocRef Formatter::FormatConstantDef(const ConstantDef& n) { // There are 7 places a comment can be in a constant definition: // [pub 1] const 2 name 3 [: 4 type 5] = 6 value 7; @@ -2023,10 +1914,9 @@ DocRef Formatter::Format(const ConstantDef& n) { if (n.type_annotation() != nullptr) { // Comments between the name and the type (category 3 and 4). We don't know // there the colon is, so we put it just before the type. - std::optional comments_doc = EmitCommentsBetween( + std::optional comments_doc = FormatCommentsBetween( n.name_def()->GetSpan()->limit(), - n.type_annotation()->GetSpan()->start(), comments_, arena_, - /*last_comment_span=*/nullptr); + n.type_annotation()->GetSpan()->start(), /*last_comment_span=*/nullptr); if (comments_doc.has_value()) { dest->push_back(ConcatN( arena_, {arena_.break1(), *comments_doc, arena_.hard_line()})); @@ -2037,14 +1927,13 @@ DocRef Formatter::Format(const ConstantDef& n) { dest->push_back(arena_.colon()); dest->push_back(arena_.break1()); - dest->push_back(Fmt(*n.type_annotation(), comments_, arena_)); + dest->push_back(FormatTypeAnnotation(*n.type_annotation())); - // Find comments between the end of the type annotation and the start of - // the value and put them between the type and the = - comments_doc = - EmitCommentsBetween(n.type_annotation()->GetSpan()->limit(), - n.value()->GetSpan()->start(), comments_, arena_, - /*last_comment_span=*/nullptr); + // Find comments between the end of the type annotation and the start of the + // value and put them between the type and the = + comments_doc = FormatCommentsBetween( + n.type_annotation()->GetSpan()->limit(), n.value()->GetSpan()->start(), + /*last_comment_span=*/nullptr); if (comments_doc.has_value()) { dest->push_back(ConcatN( arena_, {arena_.break1(), *comments_doc, arena_.hard_line()})); @@ -2058,10 +1947,9 @@ DocRef Formatter::Format(const ConstantDef& n) { } else { // Comments in category 3 & 6: between the name and the value. We don't know // where the = is, so we put all comments in this category before it. - std::optional comments_doc = - EmitCommentsBetween(n.name_def()->GetSpan()->limit(), - n.value()->GetSpan()->start(), comments_, arena_, - /*last_comment_span=*/nullptr); + std::optional comments_doc = FormatCommentsBetween( + n.name_def()->GetSpan()->limit(), n.value()->GetSpan()->start(), + /*last_comment_span=*/nullptr); if (comments_doc.has_value()) { leader_pieces.push_back(ConcatN( arena_, {arena_.break1(), *comments_doc, arena_.hard_line()})); @@ -2089,10 +1977,10 @@ DocRef Formatter::Format(const ConstantDef& n) { lhs = ConcatNGroup(arena_, leader_pieces); } - DocRef value_doc = Fmt(*n.value(), comments_, arena_); - std::optional comments_doc = EmitCommentsBetween( - n.value()->GetSpan()->limit(), n.span().limit(), comments_, arena_, - /*last_comment_span=*/nullptr); + DocRef value_doc = FormatExpr(*n.value()); + std::optional comments_doc = + FormatCommentsBetween(n.value()->GetSpan()->limit(), n.span().limit(), + /*last_comment_span=*/nullptr); if (comments_doc.has_value()) { // There are comments between the end of the value and the semicolon. @@ -2122,9 +2010,9 @@ DocRef Formatter::Format(const ConstantDef& n) { // name (category 1 & 2) DocRef pre_comment = arena_.empty(); Span lhs_comments_span(n.span().start(), n.name_def()->GetSpan()->start()); - comments_doc = EmitCommentsBetween( - lhs_comments_span.start(), lhs_comments_span.limit(), comments_, arena_, - /*last_comment_span=*/nullptr); + comments_doc = FormatCommentsBetween(lhs_comments_span.start(), + lhs_comments_span.limit(), + /*last_comment_span=*/nullptr); if (comments_doc.has_value()) { pre_comment = ConcatN(arena_, {*comments_doc, arena_.hard_line()}); } @@ -2132,13 +2020,13 @@ DocRef Formatter::Format(const ConstantDef& n) { return ConcatN(arena_, {pre_comment, lhs, rhs}); } -DocRef Formatter::Format(const ConstAssert& n) { - DocRef arg_doc = Fmt(*n.arg(), comments_, arena_); +DocRef Formatter::FormatConstAssert(const ConstAssert& n) { + DocRef arg_doc = FormatExpr(*n.arg()); // Helper lambda for the case where we have a blocked expression with a // "leader" doc. auto make_blocked = [&]() { - DocRef leader = FmtBlockedExprLeader(*n.arg(), comments_, arena_); + DocRef leader = FormatBlockedExprLeader(*n.arg()); DocRef nested = arena_.MakeNest(arena_.MakeConcat(arena_.hard_line(), arg_doc)); // If the leader doc fits, we emit the arg doc directly with the leader @@ -2161,14 +2049,14 @@ DocRef Formatter::Format(const ConstAssert& n) { }); } -DocRef Formatter::Format(const VerbatimNode& n) { +DocRef Formatter::FormatVerbatimNode(const VerbatimNode& n) { if (n.text().empty()) { return arena_.empty(); } return arena_.MakeZeroIndent(arena_.MakeText(std::string(n.text()))); } -DocRef Formatter::Format(const Statement& n, bool trailing_semi) { +DocRef Formatter::FormatStatement(const Statement& n, bool trailing_semi) { auto maybe_concat_semi = [&](DocRef d) { if (trailing_semi) { return arena_.MakeConcat(d, arena_.semi()); @@ -2177,13 +2065,15 @@ DocRef Formatter::Format(const Statement& n, bool trailing_semi) { }; return absl::visit( Visitor{ - [&](const VerbatimNode* n) { return Format(*n); }, - [&](const Expr* n) { - return maybe_concat_semi(Fmt(*n, comments_, arena_)); + [&](const VerbatimNode* n) { return FormatVerbatimNode(*n); }, + [&](const Expr* n) { return maybe_concat_semi(FormatExpr(*n)); }, + [&](const TypeAlias* n) { + return maybe_concat_semi(FormatTypeAlias(*n)); + }, + [&](const Let* n) { return FormatLet(*n, trailing_semi); }, + [&](const ConstAssert* n) { + return maybe_concat_semi(FormatConstAssert(*n)); }, - [&](const TypeAlias* n) { return maybe_concat_semi(Format(*n)); }, - [&](const Let* n) { return Format(*n, trailing_semi); }, - [&](const ConstAssert* n) { return maybe_concat_semi(Format(*n)); }, }, n.wrapped()); } @@ -2191,31 +2081,30 @@ DocRef Formatter::Format(const Statement& n, bool trailing_semi) { // Formats parameters (i.e. function parameters) with leading '(' and trailing // ')'. DocRef Formatter::FormatParams(absl::Span params) { - DocRef guts = FmtJoin( + DocRef guts = FormatJoin( params, Joiner::kCommaBreak1AsGroupNoTrailingComma, - [](const Param* param, Comments& comments, DocArena& arena) { - DocRef id = arena.MakeText(param->identifier()); + [this](const Param* param) { + DocRef id = arena_.MakeText(param->identifier()); if (auto* st = dynamic_cast(param->type_annotation()); st != nullptr && !st->explicit_type()) { return id; } - DocRef type = Fmt(*param->type_annotation(), comments, arena); - return ConcatN(arena, {id, arena.colon(), arena.space(), type}); - }, - comments_, arena_); + DocRef type = FormatTypeAnnotation(*param->type_annotation()); + return ConcatN(arena_, {id, arena_.colon(), arena_.space(), type}); + }); return ConcatNGroup( arena_, {arena_.oparen(), arena_.MakeAlign(arena_.MakeConcat(guts, arena_.cparen()))}); } -DocRef Formatter::Format(const ParametricBinding& n) { +DocRef Formatter::FormatParametricBinding(const ParametricBinding& n) { std::vector pieces = { arena_.MakeText(n.identifier()), arena_.colon(), arena_.break1(), - Fmt(*n.type_annotation(), comments_, arena_), + FormatTypeAnnotation(*n.type_annotation()), }; if (n.expr() != nullptr) { pieces.push_back(arena_.space()); @@ -2223,18 +2112,18 @@ DocRef Formatter::Format(const ParametricBinding& n) { pieces.push_back(arena_.space()); pieces.push_back(arena_.ocurl()); pieces.push_back(arena_.break0()); - pieces.push_back(arena_.MakeNest(Fmt(*n.expr(), comments_, arena_))); + pieces.push_back(arena_.MakeNest(FormatExpr(*n.expr()))); pieces.push_back(arena_.ccurl()); } return ConcatNGroup(arena_, pieces); } -DocRef Formatter::Format(const ParametricBinding* n) { +DocRef Formatter::FormatParametricBindingPtr(const ParametricBinding* n) { CHECK(n != nullptr); - return Format(*n); + return FormatParametricBinding(*n); } -DocRef Formatter::Format(const Function& n, bool is_test) { +DocRef Formatter::FormatFunction(const Function& n, bool is_test) { std::vector signature_pieces; // Note that the functions in a trait are implicitly public. @@ -2248,23 +2137,23 @@ DocRef Formatter::Format(const Function& n, bool is_test) { signature_pieces.push_back(arena_.MakeText(n.identifier())); if (n.IsParametric()) { - DocRef flat_parametrics = ConcatNGroup( - arena_, {arena_.oangle(), - FmtJoin( - n.parametric_bindings(), Joiner::kCommaSpace, - [&](const ParametricBinding* n, Comments& comments, - DocArena& arena) { return Format(n); }, - comments_, arena_), - arena_.cangle()}); + DocRef flat_parametrics = + ConcatNGroup(arena_, {arena_.oangle(), + FormatJoin( + n.parametric_bindings(), Joiner::kCommaSpace, + [&](const ParametricBinding* n) { + return FormatParametricBindingPtr(n); + }), + arena_.cangle()}); DocRef parametric_guts = ConcatN(arena_, {arena_.oangle(), - arena_.MakeAlign(FmtJoin( + arena_.MakeAlign(FormatJoin( n.parametric_bindings(), Joiner::kCommaBreak1AsGroupNoTrailingComma, - [&](const ParametricBinding* n, Comments& comments, - DocArena& arena) { return Format(n); }, - comments_, arena_)), + [&](const ParametricBinding* n) { + return FormatParametricBindingPtr(n); + })), arena_.cangle()}); DocRef break_parametrics = ConcatNGroup( arena_, { @@ -2295,7 +2184,7 @@ DocRef Formatter::Format(const Function& n, bool is_test) { return_pieces.push_back(arena_.break1()); return_pieces.push_back(arena_.arrow()); return_pieces.push_back(arena_.space()); - return_pieces.push_back(Fmt(*n.return_type(), comments_, arena_)); + return_pieces.push_back(FormatTypeAnnotation(*n.return_type())); if (n.IsStub()) { return_pieces.push_back(arena_.semi()); } else { @@ -2313,7 +2202,7 @@ DocRef Formatter::Format(const Function& n, bool is_test) { std::optional fuzz_test_attr = GetAttribute(&n, AttributeKind::kFuzzTest); if (fuzz_test_attr.has_value()) { - fn_pieces.push_back(FmtAttribute(**fuzz_test_attr, arena_)); + fn_pieces.push_back(FormatAttribute(**fuzz_test_attr)); } if (n.extern_verilog_module().has_value()) { @@ -2340,15 +2229,13 @@ DocRef Formatter::Format(const Function& n, bool is_test) { if (!n.IsStub()) { if (n.body()->empty()) { // For empty function we don't put spaces between the curls. - fn_pieces.push_back( - FmtBlock(*n.body(), comments_, arena_, /*add_curls=*/false)); + fn_pieces.push_back(FormatBlock(*n.body(), /*add_curls=*/false)); fn_pieces.push_back(arena_.ccurl()); } else { // For non-empty functions, we break after the signature and before // the ccurl. fn_pieces.push_back(arena_.break1()); - fn_pieces.push_back( - FmtBlock(*n.body(), comments_, arena_, /*add_curls=*/false)); + fn_pieces.push_back(FormatBlock(*n.body(), /*add_curls=*/false)); fn_pieces.push_back(arena_.break1()); fn_pieces.push_back(arena_.ccurl()); } @@ -2357,13 +2244,13 @@ DocRef Formatter::Format(const Function& n, bool is_test) { return ConcatNGroup(arena_, fn_pieces); } -DocRef Formatter::Format(const ProcMember& n) { +DocRef Formatter::FormatProcMember(const ProcMember& n) { return ConcatNGroup( - arena_, {Fmt(*n.name_def(), comments_, arena_), arena_.colon(), - arena_.break1(), Fmt(*n.type_annotation(), comments_, arena_)}); + arena_, {FormatNameDef(*n.name_def()), arena_.colon(), arena_.break1(), + FormatTypeAnnotation(*n.type_annotation())}); } -DocRef Formatter::Format(const Proc& n, bool is_test) { +DocRef Formatter::FormatProc(const Proc& n, bool is_test) { std::vector attribute_pieces; if (n.is_test_utility() && !is_test) { attribute_pieces.push_back( @@ -2386,22 +2273,21 @@ DocRef Formatter::Format(const Proc& n, bool is_test) { signature_pieces.push_back(arena_.MakeText(n.identifier())); if (n.IsParametric()) { - signature_pieces.push_back(ConcatNGroup( - arena_, {arena_.oangle(), - FmtJoin( - n.parametric_bindings(), Joiner::kCommaSpace, - [&](const ParametricBinding* n, Comments& comments, - DocArena& arena) { return Format(n); }, - comments_, arena_), - arena_.cangle()})); + signature_pieces.push_back( + ConcatNGroup(arena_, {arena_.oangle(), + FormatJoin( + n.parametric_bindings(), Joiner::kCommaSpace, + [&](const ParametricBinding* n) { + return FormatParametricBindingPtr(n); + }), + arena_.cangle()})); } signature_pieces.push_back(arena_.break1()); signature_pieces.push_back(arena_.ocurl()); Pos last_stmt_limit = n.body_span().start(); - // We update this with the position that's relevant for config start - // comments_. + // We update this with the position that's relevant for config start comments. std::optional config_comment_start_pos; std::optional init_comment_start_pos; std::optional next_comment_start_pos; @@ -2431,48 +2317,44 @@ DocRef Formatter::Format(const Proc& n, bool is_test) { last_stmt_limit = f->span().limit(); }, [&](const ProcMember* n) { - if (std::optional maybe_doc = - EmitCommentsBetween(last_stmt_limit, n->span().start(), - comments_, arena_, nullptr)) { + if (std::optional maybe_doc = FormatCommentsBetween( + last_stmt_limit, n->span().start(), nullptr)) { stmt_pieces.push_back( arena_.MakeConcat(maybe_doc.value(), arena_.hard_line())); } - stmt_pieces.push_back(Format(*n)); + stmt_pieces.push_back(FormatProcMember(*n)); stmt_pieces.push_back(arena_.semi()); stmt_pieces.push_back(arena_.hard_line()); last_stmt_limit = n->span().limit(); }, [&](const ConstantDef* n) { - if (std::optional maybe_doc = - EmitCommentsBetween(last_stmt_limit, n->span().start(), - comments_, arena_, nullptr)) { + if (std::optional maybe_doc = FormatCommentsBetween( + last_stmt_limit, n->span().start(), nullptr)) { stmt_pieces.push_back( arena_.MakeConcat(maybe_doc.value(), arena_.hard_line())); } - stmt_pieces.push_back(Format(*n)); + stmt_pieces.push_back(FormatConstantDef(*n)); stmt_pieces.push_back(arena_.hard_line()); last_stmt_limit = n->span().limit(); }, [&](const TypeAlias* n) { - if (std::optional maybe_doc = - EmitCommentsBetween(last_stmt_limit, n->span().start(), - comments_, arena_, nullptr)) { + if (std::optional maybe_doc = FormatCommentsBetween( + last_stmt_limit, n->span().start(), nullptr)) { stmt_pieces.push_back( arena_.MakeConcat(maybe_doc.value(), arena_.hard_line())); } - stmt_pieces.push_back(Format(*n)); + stmt_pieces.push_back(FormatTypeAlias(*n)); stmt_pieces.push_back(arena_.semi()); stmt_pieces.push_back(arena_.hard_line()); last_stmt_limit = n->span().limit(); }, [&](const ConstAssert* n) { - if (std::optional maybe_doc = - EmitCommentsBetween(last_stmt_limit, n->span().start(), - comments_, arena_, nullptr)) { + if (std::optional maybe_doc = FormatCommentsBetween( + last_stmt_limit, n->span().start(), nullptr)) { stmt_pieces.push_back( arena_.MakeConcat(maybe_doc.value(), arena_.hard_line())); } - stmt_pieces.push_back(Format(*n)); + stmt_pieces.push_back(FormatConstAssert(*n)); stmt_pieces.push_back(arena_.semi()); stmt_pieces.push_back(arena_.hard_line()); last_stmt_limit = n->span().limit(); @@ -2482,20 +2364,17 @@ DocRef Formatter::Format(const Proc& n, bool is_test) { } CHECK(config_comment_start_pos.has_value()); - std::optional config_comment = - EmitCommentsBetween(config_comment_start_pos, n.config().span().start(), - comments_, arena_, nullptr); + std::optional config_comment = FormatCommentsBetween( + config_comment_start_pos, n.config().span().start(), nullptr); CHECK(init_comment_start_pos.has_value()); - std::optional init_comment = - EmitCommentsBetween(init_comment_start_pos, n.init().span().start(), - comments_, arena_, nullptr); + std::optional init_comment = FormatCommentsBetween( + init_comment_start_pos, n.init().span().start(), nullptr); CHECK(next_comment_start_pos.has_value()); - std::optional next_comment = - EmitCommentsBetween(next_comment_start_pos, n.next().span().start(), - comments_, arena_, nullptr); + std::optional next_comment = FormatCommentsBetween( + next_comment_start_pos, n.next().span().start(), nullptr); // Comments between the last statement and the end of the proc. - std::optional end_comment = EmitCommentsBetween( - last_stmt_limit, n.body_span().limit(), comments_, arena_, nullptr); + std::optional end_comment = + FormatCommentsBetween(last_stmt_limit, n.body_span().limit(), nullptr); std::vector config_pieces = { arena_.MakeText("config"), @@ -2503,7 +2382,7 @@ DocRef Formatter::Format(const Proc& n, bool is_test) { arena_.space(), arena_.ocurl(), arena_.break1(), - FmtBlock(*n.config().body(), comments_, arena_, /*add_curls=*/false), + FormatBlock(*n.config().body(), /*add_curls=*/false), arena_.break1(), arena_.ccurl(), }; @@ -2513,7 +2392,7 @@ DocRef Formatter::Format(const Proc& n, bool is_test) { arena_.space(), arena_.ocurl(), arena_.break1(), - FmtBlock(*n.init().body(), comments_, arena_, /*add_curls=*/false), + FormatBlock(*n.init().body(), /*add_curls=*/false), arena_.break1(), arena_.ccurl(), }; @@ -2524,7 +2403,7 @@ DocRef Formatter::Format(const Proc& n, bool is_test) { arena_.space(), arena_.ocurl(), arena_.break1(), - FmtBlock(*n.next().body(), comments_, arena_, /*add_curls=*/false), + FormatBlock(*n.next().body(), /*add_curls=*/false), arena_.break1(), arena_.ccurl(), }; @@ -2575,15 +2454,15 @@ DocRef Formatter::Format(const Proc& n, bool is_test) { return ConcatNGroup(arena_, proc_pieces); } -DocRef Formatter::Format(const TestFunction& n) { +DocRef Formatter::FormatTestFunction(const TestFunction& n) { std::vector pieces; pieces.push_back(arena_.MakeText("#[test]")); pieces.push_back(arena_.hard_line()); - pieces.push_back(Format(n.fn(), /*is_test=*/true)); + pieces.push_back(FormatFunction(n.fn(), /*is_test=*/true)); return ConcatN(arena_, pieces); } -DocRef Formatter::Format(const TestProc& n) { +DocRef Formatter::FormatTestProc(const TestProc& n) { std::vector pieces; if (n.expected_fail_label().has_value()) { pieces.push_back(arena_.MakeText( @@ -2593,11 +2472,11 @@ DocRef Formatter::Format(const TestProc& n) { pieces.push_back(arena_.MakeText("#[test_proc]")); } pieces.push_back(arena_.hard_line()); - pieces.push_back(Format(*n.proc(), /*is_test=*/true)); + pieces.push_back(FormatProc(*n.proc(), /*is_test=*/true)); return ConcatN(arena_, pieces); } -DocRef Formatter::Format(const QuickCheck& n) { +DocRef Formatter::FormatQuickCheck(const QuickCheck& n) { std::vector pieces; switch (n.test_cases().tag()) { case QuickCheckTestCasesTag::kExhaustive: @@ -2613,14 +2492,14 @@ DocRef Formatter::Format(const QuickCheck& n) { break; } pieces.push_back(arena_.hard_line()); - pieces.push_back(Format(*n.fn())); + pieces.push_back(FormatFunction(*n.fn())); return ConcatN(arena_, pieces); } -static void FmtStructMembers(const StructDefBase& n, Comments& comments, - DocArena& arena, std::vector& pieces) { +void Formatter::FormatStructMembers(const StructDefBase& n, + std::vector& pieces) { if (!n.members().empty()) { - pieces.push_back(arena.break1()); + pieces.push_back(arena_.break1()); } std::vector body_pieces; @@ -2634,41 +2513,39 @@ static void FmtStructMembers(const StructDefBase& n, Comments& comments, // See if there are comments between the last member and the start of this // member. std::optional last_comment_span; - if (std::optional comments_doc = - EmitCommentsBetween(last_member_pos, member_start, comments, arena, - &last_comment_span)) { + if (std::optional comments_doc = FormatCommentsBetween( + last_member_pos, member_start, &last_comment_span)) { body_pieces.push_back(comments_doc.value()); - body_pieces.push_back(arena.hard_line()); + body_pieces.push_back(arena_.hard_line()); // If the comment abuts the member we don't put a newline in // between, we assume the comment is associated with the member. if (last_comment_span->limit().lineno() != member_start.lineno()) { - body_pieces.push_back(arena.hard_line()); + body_pieces.push_back(arena_.hard_line()); } } last_member_pos = member_span.limit(); - body_pieces.push_back(arena.MakeText(member->name())); - body_pieces.push_back(arena.colon()); - body_pieces.push_back(arena.space()); - body_pieces.push_back(Fmt(*member->type(), comments, arena)); + body_pieces.push_back(arena_.MakeText(member->name())); + body_pieces.push_back(arena_.colon()); + body_pieces.push_back(arena_.space()); + body_pieces.push_back(FormatTypeAnnotation(*member->type())); bool last_member = i + 1 == n.members().size(); if (last_member) { - body_pieces.push_back(arena.MakeFlatChoice(/*on_flat=*/arena.empty(), - /*on_break=*/arena.comma())); + body_pieces.push_back(arena_.MakeFlatChoice(/*on_flat=*/arena_.empty(), + /*on_break=*/arena_.comma())); } else { - body_pieces.push_back(arena.comma()); + body_pieces.push_back(arena_.comma()); } // See if there are inline comments after the member. - Pos new_last_member_pos = - CollectInlineComments(member_span.limit(), last_member_pos, comments, - arena, body_pieces, last_comment_span); + Pos new_last_member_pos = FormatCollectInlineComments( + member_span.limit(), last_member_pos, body_pieces, last_comment_span); bool had_inline = new_last_member_pos != last_member_pos; if (!last_member) { - body_pieces.push_back(had_inline ? arena.hard_line() : arena.break1()); + body_pieces.push_back(had_inline ? arena_.hard_line() : arena_.break1()); } last_member_pos = new_last_member_pos; } @@ -2677,18 +2554,17 @@ static void FmtStructMembers(const StructDefBase& n, Comments& comments, // of the block. std::optional last_comment_span; bool emitted_trailing_comment = false; - if (std::optional comments_doc = - EmitCommentsBetween(last_member_pos, n.span().limit(), comments, - arena, &last_comment_span)) { - body_pieces.push_back(arena.hard_line()); + if (std::optional comments_doc = FormatCommentsBetween( + last_member_pos, n.span().limit(), &last_comment_span)) { + body_pieces.push_back(arena_.hard_line()); body_pieces.push_back(comments_doc.value()); emitted_trailing_comment = true; } - pieces.push_back(arena.MakeNest(ConcatN(arena, body_pieces))); + pieces.push_back(arena_.MakeNest(ConcatN(arena_, body_pieces))); if (!n.members().empty() || emitted_trailing_comment) { - pieces.push_back(arena.break1()); + pieces.push_back(arena_.break1()); } } @@ -2698,7 +2574,7 @@ DocRef Formatter::FormatStructDefBase( std::vector pieces; std::vector attrs; for (const Attribute* attribute : n.attributes()) { - attrs.push_back(FmtAttribute(*attribute, arena_)); + attrs.push_back(FormatAttribute(*attribute)); } if (n.is_public()) { pieces.push_back(arena_.Make(Keyword::kPub)); @@ -2710,40 +2586,40 @@ DocRef Formatter::FormatStructDefBase( if (!n.parametric_bindings().empty()) { pieces.push_back(arena_.oangle()); - pieces.push_back(FmtJoin( + pieces.push_back(FormatJoin( n.parametric_bindings(), Joiner::kCommaSpace, - [&](const ParametricBinding* n, Comments& comments, DocArena& arena) { - return Format(n); - }, - comments_, arena_)); + [&](const ParametricBinding* n) { + return FormatParametricBindingPtr(n); + })); pieces.push_back(arena_.cangle()); } pieces.push_back(arena_.space()); pieces.push_back(arena_.ocurl()); - FmtStructMembers(n, comments_, arena_, pieces); + FormatStructMembers(n, pieces); pieces.push_back(arena_.ccurl()); - return JoinWithAttrs(attrs, ConcatNGroup(arena_, pieces), arena_); + return FormatJoinWithAttrs(attrs, ConcatNGroup(arena_, pieces)); } -DocRef Formatter::Format(const StructDef& n) { +DocRef Formatter::FormatStructDef(const StructDef& n) { return FormatStructDefBase(n, Keyword::kStruct, n.extern_type_name()); } -DocRef Formatter::Format(const ProcDef& n) { +DocRef Formatter::FormatProcDef(const ProcDef& n) { return FormatStructDefBase(n, Keyword::kProc, /*extern_type_name=*/std::nullopt); } -DocRef Formatter::Format(const ImplMember& n) { - return absl::visit(Visitor{ - [&](const Function* n) { return Format(*n); }, - [&](const ConstantDef* n) { return Format(*n); }, - [&](const VerbatimNode* n) { return Format(*n); }, - }, - n); +DocRef Formatter::FormatImplMember(const ImplMember& n) { + return absl::visit( + Visitor{ + [&](const Function* n) { return FormatFunction(*n); }, + [&](const ConstantDef* n) { return FormatConstantDef(*n); }, + [&](const VerbatimNode* n) { return FormatVerbatimNode(*n); }, + }, + n); } template @@ -2773,22 +2649,20 @@ DocRef Formatter::FormatImplOrTrait(const T& n, Keyword keyword, } last_was_func = std::holds_alternative(member); - // See if there are comments_ between the last member and the start of this + // See if there are comments between the last member and the start of this // member. Span member_span = ToAstNode(member)->GetSpan().value(); std::optional last_comment_span; - if (std::optional comments_doc = - EmitCommentsBetween(last_member_pos, member_span.start(), comments_, - arena_, &last_comment_span)) { + if (std::optional comments_doc = FormatCommentsBetween( + last_member_pos, member_span.start(), &last_comment_span)) { body_pieces.push_back(comments_doc.value()); body_pieces.push_back(arena_.hard_line()); } - body_pieces.push_back(Format(member)); + body_pieces.push_back(FormatImplMember(member)); last_member_pos = member_span.limit(); - last_member_pos = - CollectInlineComments(member_span.limit(), last_member_pos, comments_, - arena_, body_pieces, last_comment_span); + last_member_pos = FormatCollectInlineComments( + member_span.limit(), last_member_pos, body_pieces, last_comment_span); body_pieces.push_back(arena_.hard_line()); } @@ -2800,31 +2674,29 @@ DocRef Formatter::FormatImplOrTrait(const T& n, Keyword keyword, } pieces.push_back(arena_.ccurl()); - return JoinWithAttr(attr, ConcatNGroup(arena_, pieces), arena_); + return FormatJoinWithAttr(attr, ConcatNGroup(arena_, pieces)); } -DocRef Formatter::Format(const Impl& n) { +DocRef Formatter::FormatImpl(const Impl& n) { return FormatImplOrTrait(n, Keyword::kImpl, - Fmt(*n.struct_ref(), comments_, arena_)); + FormatTypeAnnotation(*n.struct_ref())); } -DocRef Formatter::Format(const Trait& n) { - return FormatImplOrTrait(n, Keyword::kTrait, - Fmt(*n.name_def(), comments_, arena_)); +DocRef Formatter::FormatTrait(const Trait& n) { + return FormatImplOrTrait(n, Keyword::kTrait, FormatNameDef(*n.name_def())); } -DocRef Formatter::Format(const EnumMember& n) { +DocRef Formatter::FormatEnumMember(const EnumMember& n) { return ConcatNGroup( - arena_, - {Fmt(*n.name_def, comments_, arena_), arena_.space(), arena_.equals(), - arena_.break1(), Fmt(*n.value, comments_, arena_), arena_.comma()}); + arena_, {FormatNameDef(*n.name_def), arena_.space(), arena_.equals(), + arena_.break1(), FormatExpr(*n.value), arena_.comma()}); } -DocRef Formatter::Format(const EnumDef& n) { +DocRef Formatter::FormatEnumDef(const EnumDef& n) { std::vector pieces; std::vector attrs; for (const Attribute* attribute : n.attributes()) { - attrs.push_back(FmtAttribute(*attribute, arena_)); + attrs.push_back(FormatAttribute(*attribute)); } if (n.is_public()) { pieces.push_back(arena_.Make(Keyword::kPub)); @@ -2838,7 +2710,7 @@ DocRef Formatter::Format(const EnumDef& n) { if (n.type_annotation() != nullptr) { pieces.push_back(arena_.colon()); pieces.push_back(arena_.space()); - pieces.push_back(Fmt(*n.type_annotation(), comments_, arena_)); + pieces.push_back(FormatTypeAnnotation(*n.type_annotation())); pieces.push_back(arena_.space()); } @@ -2857,9 +2729,8 @@ DocRef Formatter::Format(const EnumDef& n) { Pos member_start = member_span->start(); std::optional last_comment_span; - if (std::optional comments_doc = - EmitCommentsBetween(last_member_pos, member_start, comments_, - arena_, &last_comment_span)) { + if (std::optional comments_doc = FormatCommentsBetween( + last_member_pos, member_start, &last_comment_span)) { nested.push_back(comments_doc.value()); nested.push_back(arena_.hard_line()); @@ -2873,7 +2744,7 @@ DocRef Formatter::Format(const EnumDef& n) { last_member_pos = member_span->limit(); // Here we actually emit the formatted member. - nested.push_back(Format(node)); + nested.push_back(FormatEnumMember(node)); if (i + 1 != n.values().size()) { nested.push_back(arena_.hard_line()); } @@ -2882,9 +2753,8 @@ DocRef Formatter::Format(const EnumDef& n) { // See if there are any comments to emit after the last statement to the end // of the block. std::optional last_comment_span; - if (std::optional comments_doc = - EmitCommentsBetween(last_member_pos, n.span().limit(), comments_, - arena_, &last_comment_span)) { + if (std::optional comments_doc = FormatCommentsBetween( + last_member_pos, n.span().limit(), &last_comment_span)) { nested.push_back(arena_.hard_line()); nested.push_back(comments_doc.value()); } @@ -2893,10 +2763,10 @@ DocRef Formatter::Format(const EnumDef& n) { pieces.push_back(arena_.MakeNest(nested_ref)); pieces.push_back(arena_.hard_line()); pieces.push_back(arena_.ccurl()); - return JoinWithAttrs(attrs, ConcatN(arena_, pieces), arena_); + return FormatJoinWithAttrs(attrs, ConcatN(arena_, pieces)); } -DocRef Formatter::Format(const Import& n) { +DocRef Formatter::FormatImport(const Import& n) { std::vector dotted_pieces; for (size_t i = 0; i < n.subject().size(); ++i) { const std::string& subject_part = n.subject()[i]; @@ -2936,26 +2806,34 @@ DocRef Formatter::Format(const Import& n) { return ConcatNGroup(arena_, pieces); } -DocRef Formatter::Format(const Use& n) { +bool Formatter::IsBlockedExprNoLeader(const Expr& e) { + return e.IsBlockedExprNoLeader(); +} + +bool Formatter::IsBlockedExprWithLeader(const Expr& e) { + return e.IsBlockedExprWithLeader(); +} + +DocRef Formatter::FormatUse(const Use& n) { // TODO(cdleary): 2024-12-07 This is just a stopgap, we should add reflow // capability. return arena_.MakeText(n.ToString()); } -DocRef Formatter::Format(const Let& n, bool trailing_semi) { +DocRef Formatter::FormatLet(const Let& n, bool trailing_semi) { std::vector leader_pieces = { arena_.Make(n.is_const() ? Keyword::kConst : Keyword::kLet), - arena_.space(), Fmt(*n.name_def_tree(), comments_, arena_)}; + arena_.space(), FormatNameDefTree(*n.name_def_tree())}; if (const TypeAnnotation* t = n.type_annotation()) { leader_pieces.push_back(arena_.colon()); leader_pieces.push_back(arena_.space()); - leader_pieces.push_back(Fmt(*t, comments_, arena_)); + leader_pieces.push_back(FormatTypeAnnotation(*t)); } leader_pieces.push_back(arena_.space()); leader_pieces.push_back(arena_.equals()); - const DocRef rhs_doc_internal = Fmt(*n.rhs(), comments_, arena_); + const DocRef rhs_doc_internal = FormatExpr(*n.rhs()); DocRef rhs_doc = rhs_doc_internal; if (trailing_semi) { @@ -2965,7 +2843,7 @@ DocRef Formatter::Format(const Let& n, bool trailing_semi) { } DocRef body; - if (n.rhs()->IsBlockedExprAnyLeader()) { + if (IsBlockedExprNoLeader(*n.rhs()) || IsBlockedExprWithLeader(*n.rhs())) { // For blocked expressions we don't align them to the equals in the let, // because it'd shove constructs like `let really_long_identifier = for ...` // too far to the right hand side. @@ -2984,14 +2862,14 @@ DocRef Formatter::Format(const Let& n, bool trailing_semi) { // If the blocky expression has a leader, and that leader doesn't fit in // the line, we want to nest the whole thing so it has space to look // normal and it knows it's in break mode. - if (n.rhs()->IsBlockedExprWithLeader()) { + if (IsBlockedExprWithLeader(*n.rhs())) { // If the leading component fits, then see what we can fit flat from the // RHS, we know we can at least fit that. // // If the leading component does not fit, emit the whole construct nested // on the next line. - DocRef leader = arena_.MakeConcat( - arena_.space(), FmtBlockedExprLeader(*n.rhs(), comments_, arena_)); + DocRef leader = + arena_.MakeConcat(arena_.space(), FormatBlockedExprLeader(*n.rhs())); DocRef nested = arena_.MakeNest(arena_.MakeConcat(arena_.hard_line(), rhs_doc)); on_other_ref = arena_.MakeModeSelect(leader, /*on_flat=*/on_other_ref, @@ -3013,11 +2891,11 @@ DocRef Formatter::Format(const Let& n, bool trailing_semi) { return ConcatNGroup(arena_, {leader, body}); } -DocRef Formatter::Format(const TypeAlias& n) { +DocRef Formatter::FormatTypeAlias(const TypeAlias& n) { std::vector pieces; std::vector attrs; for (const Attribute* attribute : n.attributes()) { - attrs.push_back(FmtAttribute(*attribute, arena_)); + attrs.push_back(FormatAttribute(*attribute)); } if (n.is_public()) { pieces.push_back(arena_.Make(Keyword::kPub)); @@ -3029,11 +2907,11 @@ DocRef Formatter::Format(const TypeAlias& n) { pieces.push_back(arena_.space()); pieces.push_back(arena_.equals()); pieces.push_back(arena_.break1()); - pieces.push_back(Fmt(n.type_annotation(), comments_, arena_)); - return JoinWithAttrs(attrs, ConcatNGroup(arena_, pieces), arena_); + pieces.push_back(FormatTypeAnnotation(n.type_annotation())); + return FormatJoinWithAttrs(attrs, ConcatNGroup(arena_, pieces)); } -DocRef Formatter::Format(const ProcAlias& n) { +DocRef Formatter::FormatProcAlias(const ProcAlias& n) { std::vector pieces; std::optional attr; if (n.is_public()) { @@ -3049,49 +2927,49 @@ DocRef Formatter::Format(const ProcAlias& n) { ProcAlias::Target target = n.target(); if (std::holds_alternative(target)) { - pieces.push_back(Fmt(*std::get(target), comments_, arena_)); + pieces.push_back(FormatNameRef(*std::get(target))); } else { - pieces.push_back(Fmt(*std::get(target), comments_, arena_)); + pieces.push_back(FormatColonRef(*std::get(target))); } - std::optional parametrics_doc = FmtExplicitParametrics( - absl::MakeConstSpan(n.parametrics()), comments_, arena_); + std::optional parametrics_doc = + FormatExplicitParametrics(absl::MakeConstSpan(n.parametrics())); if (parametrics_doc.has_value()) { pieces.push_back(*parametrics_doc); } - return JoinWithAttr(attr, ConcatNGroup(arena_, pieces), arena_); + return FormatJoinWithAttr(attr, ConcatNGroup(arena_, pieces)); } -DocRef Formatter::Format(const ModuleMember& n) { +DocRef Formatter::FormatModuleMember(const ModuleMember& n) { return absl::visit( Visitor{ - [&](const Function* n) { return Format(*n); }, - [&](const Proc* n) { return Format(*n); }, - [&](const TestFunction* n) { return Format(*n); }, + [&](const Function* n) { return FormatFunction(*n); }, + [&](const Proc* n) { return FormatProc(*n); }, + [&](const TestFunction* n) { return FormatTestFunction(*n); }, // Formatting the function takes care of the attributes so we don't // need a special formatting function for FuzzTestFunction. - [&](const FuzzTestFunction* n) { return Format(n->fn()); }, - [&](const TestProc* n) { return Format(*n); }, - [&](const QuickCheck* n) { return Format(*n); }, + [&](const FuzzTestFunction* n) { return FormatFunction(n->fn()); }, + [&](const TestProc* n) { return FormatTestProc(*n); }, + [&](const QuickCheck* n) { return FormatQuickCheck(*n); }, [&](const TypeAlias* n) { - return arena_.MakeConcat(Format(*n), arena_.semi()); + return arena_.MakeConcat(FormatTypeAlias(*n), arena_.semi()); }, [&](const ProcAlias* n) { - return arena_.MakeConcat(Format(*n), arena_.semi()); + return arena_.MakeConcat(FormatProcAlias(*n), arena_.semi()); }, - [&](const StructDef* n) { return Format(*n); }, - [&](const ProcDef* n) { return Format(*n); }, - [&](const Impl* n) { return Format(*n); }, - [&](const Trait* n) { return Format(*n); }, - [&](const ConstantDef* n) { return Format(*n); }, - [&](const EnumDef* n) { return Format(*n); }, - [&](const Import* n) { return Format(*n); }, - [&](const Use* n) { return Format(*n); }, + [&](const StructDef* n) { return FormatStructDef(*n); }, + [&](const ProcDef* n) { return FormatProcDef(*n); }, + [&](const Impl* n) { return FormatImpl(*n); }, + [&](const Trait* n) { return FormatTrait(*n); }, + [&](const ConstantDef* n) { return FormatConstantDef(*n); }, + [&](const EnumDef* n) { return FormatEnumDef(*n); }, + [&](const Import* n) { return FormatImport(*n); }, + [&](const Use* n) { return FormatUse(*n); }, [&](const ConstAssert* n) { - return arena_.MakeConcat(Format(*n), arena_.semi()); + return arena_.MakeConcat(FormatConstAssert(*n), arena_.semi()); }, - [&](const VerbatimNode* n) { return Format(*n); }, + [&](const VerbatimNode* n) { return FormatVerbatimNode(*n); }, }, n); } @@ -3164,16 +3042,15 @@ static int NumHardLinesAfter(const AstNode* node, const ModuleMember& member, return num_hard_lines; } -absl::StatusOr Formatter::Format(const Module& n) { +absl::StatusOr Formatter::FormatModule(const Module& n) { std::vector pieces; std::optional last_comment_span; std::optional last_entity_pos; if (!n.attributes().empty()) { if (std::optional span = n.GetAttributeSpan(); span.has_value()) { - if (std::optional comments_doc = - EmitCommentsBetween(std::nullopt, span->limit(), comments_, - arena_, &last_comment_span); + if (std::optional comments_doc = FormatCommentsBetween( + std::nullopt, span->limit(), &last_comment_span); comments_doc.has_value()) { pieces.push_back(comments_doc.value()); pieces.push_back(arena_.hard_line()); @@ -3272,9 +3149,8 @@ absl::StatusOr Formatter::Format(const Module& n) { CHECK_GE(member_start, last_entity_pos.value()); } - if (std::optional comments_doc = - EmitCommentsBetween(last_entity_pos, member_start, comments_, - arena_, &last_comment_span)) { + if (std::optional comments_doc = FormatCommentsBetween( + last_entity_pos, member_start, &last_comment_span)) { pieces.push_back(comments_doc.value()); pieces.push_back(arena_.hard_line()); @@ -3295,15 +3171,14 @@ absl::StatusOr Formatter::Format(const Module& n) { } // Here we actually emit the formatted member. - pieces.push_back(Format(member)); + pieces.push_back(FormatModuleMember(member)); // Now we reflect the emission of the member. last_entity_pos = member_span->limit(); // See if there are inline comments after the statement. - last_entity_pos = - CollectInlineComments(member_limit, last_entity_pos.value(), comments_, - arena_, pieces, last_comment_span); + last_entity_pos = FormatCollectInlineComments( + member_limit, last_entity_pos.value(), pieces, last_comment_span); int num_hard_lines = NumHardLinesAfter(node, member, n.top(), i); for (int i = 0; i < num_hard_lines; ++i) { @@ -3314,16 +3189,15 @@ absl::StatusOr Formatter::Format(const Module& n) { if (std::optional last_data_limit = comments_.last_data_limit(); last_data_limit.has_value() && last_entity_pos < last_data_limit) { std::optional last_comment_span; - if (std::optional comments_doc = - EmitCommentsBetween(last_entity_pos, last_data_limit.value(), - comments_, arena_, &last_comment_span)) { + if (std::optional comments_doc = FormatCommentsBetween( + last_entity_pos, last_data_limit.value(), &last_comment_span)) { pieces.push_back(comments_doc.value()); pieces.push_back(arena_.hard_line()); } } - // Check if there are any comments that were within the span of the - // module, but not placed. + // Check if there are any comments that were within the span of the module, + // but not placed. if (comments_.last_data_limit().has_value()) { Pos last_data_limit = comments_.last_data_limit().value(); @@ -3337,7 +3211,7 @@ absl::StatusOr Formatter::Format(const Module& n) { std::string{absl::StripTrailingAsciiWhitespace(comment->text)}; return absl::InternalError(absl::StrFormat( "Formatting was skipped because a comment at %s would be " - "deleted by the formatter: //%s\nThis is probably due to a bug " + "deleted by the *this: //%s\nThis is probably due to a bug " "(which may not have been reported yet). To complete formatting, " "try moving the comment to a different line.", comment->span.ToString(arena_.file_table()), comment_text)); @@ -3348,39 +3222,59 @@ absl::StatusOr Formatter::Format(const Module& n) { return ConcatN(arena_, pieces); } -static absl::StatusOr AutoFmt(const Module& m, Comments& comments, +DocRef Formatter::FormatStatementBlock(const StatementBlock& n) { + return FormatBlock(n, /*add_curls=*/n.has_braces()); +} +DocRef Formatter::FormatXlsTuple(const XlsTuple& n) { return FormatTuple(n); } + +static absl::StatusOr AutoFmt(const Module& m, + Formatter& formatter, int64_t text_width) { - DocArena arena(*m.file_table()); - Formatter formatter(comments, arena); - XLS_ASSIGN_OR_RETURN(DocRef ref, formatter.Format(m)); - return PrettyPrint(arena, ref, text_width); + XLS_ASSIGN_OR_RETURN(DocRef ref, formatter.FormatModule(m)); + return PrettyPrint(formatter.arena(), ref, text_width); } absl::StatusOr AutoFmt(VirtualizableFilesystem& vfs, - const Module& m, Comments& comments, + const Module& m, Formatter& formatter, int64_t text_width) { XLS_RET_CHECK(m.fs_path().has_value()); - FormatDisabler disabler(vfs, comments, *m.fs_path()); + FormatDisabler disabler(vfs, formatter.comments(), *m.fs_path()); XLS_ASSIGN_OR_RETURN( std::unique_ptr clone, CloneModule(m, [&](const AstNode* node, Module*, const absl::flat_hash_map&) { return disabler(node); })); - return AutoFmt(*clone, comments, text_width); + return AutoFmt(*clone, formatter, text_width); } absl::StatusOr AutoFmt(VirtualizableFilesystem& vfs, - const Module& m, Comments& comments, + const Module& m, Formatter& formatter, std::string contents, int64_t text_width) { - FormatDisabler disabler(vfs, comments, contents); + FormatDisabler disabler(vfs, formatter.comments(), contents); XLS_ASSIGN_OR_RETURN( std::unique_ptr clone, CloneModule(m, [&](const AstNode* node, Module*, const absl::flat_hash_map&) { return disabler(node); })); - return AutoFmt(*clone, comments, text_width); + return AutoFmt(*clone, formatter, text_width); +} + +absl::StatusOr AutoFmt(VirtualizableFilesystem& vfs, + const Module& m, Comments& comments, + int64_t text_width) { + DocArena arena(*m.file_table()); + Formatter formatter(comments, arena); + return AutoFmt(vfs, m, formatter, text_width); +} + +absl::StatusOr AutoFmt(VirtualizableFilesystem& vfs, + const Module& m, Comments& comments, + std::string contents, int64_t text_width) { + DocArena arena(*m.file_table()); + Formatter formatter(comments, arena); + return AutoFmt(vfs, m, formatter, std::move(contents), text_width); } // AutoFmt output should be the same as input after whitespace is eliminated diff --git a/xls/dslx/fmt/ast_fmt.h b/xls/dslx/fmt/ast_fmt.h index aaf00d3161..a88797f5c0 100644 --- a/xls/dslx/fmt/ast_fmt.h +++ b/xls/dslx/fmt/ast_fmt.h @@ -16,6 +16,7 @@ #define XLS_DSLX_FMT_AST_FMT_H_ #include +#include #include #include #include @@ -26,63 +27,192 @@ #include "xls/dslx/fmt/pretty_print.h" #include "xls/dslx/frontend/ast.h" #include "xls/dslx/frontend/module.h" +#include "xls/dslx/frontend/pos.h" #include "xls/dslx/frontend/token.h" #include "xls/dslx/virtualizable_file_system.h" +#include "xls/ir/channel.h" namespace xls::dslx { // TODO: davidplass - Move this class to its own file after all the // Expr-descendants are migrated to it. class Formatter { + friend class FmtExprVisitor; + public: Formatter(Comments& comments, DocArena& arena) : comments_(comments), arena_(arena) {} - // Each `Format` method creates a pretty-printable document from the given AST - // node `n`. + virtual ~Formatter() = default; + + Comments& comments() { return comments_; } + const Comments& comments() const { return comments_; } + DocArena& arena() { return arena_; } + const DocArena& arena() const { return arena_; } + + // Each `FormatXXX` method creates a pretty-printable document from the given + // AST node `n`. + // keep-sorted start - DocRef Format(const Expr& n); - DocRef Format(const Function& n, bool is_test = false); - DocRef Format(const Let& n, bool trailing_semi); - // If `trailing_semi` is true, then a trailing semicolon will also be emitted. - DocRef Format(const Statement& n, bool trailing_semi); - DocRef Format(const VerbatimNode& n); - absl::StatusOr Format(const Module& n); + virtual DocRef FormatBlockedExprLeader(const Expr& e); + virtual DocRef FormatExpr(const Expr& n, bool suppress_parens = false); + virtual DocRef FormatFunction(const Function& n, bool is_test = false); + virtual DocRef FormatLet(const Let& n, bool trailing_semi); + virtual DocRef FormatStatement(const Statement& n, bool trailing_semi); + virtual DocRef FormatTypeAnnotation(const TypeAnnotation& n); + virtual DocRef FormatVerbatimNode(const VerbatimNode& n); + virtual absl::StatusOr FormatModule(const Module& n); // keep-sorted end - private: + protected: + enum class Joiner : uint8_t { + kCommaSpace, + kCommaBreak1, + + kCommaHardlineTrailingCommaAlways, + + // Separates via a comma and break1, but groups the element with its + // delimiter. This is useful when we're packing member elements that we want + // to be reflowed across lines. + // + // Note that, in this mode, if we span multiple lines, we'll put a trailing + // comma as well. + kCommaBreak1AsGroupTrailingCommaOnBreak, + kCommaBreak1AsGroupTrailingCommaAlways, + kCommaBreak1AsGroupNoTrailingComma, + + kSpaceBarBreak, + kHardLine, + }; + + std::optional FormatCommentsBetween( + std::optional start, const Pos& limit, + std::optional* last_comment_span = nullptr); + template DocRef FormatImplOrTrait(const T& n, Keyword keyword, DocRef name_or_struct_ref); // keep-sorted start - DocRef Format(const ConstAssert& n); - DocRef Format(const ConstantDef& n); - DocRef Format(const EnumDef& n); - DocRef Format(const EnumMember& n); - DocRef Format(const Impl& n); - DocRef Format(const ImplMember& n); - DocRef Format(const Import& n); - DocRef Format(const ModuleMember& n); - DocRef Format(const ParametricBinding& n); - DocRef Format(const ParametricBinding* n); - DocRef Format(const Proc& n, bool is_test = false); - DocRef Format(const ProcAlias& n); - DocRef Format(const ProcDef& n); - DocRef Format(const ProcMember& n); - DocRef Format(const QuickCheck& n); - DocRef Format(const StructDef& n); - DocRef Format(const TestFunction& n); - DocRef Format(const TestProc& n); - DocRef Format(const Trait& n); - DocRef Format(const TypeAlias& n); - DocRef Format(const Use& n); - DocRef FormatParams(absl::Span params); - DocRef FormatStructDefBase( + virtual DocRef FormatAllOnesMacro(const AllOnesMacro& n); + virtual DocRef FormatArray(const Array& n); + virtual DocRef FormatArrayTypeAnnotation(const ArrayTypeAnnotation& n); + virtual DocRef FormatAttr(const Attr& n); + virtual DocRef FormatAttribute(const Attribute& n); + virtual DocRef FormatBinop(const Binop& n); + virtual DocRef FormatBlock(const StatementBlock& n, bool add_curls = true, + bool force_multiline = false); + virtual DocRef FormatBuiltinTypeAnnotation(const BuiltinTypeAnnotation& n); + virtual DocRef FormatCast(const Cast& n); + virtual DocRef FormatChannelConfig(const ChannelConfig& n); + virtual DocRef FormatChannelDecl(const ChannelDecl& n); + virtual DocRef FormatChannelTypeAnnotation(const ChannelTypeAnnotation& n); + virtual DocRef FormatColonRef(const ColonRef& n); + virtual DocRef FormatConditional(const Conditional& n); + virtual DocRef FormatConstAssert(const ConstAssert& n); + virtual DocRef FormatConstFor(const ConstFor& n); + virtual DocRef FormatConstantDef(const ConstantDef& n); + virtual DocRef FormatEnumDef(const EnumDef& n); + virtual DocRef FormatEnumMember(const EnumMember& n); + virtual DocRef FormatFor(const For& n); + virtual DocRef FormatFormatMacro(const FormatMacro& n); + virtual DocRef FormatFunctionRef(const FunctionRef& n); + virtual DocRef FormatImpl(const Impl& n); + virtual DocRef FormatImplMember(const ImplMember& n); + virtual DocRef FormatImport(const Import& n); + virtual DocRef FormatIndex(const Index& n); + virtual DocRef FormatIndexRhs(const IndexRhs& n); + virtual DocRef FormatInvocation(const Invocation& n); + virtual DocRef FormatLambda(const Lambda& n); + virtual DocRef FormatMatch(const Match& n); + virtual DocRef FormatModuleMember(const ModuleMember& n); + virtual DocRef FormatNameDef(const NameDef& n); + virtual DocRef FormatNameDefTree(const NameDefTree& n); + virtual DocRef FormatNameDefTreeLeaf(const NameDefTree::Leaf& n); + virtual DocRef FormatNameRef(const NameRef& n); + virtual DocRef FormatNumber(const Number& n); + virtual DocRef FormatParametricBinding(const ParametricBinding& n); + virtual DocRef FormatParametricBindingPtr(const ParametricBinding* n); + virtual DocRef FormatParams(absl::Span params); + virtual DocRef FormatProc(const Proc& n, bool is_test = false); + virtual DocRef FormatProcAlias(const ProcAlias& n); + virtual DocRef FormatProcDef(const ProcDef& n); + virtual DocRef FormatProcMember(const ProcMember& n); + virtual DocRef FormatQuickCheck(const QuickCheck& n); + virtual DocRef FormatRange(const Range& n); + virtual DocRef FormatRestOfTuple(const RestOfTuple& n); + virtual DocRef FormatSlice(const Slice& n); + virtual DocRef FormatSpawn(const Spawn& n); + virtual DocRef FormatSplatStructInstance(const SplatStructInstance& n); + virtual DocRef FormatStatementBlock(const StatementBlock& n); + virtual DocRef FormatString(const String& n); + virtual DocRef FormatStructDef(const StructDef& n); + virtual DocRef FormatStructDefBase( const StructDefBase& n, Keyword keyword, const std::optional& extern_type_name); + virtual DocRef FormatStructInstance(const StructInstance& n); + virtual DocRef FormatTestFunction(const TestFunction& n); + virtual DocRef FormatTestProc(const TestProc& n); + virtual DocRef FormatTrait(const Trait& n); + virtual DocRef FormatTupleIndex(const TupleIndex& n); + virtual DocRef FormatTupleTypeAnnotation(const TupleTypeAnnotation& n); + virtual DocRef FormatTypeAlias(const TypeAlias& n); + virtual DocRef FormatTypeRef(const TypeRef& n); + virtual DocRef FormatTypeRefTypeAnnotation(const TypeRefTypeAnnotation& n); + virtual DocRef FormatTypeVariableTypeAnnotation( + const TypeVariableTypeAnnotation& n); + virtual DocRef FormatUnop(const Unop& n); + virtual DocRef FormatUse(const Use& n); + virtual DocRef FormatWidthSlice(const WidthSlice& n); + virtual DocRef FormatWildcardPattern(const WildcardPattern& n); + virtual DocRef FormatXlsTuple(const XlsTuple& n); + virtual DocRef FormatZeroMacro(const ZeroMacro& n); // keep-sorted end + DocRef Format(const Expr* n); + DocRef Format(const TypeAnnotation* n); + DocRef Format(const NameDefTree* n); + DocRef FormatBreakBody(const Array& n); + DocRef FormatBreakRest(const StructInstance& n); + Pos FormatCollectInlineComments(const Pos& prev_limit, + const Pos& last_entity_pos, + std::vector& pieces, + std::optional last_comment_span); + std::optional FormatCommentsNested(const Pos start, const Pos limit); + DocRef FormatConditionalMultiline(const Conditional& n); + std::optional FormatExplicitParametrics( + absl::Span parametrics); + DocRef FormatExprOrType(const ExprOrType& n); + DocRef FormatFlatBody(const Array& n); + DocRef FormatFlatRest(const StructInstance& n); + DocRef FormatForLoopBase(Keyword keyword, const ForLoopBase& n, + bool is_const_for); + DocRef FormatForLoopBaseLeader(Keyword keyword, DocRef names_ref, + const ForLoopBase& n, bool is_const_for); + DocRef FormatJoinWithAttr(std::optional attr, DocRef rest); + DocRef FormatJoinWithAttrs(absl::Span attrs, DocRef rest); + DocRef FormatMakeArrayLeader(const Array& n); + DocRef FormatMakeConditionalTest(const Conditional& n); + DocRef FormatMatchArm(const MatchArm& n); + DocRef FormatParametricArg(const ExprOrType& n); + DocRef FormatSingleStatementBlockInline(const StatementBlock& n, + bool add_curls); + DocRef FormatStructLeader(const TypeAnnotation* struct_ref); + void FormatStructMembers(const StructDefBase& n, std::vector& pieces); + DocRef FormatStructMembersBreak( + Span struct_span, + absl::Span> members); + DocRef FormatStructMembersFlat( + absl::Span> members); + DocRef FormatTuple(const XlsTuple& n); + DocRef FormatTupleWithoutComments(const XlsTuple& n); + template + DocRef FormatJoin(absl::Span items, Joiner joiner, + const std::function& fmt); + + virtual bool IsBlockedExprNoLeader(const Expr& e); + virtual bool IsBlockedExprWithLeader(const Expr& e); + Comments& comments_; DocArena& arena_; }; @@ -90,13 +220,19 @@ class Formatter { inline constexpr int64_t kDslxDefaultTextWidth = 100; // Auto-formatting entry points. -// + // Performs a reflow-capable formatting of module `m` with standard line width, // but with the ability to disable formatting for specific ranges of text. absl::StatusOr AutoFmt(VirtualizableFilesystem& vfs, const Module& m, Comments& comments, int64_t text_width = kDslxDefaultTextWidth); +// Variant which takes a `Formatter`, allowing the caller to customize the +// behavior. +absl::StatusOr AutoFmt(VirtualizableFilesystem& vfs, + const Module& m, Formatter& formatter, + int64_t text_width = kDslxDefaultTextWidth); + // Performs a reflow-capable formatting of module `m` with standard line width, // for the actual `content` but with the ability to disable formatting for // specific ranges of text. @@ -105,6 +241,13 @@ absl::StatusOr AutoFmt(VirtualizableFilesystem& vfs, std::string contents, int64_t text_width = kDslxDefaultTextWidth); +// Variant which takes a `Formatter`, allowing the caller to customize the +// behavior. +absl::StatusOr AutoFmt(VirtualizableFilesystem& vfs, + const Module& m, Formatter& formatter, + std::string contents, + int64_t text_width = kDslxDefaultTextWidth); + // If we fail the postcondition we return back the data we used to detect that // the postcondition was violated. struct AutoFmtPostconditionViolation { diff --git a/xls/dslx/fmt/ast_fmt_test.cc b/xls/dslx/fmt/ast_fmt_test.cc index cbdc4dd8f6..ab081d7580 100644 --- a/xls/dslx/fmt/ast_fmt_test.cc +++ b/xls/dslx/fmt/ast_fmt_test.cc @@ -56,7 +56,7 @@ TEST(BuiltAstFmtTest, FormatCastThatNeedsParens) { Comments empty_comments = Comments::Create({}); DocArena arena(file_table); - DocRef doc = Formatter(empty_comments, arena).Format(*lt); + DocRef doc = Formatter(empty_comments, arena).FormatExpr(*lt); EXPECT_EQ(PrettyPrint(arena, doc, /*text_width=*/100), "(x as t) < x"); } @@ -65,7 +65,7 @@ TEST(BuiltAstFmtTest, FormatIndexThatNeedsParens) { Comments empty_comments = Comments::Create({}); DocArena arena(file_table); - DocRef doc = Formatter(empty_comments, arena).Format(*index); + DocRef doc = Formatter(empty_comments, arena).FormatExpr(*index); EXPECT_EQ(PrettyPrint(arena, doc, /*text_width=*/100), "(x as u32[42])[i]"); } @@ -75,7 +75,7 @@ TEST(BuiltAstFmtTest, FormatTupleIndexThatNeedsParens) { Comments empty_comments = Comments::Create({}); DocArena arena(file_table); - DocRef doc = Formatter(empty_comments, arena).Format(*tuple_index); + DocRef doc = Formatter(empty_comments, arena).FormatExpr(*tuple_index); EXPECT_EQ(PrettyPrint(arena, doc, /*text_width=*/100), "(x[i]).2"); } @@ -85,7 +85,7 @@ TEST(BuiltAstFmtTest, FormatSingleElementTuple) { Comments empty_comments = Comments::Create({}); DocArena arena(file_table); - DocRef doc = Formatter(empty_comments, arena).Format(*tuple); + DocRef doc = Formatter(empty_comments, arena).FormatExpr(*tuple); EXPECT_EQ(PrettyPrint(arena, doc, /*text_width=*/100), "(x0,)"); } @@ -95,7 +95,7 @@ TEST(BuiltAstFmtTest, FormatShortTupleWithoutTrailingComma) { Comments empty_comments = Comments::Create({}); DocArena arena(file_table); - DocRef doc = Formatter(empty_comments, arena).Format(*tuple); + DocRef doc = Formatter(empty_comments, arena).FormatExpr(*tuple); EXPECT_EQ(PrettyPrint(arena, doc, /*text_width=*/100), "(x0, x1)"); } @@ -105,7 +105,7 @@ TEST(BuiltAstFmtTest, FormatShortTupleWithTrailingComma) { Comments empty_comments = Comments::Create({}); DocArena arena(file_table); - DocRef doc = Formatter(empty_comments, arena).Format(*tuple); + DocRef doc = Formatter(empty_comments, arena).FormatExpr(*tuple); EXPECT_EQ(PrettyPrint(arena, doc, /*text_width=*/100), "(x0, x1)"); } @@ -116,7 +116,7 @@ TEST(BuiltAstFmtTest, FormatLongTupleShouldAddTrailingComma) { MakeNElementTupleExpression(40, /*has_trailing_comma=*/true); DocArena arena(file_table); - DocRef doc = Formatter(empty_comments, arena).Format(*tuple); + DocRef doc = Formatter(empty_comments, arena).FormatExpr(*tuple); EXPECT_EQ(PrettyPrint(arena, doc, /*text_width=*/100), R"(( x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, @@ -129,8 +129,8 @@ TEST(BuiltAstFmtTest, FormatLongTupleShouldAddTrailingComma) { MakeNElementTupleExpression(40, /*has_trailing_comma=*/false); DocArena arena(file_table); - DocRef doc = - Formatter(empty_comments, arena).Format(*tuple_without_trailing_comma); + DocRef doc = Formatter(empty_comments, arena) + .FormatExpr(*tuple_without_trailing_comma); EXPECT_EQ(PrettyPrint(arena, doc, /*text_width=*/100), R"(( x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, @@ -144,7 +144,7 @@ TEST(BuiltAstFmtTest, FormatUnopThatNeedsParensOnOperand) { Comments empty_comments = Comments::Create({}); DocArena arena(file_table); - DocRef doc = Formatter(empty_comments, arena).Format(*unop); + DocRef doc = Formatter(empty_comments, arena).FormatExpr(*unop); EXPECT_EQ(PrettyPrint(arena, doc, /*text_width=*/100), "-(x as u32)"); } @@ -153,7 +153,7 @@ TEST(BuiltAstFmtTest, FormatAttrThatNeedsParensOnOperand) { Comments empty_comments = Comments::Create({}); DocArena arena(file_table); - DocRef doc = Formatter(empty_comments, arena).Format(*attr); + DocRef doc = Formatter(empty_comments, arena).FormatExpr(*attr); EXPECT_EQ(PrettyPrint(arena, doc, /*text_width=*/100), "(x * y).my_attr"); } @@ -170,7 +170,7 @@ TEST(AstFmtTest, FormatLet) { DocArena arena(file_table); Formatter fmt(comments, arena); - DocRef doc = fmt.Format(*stmt, /*trailing_semi=*/false); + DocRef doc = fmt.FormatStatement(*stmt, /*trailing_semi=*/false); EXPECT_EQ(PrettyPrint(arena, doc, /*text_width=*/100), "let x: u32 = u32:42"); } @@ -185,7 +185,7 @@ TEST(AstFmtTest, FormatVerbatimNodeTop) { DocArena arena(file_table); XLS_ASSERT_OK_AND_ASSIGN(DocRef doc, - Formatter(empty_comments, arena).Format(m)); + Formatter(empty_comments, arena).FormatModule(m)); // Intentionally small text width, should still be formatted verbatim. EXPECT_EQ(PrettyPrint(arena, doc, /*text_width=*/10), verbatim_text); @@ -202,7 +202,7 @@ TEST(AstFmtTest, FormatVerbatimNodeStatement) { DocArena arena(file_table); DocRef doc = Formatter(empty_comments, arena) - .Format(statement, /*trailing_semi=*/false); + .FormatStatement(statement, /*trailing_semi=*/false); // Intentionally small text width, should still be formatted verbatim. EXPECT_EQ(PrettyPrint(arena, doc, /*text_width=*/10), verbatim_text); @@ -237,7 +237,7 @@ class FunctionFmtTest : public testing::Test { f_, parser_->ParseFunction(Pos(), /*is_public=*/false, bindings_)); Comments comments = Comments::Create(scanner_->comments()); - DocRef doc = Formatter(comments, arena_).Format(*f_); + DocRef doc = Formatter(comments, arena_).FormatFunction(*f_); std::string formatted = PrettyPrint(arena_, doc, kDslxDefaultTextWidth); std::optional maybe_violation = @@ -1442,7 +1442,7 @@ class ModuleFmtTest : public testing::Test { StatusIs(code, HasSubstr(error_substr))); } - private: + protected: FileTable file_table_; }; @@ -3939,5 +3939,32 @@ const_assert!(m::AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA )"); } +class CustomTestFormatter : public Formatter { + public: + using Formatter::Formatter; + + DocRef FormatFunction(const Function& n, bool is_test = false) override { + return arena().MakeText("// CUSTOM_FUNCTION_FORMAT"); + } +}; + +TEST_F(ModuleFmtTest, CustomFormatterOverriddenMethodUsed) { + std::string_view input = R"(fn f() { + u32:42 +} +)"; + std::vector comments_vec; + XLS_ASSERT_OK_AND_ASSIGN( + std::unique_ptr m, + ParseModule(input, "fake.x", "fake", file_table_, &comments_vec)); + Comments comments = Comments::Create(comments_vec); + DocArena arena(file_table_); + CustomTestFormatter custom_formatter(comments, arena); + AllErrorsFilesystem vfs; + XLS_ASSERT_OK_AND_ASSIGN( + std::string got, AutoFmt(vfs, *m, custom_formatter, std::string(input))); + EXPECT_EQ(got, "// CUSTOM_FUNCTION_FORMAT\n"); +} + } // namespace } // namespace xls::dslx