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