formatter.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "toolchain/sem_ir/formatter.h"
  5. #include "llvm/ADT/Sequence.h"
  6. #include "llvm/ADT/StringExtras.h"
  7. #include "llvm/Support/SaveAndRestore.h"
  8. #include "toolchain/lex/tokenized_buffer.h"
  9. #include "toolchain/parse/tree.h"
  10. namespace Carbon::SemIR {
  11. namespace {
  12. // Assigns names to nodes, blocks, and scopes in the Semantics IR.
  13. //
  14. // TODOs / future work ideas:
  15. // - Add a documentation file for the textual format and link to the
  16. // naming section here.
  17. // - Consider representing literals as just `literal` in the IR and using the
  18. // type to distinguish.
  19. class NodeNamer {
  20. public:
  21. // int32_t matches the input value size.
  22. // NOLINTNEXTLINE(performance-enum-size)
  23. enum class ScopeIndex : int32_t {
  24. None = -1,
  25. Package = 0,
  26. };
  27. static_assert(sizeof(ScopeIndex) == sizeof(FunctionId));
  28. NodeNamer(const Lex::TokenizedBuffer& tokenized_buffer,
  29. const Parse::Tree& parse_tree, const File& semantics_ir)
  30. : tokenized_buffer_(tokenized_buffer),
  31. parse_tree_(parse_tree),
  32. semantics_ir_(semantics_ir) {
  33. nodes.resize(semantics_ir.nodes_size());
  34. labels.resize(semantics_ir.node_blocks_size());
  35. scopes.resize(1 + semantics_ir.functions_size());
  36. // Build the package scope.
  37. GetScopeInfo(ScopeIndex::Package).name =
  38. globals.AddNameUnchecked("package");
  39. CollectNamesInBlock(ScopeIndex::Package, semantics_ir.top_node_block_id());
  40. // Build each function scope.
  41. for (int i : llvm::seq(semantics_ir.functions_size())) {
  42. auto fn_id = FunctionId(i);
  43. auto fn_scope = GetScopeFor(fn_id);
  44. const auto& fn = semantics_ir.GetFunction(fn_id);
  45. // TODO: Provide a location for the function for use as a
  46. // disambiguator.
  47. auto fn_loc = Parse::Node::Invalid;
  48. GetScopeInfo(fn_scope).name = globals.AllocateName(
  49. *this, fn_loc,
  50. fn.name_id.is_valid() ? semantics_ir.GetString(fn.name_id).str()
  51. : "");
  52. CollectNamesInBlock(fn_scope, fn.param_refs_id);
  53. if (fn.return_slot_id.is_valid()) {
  54. nodes[fn.return_slot_id.index] = {
  55. fn_scope,
  56. GetScopeInfo(fn_scope).nodes.AllocateName(
  57. *this, semantics_ir.GetNode(fn.return_slot_id).parse_node(),
  58. "return")};
  59. }
  60. if (!fn.body_block_ids.empty()) {
  61. AddBlockLabel(fn_scope, fn.body_block_ids.front(), "entry", fn_loc);
  62. }
  63. for (auto block_id : fn.body_block_ids) {
  64. CollectNamesInBlock(fn_scope, block_id);
  65. }
  66. for (auto block_id : fn.body_block_ids) {
  67. AddBlockLabel(fn_scope, block_id);
  68. }
  69. }
  70. }
  71. // Returns the scope index corresponding to a function.
  72. auto GetScopeFor(FunctionId fn_id) -> ScopeIndex {
  73. return static_cast<ScopeIndex>(fn_id.index + 1);
  74. }
  75. // Returns the IR name to use for a function.
  76. auto GetNameFor(FunctionId fn_id) -> llvm::StringRef {
  77. if (!fn_id.is_valid()) {
  78. return "invalid";
  79. }
  80. return GetScopeInfo(GetScopeFor(fn_id)).name.str();
  81. }
  82. // Returns the IR name to use for a node, when referenced from a given scope.
  83. auto GetNameFor(ScopeIndex scope_idx, NodeId node_id) -> std::string {
  84. if (!node_id.is_valid()) {
  85. return "invalid";
  86. }
  87. // Check for a builtin.
  88. if (node_id.index < BuiltinKind::ValidCount) {
  89. return BuiltinKind::FromInt(node_id.index).label().str();
  90. }
  91. auto& [node_scope, node_name] = nodes[node_id.index];
  92. if (!node_name) {
  93. // This should not happen in valid IR.
  94. return "<unexpected noderef " + llvm::itostr(node_id.index) + ">";
  95. }
  96. if (node_scope == scope_idx) {
  97. return node_name.str().str();
  98. }
  99. return (GetScopeInfo(node_scope).name.str() + "." + node_name.str()).str();
  100. }
  101. // Returns the IR name to use for a label, when referenced from a given scope.
  102. auto GetLabelFor(ScopeIndex scope_idx, NodeBlockId block_id) -> std::string {
  103. if (!block_id.is_valid()) {
  104. return "!invalid";
  105. }
  106. auto& [label_scope, label_name] = labels[block_id.index];
  107. if (!label_name) {
  108. // This should not happen in valid IR.
  109. return "<unexpected nodeblockref " + llvm::itostr(block_id.index) + ">";
  110. }
  111. if (label_scope == scope_idx) {
  112. return label_name.str().str();
  113. }
  114. return (GetScopeInfo(label_scope).name.str() + "." + label_name.str())
  115. .str();
  116. }
  117. private:
  118. // A space in which unique names can be allocated.
  119. struct Namespace {
  120. // A result of a name lookup.
  121. struct NameResult;
  122. // A name in a namespace, which might be redirected to refer to another name
  123. // for disambiguation purposes.
  124. class Name {
  125. public:
  126. Name() : value_(nullptr) {}
  127. explicit Name(llvm::StringMapIterator<NameResult> it) : value_(&*it) {}
  128. explicit operator bool() const { return value_; }
  129. auto str() const -> llvm::StringRef {
  130. llvm::StringMapEntry<NameResult>* value = value_;
  131. CARBON_CHECK(value) << "cannot print a null name";
  132. while (value->second.ambiguous && value->second.fallback) {
  133. value = value->second.fallback.value_;
  134. }
  135. return value->first();
  136. }
  137. auto SetFallback(Name name) -> void { value_->second.fallback = name; }
  138. auto SetAmbiguous() -> void { value_->second.ambiguous = true; }
  139. private:
  140. llvm::StringMapEntry<NameResult>* value_;
  141. };
  142. struct NameResult {
  143. bool ambiguous = false;
  144. Name fallback = Name();
  145. };
  146. llvm::StringRef prefix;
  147. llvm::StringMap<NameResult> allocated = {};
  148. int unnamed_count = 0;
  149. auto AddNameUnchecked(llvm::StringRef name) -> Name {
  150. return Name(allocated.insert({name, NameResult()}).first);
  151. }
  152. auto AllocateName(const NodeNamer& namer, Parse::Node node,
  153. std::string name = "") -> Name {
  154. // The best (shortest) name for this node so far, and the current name
  155. // for it.
  156. Name best;
  157. Name current;
  158. // Add `name` as a name for this entity.
  159. auto add_name = [&](bool mark_ambiguous = true) {
  160. auto [it, added] = allocated.insert({name, NameResult()});
  161. Name new_name = Name(it);
  162. if (!added) {
  163. if (mark_ambiguous) {
  164. // This name was allocated for a different node. Mark it as
  165. // ambiguous and keep looking for a name for this node.
  166. new_name.SetAmbiguous();
  167. }
  168. } else {
  169. if (!best) {
  170. best = new_name;
  171. } else {
  172. CARBON_CHECK(current);
  173. current.SetFallback(new_name);
  174. }
  175. current = new_name;
  176. }
  177. return added;
  178. };
  179. // All names start with the prefix.
  180. name.insert(0, prefix);
  181. // Use the given name if it's available and not just the prefix.
  182. if (name.size() > prefix.size()) {
  183. add_name();
  184. }
  185. // Append location information to try to disambiguate.
  186. if (node.is_valid()) {
  187. auto token = namer.parse_tree_.node_token(node);
  188. llvm::raw_string_ostream(name)
  189. << ".loc" << namer.tokenized_buffer_.GetLineNumber(token);
  190. add_name();
  191. llvm::raw_string_ostream(name)
  192. << "_" << namer.tokenized_buffer_.GetColumnNumber(token);
  193. add_name();
  194. }
  195. // Append numbers until we find an available name.
  196. name += ".";
  197. auto name_size_without_counter = name.size();
  198. for (int counter = 1;; ++counter) {
  199. name.resize(name_size_without_counter);
  200. llvm::raw_string_ostream(name) << counter;
  201. if (add_name(/*mark_ambiguous=*/false)) {
  202. return best;
  203. }
  204. }
  205. }
  206. };
  207. // A named scope that contains named entities.
  208. struct Scope {
  209. Namespace::Name name;
  210. Namespace nodes = {.prefix = "%"};
  211. Namespace labels = {.prefix = "!"};
  212. };
  213. auto GetScopeInfo(ScopeIndex scope_idx) -> Scope& {
  214. return scopes[static_cast<int>(scope_idx)];
  215. }
  216. auto AddBlockLabel(ScopeIndex scope_idx, NodeBlockId block_id,
  217. std::string name = "",
  218. Parse::Node parse_node = Parse::Node::Invalid) -> void {
  219. if (!block_id.is_valid() || labels[block_id.index].second) {
  220. return;
  221. }
  222. if (parse_node == Parse::Node::Invalid) {
  223. if (const auto& block = semantics_ir_.GetNodeBlock(block_id);
  224. !block.empty()) {
  225. parse_node = semantics_ir_.GetNode(block.front()).parse_node();
  226. }
  227. }
  228. labels[block_id.index] = {scope_idx,
  229. GetScopeInfo(scope_idx).labels.AllocateName(
  230. *this, parse_node, std::move(name))};
  231. }
  232. // Finds and adds a suitable block label for the given semantics node that
  233. // represents some kind of branch.
  234. auto AddBlockLabel(ScopeIndex scope_idx, NodeBlockId block_id, Node node)
  235. -> void {
  236. llvm::StringRef name;
  237. switch (parse_tree_.node_kind(node.parse_node())) {
  238. case Parse::NodeKind::IfExpressionIf:
  239. switch (node.kind()) {
  240. case NodeKind::BranchIf:
  241. name = "if.expr.then";
  242. break;
  243. case NodeKind::Branch:
  244. name = "if.expr.else";
  245. break;
  246. case NodeKind::BranchWithArg:
  247. name = "if.expr.result";
  248. break;
  249. default:
  250. break;
  251. }
  252. break;
  253. case Parse::NodeKind::IfCondition:
  254. switch (node.kind()) {
  255. case NodeKind::BranchIf:
  256. name = "if.then";
  257. break;
  258. case NodeKind::Branch:
  259. name = "if.else";
  260. break;
  261. default:
  262. break;
  263. }
  264. break;
  265. case Parse::NodeKind::IfStatement:
  266. name = "if.done";
  267. break;
  268. case Parse::NodeKind::ShortCircuitOperand: {
  269. bool is_rhs = node.kind() == NodeKind::BranchIf;
  270. bool is_and = tokenized_buffer_.GetKind(parse_tree_.node_token(
  271. node.parse_node())) == Lex::TokenKind::And;
  272. name = is_and ? (is_rhs ? "and.rhs" : "and.result")
  273. : (is_rhs ? "or.rhs" : "or.result");
  274. break;
  275. }
  276. default:
  277. break;
  278. }
  279. AddBlockLabel(scope_idx, block_id, name.str(), node.parse_node());
  280. }
  281. auto CollectNamesInBlock(ScopeIndex scope_idx, NodeBlockId block_id) -> void {
  282. if (!block_id.is_valid()) {
  283. return;
  284. }
  285. Scope& scope = GetScopeInfo(scope_idx);
  286. // Use bound names where available. Otherwise, assign a backup name.
  287. for (auto node_id : semantics_ir_.GetNodeBlock(block_id)) {
  288. if (!node_id.is_valid()) {
  289. continue;
  290. }
  291. auto node = semantics_ir_.GetNode(node_id);
  292. switch (node.kind()) {
  293. case NodeKind::Branch: {
  294. auto dest_id = node.GetAsBranch();
  295. AddBlockLabel(scope_idx, dest_id, node);
  296. break;
  297. }
  298. case NodeKind::BranchIf: {
  299. auto [dest_id, cond_id] = node.GetAsBranchIf();
  300. AddBlockLabel(scope_idx, dest_id, node);
  301. break;
  302. }
  303. case NodeKind::BranchWithArg: {
  304. auto [dest_id, arg_id] = node.GetAsBranchWithArg();
  305. AddBlockLabel(scope_idx, dest_id, node);
  306. break;
  307. }
  308. case NodeKind::Parameter: {
  309. auto name_id = node.GetAsParameter();
  310. nodes[node_id.index] = {
  311. scope_idx,
  312. scope.nodes.AllocateName(*this, node.parse_node(),
  313. semantics_ir_.GetString(name_id).str())};
  314. break;
  315. }
  316. case NodeKind::VarStorage: {
  317. // TODO: Eventually this name will be optional, and we'll want to
  318. // provide something like `var` as a default. However, that's not
  319. // possible right now so cannot be tested.
  320. auto name_id = node.GetAsVarStorage();
  321. nodes[node_id.index] = {
  322. scope_idx,
  323. scope.nodes.AllocateName(*this, node.parse_node(),
  324. semantics_ir_.GetString(name_id).str())};
  325. break;
  326. }
  327. default: {
  328. // Sequentially number all remaining values.
  329. if (node.kind().value_kind() != NodeValueKind::None) {
  330. nodes[node_id.index] = {
  331. scope_idx, scope.nodes.AllocateName(*this, node.parse_node())};
  332. }
  333. break;
  334. }
  335. }
  336. }
  337. }
  338. const Lex::TokenizedBuffer& tokenized_buffer_;
  339. const Parse::Tree& parse_tree_;
  340. const File& semantics_ir_;
  341. Namespace globals = {.prefix = "@"};
  342. std::vector<std::pair<ScopeIndex, Namespace::Name>> nodes;
  343. std::vector<std::pair<ScopeIndex, Namespace::Name>> labels;
  344. std::vector<Scope> scopes;
  345. };
  346. } // namespace
  347. // Formatter for printing textual Semantics IR.
  348. class Formatter {
  349. public:
  350. explicit Formatter(const Lex::TokenizedBuffer& tokenized_buffer,
  351. const Parse::Tree& parse_tree, const File& semantics_ir,
  352. llvm::raw_ostream& out)
  353. : semantics_ir_(semantics_ir),
  354. out_(out),
  355. node_namer_(tokenized_buffer, parse_tree, semantics_ir) {}
  356. auto Format() -> void {
  357. // TODO: Include information from the package declaration, once we fully
  358. // support it.
  359. out_ << "package {\n";
  360. // TODO: Handle the case where there are multiple top-level node blocks.
  361. // For example, there may be branching in the initializer of a global or a
  362. // type expression.
  363. if (auto block_id = semantics_ir_.top_node_block_id();
  364. block_id.is_valid()) {
  365. llvm::SaveAndRestore package_scope(scope_,
  366. NodeNamer::ScopeIndex::Package);
  367. FormatCodeBlock(block_id);
  368. }
  369. out_ << "}\n";
  370. for (int i : llvm::seq(semantics_ir_.functions_size())) {
  371. FormatFunction(FunctionId(i));
  372. }
  373. }
  374. auto FormatFunction(FunctionId id) -> void {
  375. const Function& fn = semantics_ir_.GetFunction(id);
  376. out_ << "\nfn ";
  377. FormatFunctionName(id);
  378. out_ << "(";
  379. llvm::SaveAndRestore function_scope(scope_, node_namer_.GetScopeFor(id));
  380. llvm::ListSeparator sep;
  381. for (const NodeId param_id : semantics_ir_.GetNodeBlock(fn.param_refs_id)) {
  382. out_ << sep;
  383. if (!param_id.is_valid()) {
  384. out_ << "invalid";
  385. continue;
  386. }
  387. FormatNodeName(param_id);
  388. out_ << ": ";
  389. FormatType(semantics_ir_.GetNode(param_id).type_id());
  390. }
  391. out_ << ")";
  392. if (fn.return_type_id.is_valid()) {
  393. out_ << " -> ";
  394. if (fn.return_slot_id.is_valid()) {
  395. FormatNodeName(fn.return_slot_id);
  396. out_ << ": ";
  397. }
  398. FormatType(fn.return_type_id);
  399. }
  400. if (!fn.body_block_ids.empty()) {
  401. out_ << " {";
  402. for (auto block_id : fn.body_block_ids) {
  403. out_ << "\n";
  404. FormatLabel(block_id);
  405. out_ << ":\n";
  406. FormatCodeBlock(block_id);
  407. }
  408. out_ << "}\n";
  409. } else {
  410. out_ << ";\n";
  411. }
  412. }
  413. auto FormatCodeBlock(NodeBlockId block_id) -> void {
  414. if (!block_id.is_valid()) {
  415. return;
  416. }
  417. for (const NodeId node_id : semantics_ir_.GetNodeBlock(block_id)) {
  418. FormatInstruction(node_id);
  419. }
  420. }
  421. auto FormatInstruction(NodeId node_id) -> void {
  422. if (!node_id.is_valid()) {
  423. out_ << " " << NodeKind::Invalid.ir_name() << "\n";
  424. return;
  425. }
  426. FormatInstruction(node_id, semantics_ir_.GetNode(node_id));
  427. }
  428. auto FormatInstruction(NodeId node_id, Node node) -> void {
  429. // clang warns on unhandled enum values; clang-tidy is incorrect here.
  430. // NOLINTNEXTLINE(bugprone-switch-missing-default-case)
  431. switch (node.kind()) {
  432. #define CARBON_SEMANTICS_NODE_KIND(Name) \
  433. case NodeKind::Name: \
  434. FormatInstruction<Node::Name>(node_id, node); \
  435. break;
  436. #include "toolchain/sem_ir/node_kind.def"
  437. }
  438. }
  439. template <typename Kind>
  440. auto FormatInstruction(NodeId node_id, Node node) -> void {
  441. out_ << " ";
  442. FormatInstructionLHS(node_id, node);
  443. out_ << node.kind().ir_name();
  444. FormatInstructionRHS<Kind>(node);
  445. out_ << "\n";
  446. }
  447. auto FormatInstructionLHS(NodeId node_id, Node node) -> void {
  448. switch (node.kind().value_kind()) {
  449. case NodeValueKind::Typed:
  450. FormatNodeName(node_id);
  451. out_ << ": ";
  452. switch (GetExpressionCategory(semantics_ir_, node_id)) {
  453. case ExpressionCategory::NotExpression:
  454. case ExpressionCategory::Value:
  455. break;
  456. case ExpressionCategory::DurableReference:
  457. case ExpressionCategory::EphemeralReference:
  458. out_ << "ref ";
  459. break;
  460. case ExpressionCategory::Initializing:
  461. out_ << "init ";
  462. break;
  463. }
  464. FormatType(node.type_id());
  465. out_ << " = ";
  466. break;
  467. case NodeValueKind::Untyped:
  468. FormatNodeName(node_id);
  469. out_ << " = ";
  470. break;
  471. case NodeValueKind::None:
  472. break;
  473. }
  474. }
  475. template <typename Kind>
  476. auto FormatInstructionRHS(Node node) -> void {
  477. // By default, an instruction has a comma-separated argument list.
  478. FormatArgs(Kind::Get(node));
  479. }
  480. template <>
  481. auto FormatInstructionRHS<Node::BlockArg>(Node node) -> void {
  482. out_ << " ";
  483. FormatLabel(node.GetAsBlockArg());
  484. }
  485. template <>
  486. auto FormatInstruction<Node::BranchIf>(NodeId /*node_id*/, Node node)
  487. -> void {
  488. if (!in_terminator_sequence) {
  489. out_ << " ";
  490. }
  491. auto [label_id, cond_id] = node.GetAsBranchIf();
  492. out_ << "if ";
  493. FormatNodeName(cond_id);
  494. out_ << " " << NodeKind::Branch.ir_name() << " ";
  495. FormatLabel(label_id);
  496. out_ << " else ";
  497. in_terminator_sequence = true;
  498. }
  499. template <>
  500. auto FormatInstruction<Node::BranchWithArg>(NodeId /*node_id*/, Node node)
  501. -> void {
  502. if (!in_terminator_sequence) {
  503. out_ << " ";
  504. }
  505. auto [label_id, arg_id] = node.GetAsBranchWithArg();
  506. out_ << NodeKind::BranchWithArg.ir_name() << " ";
  507. FormatLabel(label_id);
  508. out_ << "(";
  509. FormatNodeName(arg_id);
  510. out_ << ")\n";
  511. in_terminator_sequence = false;
  512. }
  513. template <>
  514. auto FormatInstruction<Node::Branch>(NodeId /*node_id*/, Node node) -> void {
  515. if (!in_terminator_sequence) {
  516. out_ << " ";
  517. }
  518. out_ << NodeKind::Branch.ir_name() << " ";
  519. FormatLabel(node.GetAsBranch());
  520. out_ << "\n";
  521. in_terminator_sequence = false;
  522. }
  523. template <>
  524. auto FormatInstructionRHS<Node::Call>(Node node) -> void {
  525. out_ << " ";
  526. auto [args_id, callee_id] = node.GetAsCall();
  527. FormatArg(callee_id);
  528. llvm::ArrayRef<NodeId> args = semantics_ir_.GetNodeBlock(args_id);
  529. bool has_return_slot =
  530. semantics_ir_.GetFunction(callee_id).return_slot_id.is_valid();
  531. NodeId return_slot_id = NodeId::Invalid;
  532. if (has_return_slot) {
  533. return_slot_id = args.back();
  534. args = args.drop_back();
  535. }
  536. llvm::ListSeparator sep;
  537. out_ << '(';
  538. for (auto node_id : args) {
  539. out_ << sep;
  540. FormatArg(node_id);
  541. }
  542. out_ << ')';
  543. if (has_return_slot) {
  544. out_ << " to ";
  545. FormatArg(return_slot_id);
  546. }
  547. }
  548. template <>
  549. auto FormatInstructionRHS<Node::CrossReference>(Node node) -> void {
  550. // TODO: Figure out a way to make this meaningful. We'll need some way to
  551. // name cross-reference IRs, perhaps by the node ID of the import?
  552. auto [xref_id, node_id] = node.GetAsCrossReference();
  553. out_ << " " << xref_id << "." << node_id;
  554. }
  555. // StructTypeFields are formatted as part of their StructType.
  556. template <>
  557. auto FormatInstruction<Node::StructTypeField>(NodeId /*node_id*/,
  558. Node /*node*/) -> void {}
  559. template <>
  560. auto FormatInstructionRHS<Node::StructType>(Node node) -> void {
  561. out_ << " {";
  562. llvm::ListSeparator sep;
  563. for (auto field_id : semantics_ir_.GetNodeBlock(node.GetAsStructType())) {
  564. out_ << sep << ".";
  565. auto [field_name_id, field_type_id] =
  566. semantics_ir_.GetNode(field_id).GetAsStructTypeField();
  567. FormatString(field_name_id);
  568. out_ << ": ";
  569. FormatType(field_type_id);
  570. }
  571. out_ << "}";
  572. }
  573. auto FormatArgs(Node::NoArgs /*unused*/) -> void {}
  574. template <typename Arg1>
  575. auto FormatArgs(Arg1 arg) -> void {
  576. out_ << ' ';
  577. FormatArg(arg);
  578. }
  579. template <typename Arg1, typename Arg2>
  580. auto FormatArgs(std::pair<Arg1, Arg2> args) -> void {
  581. out_ << ' ';
  582. FormatArg(args.first);
  583. out_ << ",";
  584. FormatArgs(args.second);
  585. }
  586. auto FormatArg(BoolValue v) -> void { out_ << v; }
  587. auto FormatArg(BuiltinKind kind) -> void { out_ << kind.label(); }
  588. auto FormatArg(FunctionId id) -> void { FormatFunctionName(id); }
  589. auto FormatArg(IntegerLiteralId id) -> void {
  590. semantics_ir_.GetIntegerLiteral(id).print(out_, /*isSigned=*/false);
  591. }
  592. auto FormatArg(MemberIndex index) -> void { out_ << index; }
  593. // TODO: Should we be printing scopes inline, or should we have a separate
  594. // step to print them like we do for functions?
  595. auto FormatArg(NameScopeId id) -> void {
  596. // Name scopes aren't kept in any particular order. Sort the entries before
  597. // we print them for stability and consistency.
  598. std::vector<std::pair<NodeId, StringId>> entries;
  599. for (auto [name_id, node_id] : semantics_ir_.GetNameScope(id)) {
  600. entries.push_back({node_id, name_id});
  601. }
  602. llvm::sort(entries,
  603. [](auto a, auto b) { return a.first.index < b.first.index; });
  604. out_ << '{';
  605. llvm::ListSeparator sep;
  606. for (auto [node_id, name_id] : entries) {
  607. out_ << sep << ".";
  608. FormatString(name_id);
  609. out_ << " = ";
  610. FormatNodeName(node_id);
  611. }
  612. out_ << '}';
  613. }
  614. auto FormatArg(NodeId id) -> void { FormatNodeName(id); }
  615. auto FormatArg(NodeBlockId id) -> void {
  616. out_ << '(';
  617. llvm::ListSeparator sep;
  618. for (auto node_id : semantics_ir_.GetNodeBlock(id)) {
  619. out_ << sep;
  620. FormatArg(node_id);
  621. }
  622. out_ << ')';
  623. }
  624. auto FormatArg(RealLiteralId id) -> void {
  625. // TODO: Format with a `.` when the exponent is near zero.
  626. const auto& real = semantics_ir_.GetRealLiteral(id);
  627. out_ << real.mantissa << (real.is_decimal ? 'e' : 'p') << real.exponent;
  628. }
  629. auto FormatArg(StringId id) -> void {
  630. out_ << '"';
  631. out_.write_escaped(semantics_ir_.GetString(id), /*UseHexEscapes=*/true);
  632. out_ << '"';
  633. }
  634. auto FormatArg(TypeId id) -> void { FormatType(id); }
  635. auto FormatArg(TypeBlockId id) -> void {
  636. out_ << '(';
  637. llvm::ListSeparator sep;
  638. for (auto type_id : semantics_ir_.GetTypeBlock(id)) {
  639. out_ << sep;
  640. FormatArg(type_id);
  641. }
  642. out_ << ')';
  643. }
  644. auto FormatNodeName(NodeId id) -> void {
  645. out_ << node_namer_.GetNameFor(scope_, id);
  646. }
  647. auto FormatLabel(NodeBlockId id) -> void {
  648. out_ << node_namer_.GetLabelFor(scope_, id);
  649. }
  650. auto FormatString(StringId id) -> void {
  651. out_ << semantics_ir_.GetString(id);
  652. }
  653. auto FormatFunctionName(FunctionId id) -> void {
  654. out_ << node_namer_.GetNameFor(id);
  655. }
  656. auto FormatType(TypeId id) -> void {
  657. if (!id.is_valid()) {
  658. out_ << "invalid";
  659. } else {
  660. out_ << semantics_ir_.StringifyType(id, /*in_type_context=*/true);
  661. }
  662. }
  663. private:
  664. const File& semantics_ir_;
  665. llvm::raw_ostream& out_;
  666. NodeNamer node_namer_;
  667. NodeNamer::ScopeIndex scope_ = NodeNamer::ScopeIndex::None;
  668. bool in_terminator_sequence = false;
  669. };
  670. auto FormatFile(const Lex::TokenizedBuffer& tokenized_buffer,
  671. const Parse::Tree& parse_tree, const File& semantics_ir,
  672. llvm::raw_ostream& out) -> void {
  673. Formatter(tokenized_buffer, parse_tree, semantics_ir, out).Format();
  674. }
  675. } // namespace Carbon::SemIR