diff --git a/common/ostream.h b/common/ostream.h index aa82f7436589..b01d393f2afb 100644 --- a/common/ostream.h +++ b/common/ostream.h @@ -6,6 +6,7 @@ #define CARBON_COMMON_OSTREAM_H_ #include +#include #include "llvm/Support/raw_os_ostream.h" // Libraries should include this header instead of raw_ostream. @@ -50,6 +51,15 @@ class Printable { } }; +// Returns the result of printing the value. +template +inline auto PrintToString(const T& val) -> std::string { + std::string str; + llvm::raw_string_ostream stream(str); + stream << val; + return str; +} + } // namespace Carbon namespace llvm { diff --git a/toolchain/base/BUILD b/toolchain/base/BUILD index 34ed65e62c7f..dbd3a85d4eb1 100644 --- a/toolchain/base/BUILD +++ b/toolchain/base/BUILD @@ -28,6 +28,7 @@ cc_library( hdrs = ["value_store.h"], deps = [ ":index_base", + ":yaml", "//common:check", "//common:ostream", "@llvm-project//llvm:Support", @@ -46,3 +47,13 @@ cc_test( "@com_google_googletest//:gtest", ], ) + +cc_library( + name = "yaml", + hdrs = ["yaml.h"], + deps = [ + "//common:check", + "//common:ostream", + "@llvm-project//llvm:Support", + ], +) diff --git a/toolchain/base/value_store.h b/toolchain/base/value_store.h index 2572af2a953f..56621951db54 100644 --- a/toolchain/base/value_store.h +++ b/toolchain/base/value_store.h @@ -12,10 +12,12 @@ #include "llvm/ADT/APInt.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLFunctionalExtras.h" +#include "llvm/ADT/Sequence.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/YAMLParser.h" #include "toolchain/base/index_base.h" +#include "toolchain/base/yaml.h" namespace Carbon { @@ -86,73 +88,14 @@ namespace Internal { // Used as a parent class for non-printable types. This is just for // std::conditional, not as an API. class ValueStoreNotPrintable {}; - -// Provides YAML printing of a value. -template -inline auto PrintValue(llvm::raw_ostream& out, const ValueT& val) { - out << val; -}; -inline auto PrintValue(llvm::raw_ostream& out, const llvm::APInt& val) { - val.print(out, /*isSigned=*/false); -}; -inline auto PrintValue(llvm::raw_ostream& out, const llvm::StringRef& val) { - out << "\"" << llvm::yaml::escape(val) << "\""; -}; - -struct DefaultPrinter { - template - void operator()(llvm::raw_ostream& out, const ValueT& value) { - PrintValue(out, value); - } -}; - } // namespace Internal -// Provides YAML printing of a list. The first line indent applies even if there -// is no label, in which case it applies to the first element. -template -inline auto PrintValueRange( - llvm::raw_ostream& out, llvm::iterator_range range, - std::optional label, int first_line_indent, - int later_indent, bool trailing_newline, - llvm::function_ref print = - Internal::DefaultPrinter()) { - out.indent(first_line_indent); - if (label) { - out << *label << ":"; - if (range.empty()) { - // Add a space between the `:` and the `[]` printed below. - out << " "; - } else { - out << "\n"; - out.indent(later_indent); - } - } - if (range.empty()) { - out << "[]"; - if (trailing_newline) { - out << "\n"; - } - return; - } - std::string sep_str = "\n"; - sep_str.append(later_indent, ' '); - llvm::ListSeparator sep(sep_str); - for (const auto& val : range) { - out << sep << "- "; - print(out, val); - } - if (trailing_newline) { - out << "\n"; - } -} - // A simple wrapper for accumulating values, providing IDs to later retrieve the // value. This does not do deduplication. template class ValueStore : public std::conditional, ValueT>, - Printable>, + Yaml::Printable>, Internal::ValueStoreNotPrintable> { public: using PrintFn = @@ -189,17 +132,13 @@ class ValueStore auto Reserve(size_t size) -> void { values_.reserve(size); } // These are to support printable structures, and are not guaranteed. - auto Print(llvm::raw_ostream& out) const -> void { - Print(out, std::nullopt, 0, 0); - } - auto Print(llvm::raw_ostream& out, std::optional label, - int first_line_indent, int later_indent, - // This decays so that `const llvm::APInt` printing catches the - // specialization. - PrintFn print = Internal::DefaultPrinter()) const -> void { - PrintValueRange(out, llvm::iterator_range(values_), label, - first_line_indent, later_indent, /*trailing_newline=*/true, - print); + auto OutputYaml() const -> Yaml::OutputMapping { + return Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) { + for (auto i : llvm::seq(values_.size())) { + auto id = IdT(i); + map.Add(PrintToString(id), Yaml::OutputScalar(Get(id))); + } + }); } auto array_ref() const -> llvm::ArrayRef { return values_; } @@ -212,7 +151,7 @@ class ValueStore // Storage for StringRefs. The caller is responsible for ensuring storage is // allocated. template <> -class ValueStore : public Printable> { +class ValueStore : public Yaml::Printable> { public: using PrintFn = llvm::function_ref; @@ -234,15 +173,12 @@ class ValueStore : public Printable> { return values_[id.index]; } - auto Print(llvm::raw_ostream& out) const -> void { - Print(out, std::nullopt, 0, 0); - } - auto Print(llvm::raw_ostream& out, std::optional label, - int first_line_indent, int later_indent, - PrintFn print = Internal::DefaultPrinter()) const -> void { - PrintValueRange(out, llvm::iterator_range(values_), label, - first_line_indent, later_indent, /*trailing_newline=*/true, - print); + auto OutputYaml() const -> Yaml::OutputMapping { + return Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) { + for (auto [i, val] : llvm::enumerate(values_)) { + map.Add(PrintToString(StringId(i)), val); + } + }); } private: @@ -252,7 +188,7 @@ class ValueStore : public Printable> { // Stores that will be used across compiler steps. This is provided mainly so // that they don't need to be passed separately. -class SharedValueStores : public Printable { +class SharedValueStores : public Yaml::Printable { public: auto integers() -> ValueStore& { return integers_; } auto integers() const -> const ValueStore& { return integers_; } @@ -261,12 +197,15 @@ class SharedValueStores : public Printable { auto strings() -> ValueStore& { return strings_; } auto strings() const -> const ValueStore& { return strings_; } - auto Print(llvm::raw_ostream& out) const -> void { - out << "shared_values:\n" - << " - "; - integers_.Print(out, "integers", 0, 6); - reals_.Print(out, "reals", 4, 6); - strings_.Print(out, "strings", 4, 6); + auto OutputYaml() const -> Yaml::OutputMapping { + return Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) { + map.Add("shared_values", + Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) { + map.Add("integers", integers_.OutputYaml()); + map.Add("reals", reals_.OutputYaml()); + map.Add("strings", strings_.OutputYaml()); + })); + }); } private: diff --git a/toolchain/base/value_store_test.cpp b/toolchain/base/value_store_test.cpp index d248ae7d3273..c0bb41c4011f 100644 --- a/toolchain/base/value_store_test.cpp +++ b/toolchain/base/value_store_test.cpp @@ -78,14 +78,14 @@ TEST(ValueStore, String) { EXPECT_THAT(value_stores.strings().Add(b), Eq(b_id)); } -auto MatchSharedValues(testing::Matcher integers, - testing::Matcher reals, - testing::Matcher strings) -> auto { +auto MatchSharedValues(testing::Matcher integers, + testing::Matcher reals, + testing::Matcher strings) -> auto { return Yaml::IsYaml(Yaml::Sequence(ElementsAre(Yaml::Mapping(ElementsAre(Pair( - "shared_values", Yaml::Sequence(ElementsAre(Yaml::Mapping(ElementsAre( - Pair("integers", Yaml::Sequence(integers)), - Pair("reals", Yaml::Sequence(reals)), - Pair("strings", Yaml::Sequence(strings)))))))))))); + "shared_values", + Yaml::Mapping(ElementsAre(Pair("integers", Yaml::Mapping(integers)), + Pair("reals", Yaml::Mapping(reals)), + Pair("strings", Yaml::Mapping(strings)))))))))); } TEST(ValueStore, PrintEmpty) { @@ -106,10 +106,11 @@ TEST(ValueStore, PrintVals) { TestRawOstream out; value_stores.Print(out); - EXPECT_THAT(Yaml::Value::FromText(out.TakeStr()), - MatchSharedValues(ElementsAre(Yaml::Scalar("8")), - ElementsAre(Yaml::Scalar("8*10^8")), - ElementsAre(Yaml::Scalar("foo'\"baz")))); + EXPECT_THAT( + Yaml::Value::FromText(out.TakeStr()), + MatchSharedValues(ElementsAre(Pair("int0", Yaml::Scalar("8"))), + ElementsAre(Pair("real0", Yaml::Scalar("8*10^8"))), + ElementsAre(Pair("str0", Yaml::Scalar("foo'\"baz"))))); } } // namespace diff --git a/toolchain/base/yaml.h b/toolchain/base/yaml.h new file mode 100644 index 000000000000..86496836a4d9 --- /dev/null +++ b/toolchain/base/yaml.h @@ -0,0 +1,115 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef CARBON_TOOLCHAIN_BASE_YAML_H_ +#define CARBON_TOOLCHAIN_BASE_YAML_H_ + +#include "common/check.h" +#include "common/ostream.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/YAMLTraits.h" + +// This file provides adapters for outputting YAML using llvm::yaml's APIs. It +// only supports output, not input. However, it addresses the mix of const and +// non-const expectations of the llvm::yaml that make it difficult to otherwise +// use the trait-based approach. + +namespace Carbon::Yaml { + +// Helper for printing YAML, to maintain a consistent configuration. +template +inline auto Print(llvm::raw_ostream& out, T yaml) -> void { + llvm::yaml::Output yout(out, /*Ctxt=*/nullptr, /*WrapColumn=*/80); + yout << yaml; +} + +// Similar to the standard Printable, but relies on OutputYaml for printing. +template +class Printable : public Carbon::Printable { + public: + auto Print(llvm::raw_ostream& out) const -> void { + Carbon::Yaml::Print(out, static_cast(this)->OutputYaml()); + } +}; + +// Adapts a function for outputting YAML as a scalar. This currently assumes no +// scalars passed through this should be quoted. +class OutputScalar { + public: + template + explicit OutputScalar(const T& val) + : output_([&](llvm::raw_ostream& out) -> void { out << val; }) {} + + explicit OutputScalar(const llvm::APInt& val) + : output_([&](llvm::raw_ostream& out) -> void { + // Carbon's plain APInt storage is typically unsigned. + val.print(out, /*isSigned=*/false); + }) {} + + explicit OutputScalar(std::function output) + : output_(std::move(output)) {} + + auto Output(llvm::raw_ostream& out) const -> void { output_(out); } + + private: + std::function output_; +}; + +// Adapts a function for outputting YAML as a mapping. +class OutputMapping { + public: + class Map { + public: + explicit Map(llvm::yaml::IO& io) : io_(io) {} + + // Maps a value. This mainly takes responsibility for copying the value, + // letting mapRequired take `&value`. + template + auto Add(llvm::StringRef key, T value) -> void { + io_.mapRequired(key.data(), value); + } + + private: + llvm::yaml::IO& io_; + }; + + explicit OutputMapping(std::function output) + : output_(std::move(output)) {} + + auto Output(llvm::yaml::IO& io) -> void { output_(Map(io)); } + + private: + std::function output_; +}; + +} // namespace Carbon::Yaml + +// Link OutputScalar to the llvm::yaml::IO API. +template <> +struct llvm::yaml::ScalarTraits { + static auto output(const Carbon::Yaml::OutputScalar& value, void* /*ctxt*/, + llvm::raw_ostream& out) -> void { + value.Output(out); + } + static auto input(StringRef /*scalar*/, void* /*ctxt*/, + Carbon::Yaml::OutputScalar& /*value*/) -> StringRef { + CARBON_FATAL() << "Input is unsupported."; + } + static auto mustQuote(StringRef /*value*/) -> QuotingType { + return QuotingType::None; + } +}; +static_assert(llvm::yaml::has_ScalarTraits::value); + +// Link OutputMapping to the llvm::yaml::IO API. +template <> +struct llvm::yaml::MappingTraits { + static auto mapping(IO& io, Carbon::Yaml::OutputMapping& mapping) -> void { + mapping.Output(io); + } +}; +static_assert(llvm::yaml::has_MappingTraits::value); + +#endif // CARBON_TOOLCHAIN_BASE_YAML_H_ diff --git a/toolchain/check/testdata/basics/builtin_nodes.carbon b/toolchain/check/testdata/basics/builtin_nodes.carbon index b6453ecb8c4e..2e12bacb06bc 100644 --- a/toolchain/check/testdata/basics/builtin_nodes.carbon +++ b/toolchain/check/testdata/basics/builtin_nodes.carbon @@ -6,21 +6,23 @@ // // AUTOUPDATE -// CHECK:STDOUT: - filename: builtin_nodes.carbon -// CHECK:STDOUT: sem_ir: -// CHECK:STDOUT: - cross_reference_irs_size: 1 -// CHECK:STDOUT: functions: [] -// CHECK:STDOUT: classes: [] -// CHECK:STDOUT: types: [] -// CHECK:STDOUT: type_blocks: [] -// CHECK:STDOUT: nodes: -// CHECK:STDOUT: - {kind: CrossReference, arg0: ir0, arg1: nodeTypeType, type: typeTypeType} -// CHECK:STDOUT: - {kind: CrossReference, arg0: ir0, arg1: nodeError, type: typeError} -// CHECK:STDOUT: - {kind: CrossReference, arg0: ir0, arg1: nodeBoolType, type: typeTypeType} -// CHECK:STDOUT: - {kind: CrossReference, arg0: ir0, arg1: nodeIntegerType, type: typeTypeType} -// CHECK:STDOUT: - {kind: CrossReference, arg0: ir0, arg1: nodeFloatingPointType, type: typeTypeType} -// CHECK:STDOUT: - {kind: CrossReference, arg0: ir0, arg1: nodeStringType, type: typeTypeType} -// CHECK:STDOUT: - {kind: CrossReference, arg0: ir0, arg1: nodeFunctionType, type: typeTypeType} -// CHECK:STDOUT: - {kind: CrossReference, arg0: ir0, arg1: nodeNamespaceType, type: typeTypeType} -// CHECK:STDOUT: node_blocks: -// CHECK:STDOUT: - [] +// CHECK:STDOUT: --- +// CHECK:STDOUT: filename: builtin_nodes.carbon +// CHECK:STDOUT: sem_ir: +// CHECK:STDOUT: cross_reference_irs_size: 1 +// CHECK:STDOUT: functions: {} +// CHECK:STDOUT: classes: {} +// CHECK:STDOUT: types: {} +// CHECK:STDOUT: type_blocks: {} +// CHECK:STDOUT: nodes: +// CHECK:STDOUT: nodeTypeType: {kind: CrossReference, arg0: ir0, arg1: nodeTypeType, type: typeTypeType} +// CHECK:STDOUT: nodeError: {kind: CrossReference, arg0: ir0, arg1: nodeError, type: typeError} +// CHECK:STDOUT: nodeBoolType: {kind: CrossReference, arg0: ir0, arg1: nodeBoolType, type: typeTypeType} +// CHECK:STDOUT: nodeIntegerType: {kind: CrossReference, arg0: ir0, arg1: nodeIntegerType, type: typeTypeType} +// CHECK:STDOUT: nodeFloatingPointType: {kind: CrossReference, arg0: ir0, arg1: nodeFloatingPointType, type: typeTypeType} +// CHECK:STDOUT: nodeStringType: {kind: CrossReference, arg0: ir0, arg1: nodeStringType, type: typeTypeType} +// CHECK:STDOUT: nodeFunctionType: {kind: CrossReference, arg0: ir0, arg1: nodeFunctionType, type: typeTypeType} +// CHECK:STDOUT: nodeNamespaceType: {kind: CrossReference, arg0: ir0, arg1: nodeNamespaceType, type: typeTypeType} +// CHECK:STDOUT: node_blocks: +// CHECK:STDOUT: block0: {} +// CHECK:STDOUT: ... diff --git a/toolchain/check/testdata/basics/multifile_raw_and_textual_ir.carbon b/toolchain/check/testdata/basics/multifile_raw_and_textual_ir.carbon index 3c706688b4e4..97fb51a9ade2 100644 --- a/toolchain/check/testdata/basics/multifile_raw_and_textual_ir.carbon +++ b/toolchain/check/testdata/basics/multifile_raw_and_textual_ir.carbon @@ -14,22 +14,26 @@ fn A() {} // --- b.carbon fn B() {} -// CHECK:STDOUT: - filename: a.carbon -// CHECK:STDOUT: sem_ir: -// CHECK:STDOUT: - cross_reference_irs_size: 1 -// CHECK:STDOUT: functions: -// CHECK:STDOUT: - {name: str0, param_refs: block0, body: [block1]} -// CHECK:STDOUT: classes: [] -// CHECK:STDOUT: types: -// CHECK:STDOUT: - {node: nodeFunctionType, value_rep: {kind: copy, type: type0}} -// CHECK:STDOUT: type_blocks: [] -// CHECK:STDOUT: nodes: -// CHECK:STDOUT: - {kind: FunctionDeclaration, arg0: function0, type: type0} -// CHECK:STDOUT: - {kind: Return} -// CHECK:STDOUT: node_blocks: -// CHECK:STDOUT: - [] -// CHECK:STDOUT: - - node+1 -// CHECK:STDOUT: - - node+0 +// CHECK:STDOUT: --- +// CHECK:STDOUT: filename: a.carbon +// CHECK:STDOUT: sem_ir: +// CHECK:STDOUT: cross_reference_irs_size: 1 +// CHECK:STDOUT: functions: +// CHECK:STDOUT: function0: {name: str0, param_refs: block0, body: [block1]} +// CHECK:STDOUT: classes: {} +// CHECK:STDOUT: types: +// CHECK:STDOUT: type0: {node: nodeFunctionType, value_rep: {kind: copy, type: type0}} +// CHECK:STDOUT: type_blocks: {} +// CHECK:STDOUT: nodes: +// CHECK:STDOUT: node+0: {kind: FunctionDeclaration, arg0: function0, type: type0} +// CHECK:STDOUT: node+1: {kind: Return} +// CHECK:STDOUT: node_blocks: +// CHECK:STDOUT: block0: {} +// CHECK:STDOUT: block1: +// CHECK:STDOUT: 0: node+1 +// CHECK:STDOUT: block2: +// CHECK:STDOUT: 0: node+0 +// CHECK:STDOUT: ... // CHECK:STDOUT: // CHECK:STDOUT: file "a.carbon" { // CHECK:STDOUT: %A: = fn_decl @A @@ -39,22 +43,26 @@ fn B() {} // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } -// CHECK:STDOUT: - filename: b.carbon -// CHECK:STDOUT: sem_ir: -// CHECK:STDOUT: - cross_reference_irs_size: 1 -// CHECK:STDOUT: functions: -// CHECK:STDOUT: - {name: str1, param_refs: block0, body: [block1]} -// CHECK:STDOUT: classes: [] -// CHECK:STDOUT: types: -// CHECK:STDOUT: - {node: nodeFunctionType, value_rep: {kind: copy, type: type0}} -// CHECK:STDOUT: type_blocks: [] -// CHECK:STDOUT: nodes: -// CHECK:STDOUT: - {kind: FunctionDeclaration, arg0: function0, type: type0} -// CHECK:STDOUT: - {kind: Return} -// CHECK:STDOUT: node_blocks: -// CHECK:STDOUT: - [] -// CHECK:STDOUT: - - node+1 -// CHECK:STDOUT: - - node+0 +// CHECK:STDOUT: --- +// CHECK:STDOUT: filename: b.carbon +// CHECK:STDOUT: sem_ir: +// CHECK:STDOUT: cross_reference_irs_size: 1 +// CHECK:STDOUT: functions: +// CHECK:STDOUT: function0: {name: str1, param_refs: block0, body: [block1]} +// CHECK:STDOUT: classes: {} +// CHECK:STDOUT: types: +// CHECK:STDOUT: type0: {node: nodeFunctionType, value_rep: {kind: copy, type: type0}} +// CHECK:STDOUT: type_blocks: {} +// CHECK:STDOUT: nodes: +// CHECK:STDOUT: node+0: {kind: FunctionDeclaration, arg0: function0, type: type0} +// CHECK:STDOUT: node+1: {kind: Return} +// CHECK:STDOUT: node_blocks: +// CHECK:STDOUT: block0: {} +// CHECK:STDOUT: block1: +// CHECK:STDOUT: 0: node+1 +// CHECK:STDOUT: block2: +// CHECK:STDOUT: 0: node+0 +// CHECK:STDOUT: ... // CHECK:STDOUT: // CHECK:STDOUT: file "b.carbon" { // CHECK:STDOUT: %B: = fn_decl @B diff --git a/toolchain/check/testdata/basics/multifile_raw_ir.carbon b/toolchain/check/testdata/basics/multifile_raw_ir.carbon index 19770a279ee7..85683bdda0ae 100644 --- a/toolchain/check/testdata/basics/multifile_raw_ir.carbon +++ b/toolchain/check/testdata/basics/multifile_raw_ir.carbon @@ -14,35 +14,43 @@ fn A() {} // --- b.carbon fn B() {} -// CHECK:STDOUT: - filename: a.carbon -// CHECK:STDOUT: sem_ir: -// CHECK:STDOUT: - cross_reference_irs_size: 1 -// CHECK:STDOUT: functions: -// CHECK:STDOUT: - {name: str0, param_refs: block0, body: [block1]} -// CHECK:STDOUT: classes: [] -// CHECK:STDOUT: types: -// CHECK:STDOUT: - {node: nodeFunctionType, value_rep: {kind: copy, type: type0}} -// CHECK:STDOUT: type_blocks: [] -// CHECK:STDOUT: nodes: -// CHECK:STDOUT: - {kind: FunctionDeclaration, arg0: function0, type: type0} -// CHECK:STDOUT: - {kind: Return} -// CHECK:STDOUT: node_blocks: -// CHECK:STDOUT: - [] -// CHECK:STDOUT: - - node+1 -// CHECK:STDOUT: - - node+0 -// CHECK:STDOUT: - filename: b.carbon -// CHECK:STDOUT: sem_ir: -// CHECK:STDOUT: - cross_reference_irs_size: 1 -// CHECK:STDOUT: functions: -// CHECK:STDOUT: - {name: str1, param_refs: block0, body: [block1]} -// CHECK:STDOUT: classes: [] -// CHECK:STDOUT: types: -// CHECK:STDOUT: - {node: nodeFunctionType, value_rep: {kind: copy, type: type0}} -// CHECK:STDOUT: type_blocks: [] -// CHECK:STDOUT: nodes: -// CHECK:STDOUT: - {kind: FunctionDeclaration, arg0: function0, type: type0} -// CHECK:STDOUT: - {kind: Return} -// CHECK:STDOUT: node_blocks: -// CHECK:STDOUT: - [] -// CHECK:STDOUT: - - node+1 -// CHECK:STDOUT: - - node+0 +// CHECK:STDOUT: --- +// CHECK:STDOUT: filename: a.carbon +// CHECK:STDOUT: sem_ir: +// CHECK:STDOUT: cross_reference_irs_size: 1 +// CHECK:STDOUT: functions: +// CHECK:STDOUT: function0: {name: str0, param_refs: block0, body: [block1]} +// CHECK:STDOUT: classes: {} +// CHECK:STDOUT: types: +// CHECK:STDOUT: type0: {node: nodeFunctionType, value_rep: {kind: copy, type: type0}} +// CHECK:STDOUT: type_blocks: {} +// CHECK:STDOUT: nodes: +// CHECK:STDOUT: node+0: {kind: FunctionDeclaration, arg0: function0, type: type0} +// CHECK:STDOUT: node+1: {kind: Return} +// CHECK:STDOUT: node_blocks: +// CHECK:STDOUT: block0: {} +// CHECK:STDOUT: block1: +// CHECK:STDOUT: 0: node+1 +// CHECK:STDOUT: block2: +// CHECK:STDOUT: 0: node+0 +// CHECK:STDOUT: ... +// CHECK:STDOUT: --- +// CHECK:STDOUT: filename: b.carbon +// CHECK:STDOUT: sem_ir: +// CHECK:STDOUT: cross_reference_irs_size: 1 +// CHECK:STDOUT: functions: +// CHECK:STDOUT: function0: {name: str1, param_refs: block0, body: [block1]} +// CHECK:STDOUT: classes: {} +// CHECK:STDOUT: types: +// CHECK:STDOUT: type0: {node: nodeFunctionType, value_rep: {kind: copy, type: type0}} +// CHECK:STDOUT: type_blocks: {} +// CHECK:STDOUT: nodes: +// CHECK:STDOUT: node+0: {kind: FunctionDeclaration, arg0: function0, type: type0} +// CHECK:STDOUT: node+1: {kind: Return} +// CHECK:STDOUT: node_blocks: +// CHECK:STDOUT: block0: {} +// CHECK:STDOUT: block1: +// CHECK:STDOUT: 0: node+1 +// CHECK:STDOUT: block2: +// CHECK:STDOUT: 0: node+0 +// CHECK:STDOUT: ... diff --git a/toolchain/check/testdata/basics/raw_and_textual_ir.carbon b/toolchain/check/testdata/basics/raw_and_textual_ir.carbon index d6bfbfdfa667..e24c3068a32f 100644 --- a/toolchain/check/testdata/basics/raw_and_textual_ir.carbon +++ b/toolchain/check/testdata/basics/raw_and_textual_ir.carbon @@ -12,70 +12,81 @@ fn Foo(n: i32) -> (i32, f64) { return (n + 2, 3.4); } -// CHECK:STDOUT: - filename: raw_and_textual_ir.carbon -// CHECK:STDOUT: sem_ir: -// CHECK:STDOUT: - cross_reference_irs_size: 1 -// CHECK:STDOUT: functions: -// CHECK:STDOUT: - {name: str0, param_refs: block1, return_type: type3, return_slot: node+4, body: [block4]} -// CHECK:STDOUT: classes: [] -// CHECK:STDOUT: types: -// CHECK:STDOUT: - {node: nodeIntegerType, value_rep: {kind: copy, type: type0}} -// CHECK:STDOUT: - {node: node+1, value_rep: {kind: unknown, type: type}} -// CHECK:STDOUT: - {node: nodeFloatingPointType, value_rep: {kind: copy, type: type2}} -// CHECK:STDOUT: - {node: node+3, value_rep: {kind: pointer, type: type4}} -// CHECK:STDOUT: - {node: node+5, value_rep: {kind: copy, type: type4}} -// CHECK:STDOUT: - {node: nodeFunctionType, value_rep: {kind: copy, type: type5}} -// CHECK:STDOUT: type_blocks: -// CHECK:STDOUT: - - typeTypeType -// CHECK:STDOUT: - typeTypeType -// CHECK:STDOUT: - - type0 -// CHECK:STDOUT: - type2 -// CHECK:STDOUT: nodes: -// CHECK:STDOUT: - {kind: Parameter, arg0: str1, type: type0} -// CHECK:STDOUT: - {kind: TupleType, arg0: typeBlock0, type: typeTypeType} -// CHECK:STDOUT: - {kind: TupleLiteral, arg0: block2, type: type1} -// CHECK:STDOUT: - {kind: TupleType, arg0: typeBlock1, type: typeTypeType} -// CHECK:STDOUT: - {kind: VarStorage, arg0: str2, type: type3} -// CHECK:STDOUT: - {kind: PointerType, arg0: type3, type: typeTypeType} -// CHECK:STDOUT: - {kind: FunctionDeclaration, arg0: function0, type: type5} -// CHECK:STDOUT: - {kind: NameReference, arg0: str1, arg1: node+0, type: type0} -// CHECK:STDOUT: - {kind: IntegerLiteral, arg0: int3, type: type0} -// CHECK:STDOUT: - {kind: BinaryOperatorAdd, arg0: node+7, arg1: node+8, type: type0} -// CHECK:STDOUT: - {kind: RealLiteral, arg0: real0, type: type2} -// CHECK:STDOUT: - {kind: TupleLiteral, arg0: block5, type: type3} -// CHECK:STDOUT: - {kind: TupleAccess, arg0: node+4, arg1: member0, type: type0} -// CHECK:STDOUT: - {kind: InitializeFrom, arg0: node+9, arg1: node+12, type: type0} -// CHECK:STDOUT: - {kind: TupleAccess, arg0: node+4, arg1: member1, type: type2} -// CHECK:STDOUT: - {kind: InitializeFrom, arg0: node+10, arg1: node+14, type: type2} -// CHECK:STDOUT: - {kind: TupleInit, arg0: node+11, arg1: block6, type: type3} -// CHECK:STDOUT: - {kind: ReturnExpression, arg0: node+16} -// CHECK:STDOUT: node_blocks: -// CHECK:STDOUT: - [] -// CHECK:STDOUT: - - node+0 -// CHECK:STDOUT: - - nodeIntegerType -// CHECK:STDOUT: - nodeFloatingPointType -// CHECK:STDOUT: - - node+0 -// CHECK:STDOUT: - node+1 -// CHECK:STDOUT: - node+2 -// CHECK:STDOUT: - node+3 -// CHECK:STDOUT: - node+4 -// CHECK:STDOUT: - - node+7 -// CHECK:STDOUT: - node+8 -// CHECK:STDOUT: - node+9 -// CHECK:STDOUT: - node+10 -// CHECK:STDOUT: - node+11 -// CHECK:STDOUT: - node+12 -// CHECK:STDOUT: - node+13 -// CHECK:STDOUT: - node+14 -// CHECK:STDOUT: - node+15 -// CHECK:STDOUT: - node+16 -// CHECK:STDOUT: - node+17 -// CHECK:STDOUT: - - node+9 -// CHECK:STDOUT: - node+10 -// CHECK:STDOUT: - - node+13 -// CHECK:STDOUT: - node+15 -// CHECK:STDOUT: - - node+5 -// CHECK:STDOUT: - node+6 +// CHECK:STDOUT: --- +// CHECK:STDOUT: filename: raw_and_textual_ir.carbon +// CHECK:STDOUT: sem_ir: +// CHECK:STDOUT: cross_reference_irs_size: 1 +// CHECK:STDOUT: functions: +// CHECK:STDOUT: function0: {name: str0, param_refs: block1, return_type: type3, return_slot: node+4, body: [block4]} +// CHECK:STDOUT: classes: {} +// CHECK:STDOUT: types: +// CHECK:STDOUT: type0: {node: nodeIntegerType, value_rep: {kind: copy, type: type0}} +// CHECK:STDOUT: type1: {node: node+1, value_rep: {kind: unknown, type: type}} +// CHECK:STDOUT: type2: {node: nodeFloatingPointType, value_rep: {kind: copy, type: type2}} +// CHECK:STDOUT: type3: {node: node+3, value_rep: {kind: pointer, type: type4}} +// CHECK:STDOUT: type4: {node: node+5, value_rep: {kind: copy, type: type4}} +// CHECK:STDOUT: type5: {node: nodeFunctionType, value_rep: {kind: copy, type: type5}} +// CHECK:STDOUT: type_blocks: +// CHECK:STDOUT: typeBlock0: +// CHECK:STDOUT: 0: typeTypeType +// CHECK:STDOUT: 1: typeTypeType +// CHECK:STDOUT: typeBlock1: +// CHECK:STDOUT: 0: type0 +// CHECK:STDOUT: 1: type2 +// CHECK:STDOUT: nodes: +// CHECK:STDOUT: node+0: {kind: Parameter, arg0: str1, type: type0} +// CHECK:STDOUT: node+1: {kind: TupleType, arg0: typeBlock0, type: typeTypeType} +// CHECK:STDOUT: node+2: {kind: TupleLiteral, arg0: block2, type: type1} +// CHECK:STDOUT: node+3: {kind: TupleType, arg0: typeBlock1, type: typeTypeType} +// CHECK:STDOUT: node+4: {kind: VarStorage, arg0: str2, type: type3} +// CHECK:STDOUT: node+5: {kind: PointerType, arg0: type3, type: typeTypeType} +// CHECK:STDOUT: node+6: {kind: FunctionDeclaration, arg0: function0, type: type5} +// CHECK:STDOUT: node+7: {kind: NameReference, arg0: str1, arg1: node+0, type: type0} +// CHECK:STDOUT: node+8: {kind: IntegerLiteral, arg0: int3, type: type0} +// CHECK:STDOUT: node+9: {kind: BinaryOperatorAdd, arg0: node+7, arg1: node+8, type: type0} +// CHECK:STDOUT: node+10: {kind: RealLiteral, arg0: real0, type: type2} +// CHECK:STDOUT: node+11: {kind: TupleLiteral, arg0: block5, type: type3} +// CHECK:STDOUT: node+12: {kind: TupleAccess, arg0: node+4, arg1: member0, type: type0} +// CHECK:STDOUT: node+13: {kind: InitializeFrom, arg0: node+9, arg1: node+12, type: type0} +// CHECK:STDOUT: node+14: {kind: TupleAccess, arg0: node+4, arg1: member1, type: type2} +// CHECK:STDOUT: node+15: {kind: InitializeFrom, arg0: node+10, arg1: node+14, type: type2} +// CHECK:STDOUT: node+16: {kind: TupleInit, arg0: node+11, arg1: block6, type: type3} +// CHECK:STDOUT: node+17: {kind: ReturnExpression, arg0: node+16} +// CHECK:STDOUT: node_blocks: +// CHECK:STDOUT: block0: {} +// CHECK:STDOUT: block1: +// CHECK:STDOUT: 0: node+0 +// CHECK:STDOUT: block2: +// CHECK:STDOUT: 0: nodeIntegerType +// CHECK:STDOUT: 1: nodeFloatingPointType +// CHECK:STDOUT: block3: +// CHECK:STDOUT: 0: node+0 +// CHECK:STDOUT: 1: node+1 +// CHECK:STDOUT: 2: node+2 +// CHECK:STDOUT: 3: node+3 +// CHECK:STDOUT: 4: node+4 +// CHECK:STDOUT: block4: +// CHECK:STDOUT: 0: node+7 +// CHECK:STDOUT: 1: node+8 +// CHECK:STDOUT: 2: node+9 +// CHECK:STDOUT: 3: node+10 +// CHECK:STDOUT: 4: node+11 +// CHECK:STDOUT: 5: node+12 +// CHECK:STDOUT: 6: node+13 +// CHECK:STDOUT: 7: node+14 +// CHECK:STDOUT: 8: node+15 +// CHECK:STDOUT: 9: node+16 +// CHECK:STDOUT: 10: node+17 +// CHECK:STDOUT: block5: +// CHECK:STDOUT: 0: node+9 +// CHECK:STDOUT: 1: node+10 +// CHECK:STDOUT: block6: +// CHECK:STDOUT: 0: node+13 +// CHECK:STDOUT: 1: node+15 +// CHECK:STDOUT: block7: +// CHECK:STDOUT: 0: node+5 +// CHECK:STDOUT: 1: node+6 +// CHECK:STDOUT: ... // CHECK:STDOUT: // CHECK:STDOUT: file "raw_and_textual_ir.carbon" { // CHECK:STDOUT: %.loc11: type = ptr_type (i32, f64) diff --git a/toolchain/check/testdata/basics/raw_ir.carbon b/toolchain/check/testdata/basics/raw_ir.carbon index 99f50b0c6348..5bb0d0a8fdb6 100644 --- a/toolchain/check/testdata/basics/raw_ir.carbon +++ b/toolchain/check/testdata/basics/raw_ir.carbon @@ -12,67 +12,78 @@ fn Foo(n: i32) -> (i32, f64) { return (n + 2, 3.4); } -// CHECK:STDOUT: - filename: raw_ir.carbon -// CHECK:STDOUT: sem_ir: -// CHECK:STDOUT: - cross_reference_irs_size: 1 -// CHECK:STDOUT: functions: -// CHECK:STDOUT: - {name: str0, param_refs: block1, return_type: type3, return_slot: node+4, body: [block4]} -// CHECK:STDOUT: classes: [] -// CHECK:STDOUT: types: -// CHECK:STDOUT: - {node: nodeIntegerType, value_rep: {kind: copy, type: type0}} -// CHECK:STDOUT: - {node: node+1, value_rep: {kind: unknown, type: type}} -// CHECK:STDOUT: - {node: nodeFloatingPointType, value_rep: {kind: copy, type: type2}} -// CHECK:STDOUT: - {node: node+3, value_rep: {kind: pointer, type: type4}} -// CHECK:STDOUT: - {node: node+5, value_rep: {kind: copy, type: type4}} -// CHECK:STDOUT: - {node: nodeFunctionType, value_rep: {kind: copy, type: type5}} -// CHECK:STDOUT: type_blocks: -// CHECK:STDOUT: - - typeTypeType -// CHECK:STDOUT: - typeTypeType -// CHECK:STDOUT: - - type0 -// CHECK:STDOUT: - type2 -// CHECK:STDOUT: nodes: -// CHECK:STDOUT: - {kind: Parameter, arg0: str1, type: type0} -// CHECK:STDOUT: - {kind: TupleType, arg0: typeBlock0, type: typeTypeType} -// CHECK:STDOUT: - {kind: TupleLiteral, arg0: block2, type: type1} -// CHECK:STDOUT: - {kind: TupleType, arg0: typeBlock1, type: typeTypeType} -// CHECK:STDOUT: - {kind: VarStorage, arg0: str2, type: type3} -// CHECK:STDOUT: - {kind: PointerType, arg0: type3, type: typeTypeType} -// CHECK:STDOUT: - {kind: FunctionDeclaration, arg0: function0, type: type5} -// CHECK:STDOUT: - {kind: NameReference, arg0: str1, arg1: node+0, type: type0} -// CHECK:STDOUT: - {kind: IntegerLiteral, arg0: int3, type: type0} -// CHECK:STDOUT: - {kind: BinaryOperatorAdd, arg0: node+7, arg1: node+8, type: type0} -// CHECK:STDOUT: - {kind: RealLiteral, arg0: real0, type: type2} -// CHECK:STDOUT: - {kind: TupleLiteral, arg0: block5, type: type3} -// CHECK:STDOUT: - {kind: TupleAccess, arg0: node+4, arg1: member0, type: type0} -// CHECK:STDOUT: - {kind: InitializeFrom, arg0: node+9, arg1: node+12, type: type0} -// CHECK:STDOUT: - {kind: TupleAccess, arg0: node+4, arg1: member1, type: type2} -// CHECK:STDOUT: - {kind: InitializeFrom, arg0: node+10, arg1: node+14, type: type2} -// CHECK:STDOUT: - {kind: TupleInit, arg0: node+11, arg1: block6, type: type3} -// CHECK:STDOUT: - {kind: ReturnExpression, arg0: node+16} -// CHECK:STDOUT: node_blocks: -// CHECK:STDOUT: - [] -// CHECK:STDOUT: - - node+0 -// CHECK:STDOUT: - - nodeIntegerType -// CHECK:STDOUT: - nodeFloatingPointType -// CHECK:STDOUT: - - node+0 -// CHECK:STDOUT: - node+1 -// CHECK:STDOUT: - node+2 -// CHECK:STDOUT: - node+3 -// CHECK:STDOUT: - node+4 -// CHECK:STDOUT: - - node+7 -// CHECK:STDOUT: - node+8 -// CHECK:STDOUT: - node+9 -// CHECK:STDOUT: - node+10 -// CHECK:STDOUT: - node+11 -// CHECK:STDOUT: - node+12 -// CHECK:STDOUT: - node+13 -// CHECK:STDOUT: - node+14 -// CHECK:STDOUT: - node+15 -// CHECK:STDOUT: - node+16 -// CHECK:STDOUT: - node+17 -// CHECK:STDOUT: - - node+9 -// CHECK:STDOUT: - node+10 -// CHECK:STDOUT: - - node+13 -// CHECK:STDOUT: - node+15 -// CHECK:STDOUT: - - node+5 -// CHECK:STDOUT: - node+6 +// CHECK:STDOUT: --- +// CHECK:STDOUT: filename: raw_ir.carbon +// CHECK:STDOUT: sem_ir: +// CHECK:STDOUT: cross_reference_irs_size: 1 +// CHECK:STDOUT: functions: +// CHECK:STDOUT: function0: {name: str0, param_refs: block1, return_type: type3, return_slot: node+4, body: [block4]} +// CHECK:STDOUT: classes: {} +// CHECK:STDOUT: types: +// CHECK:STDOUT: type0: {node: nodeIntegerType, value_rep: {kind: copy, type: type0}} +// CHECK:STDOUT: type1: {node: node+1, value_rep: {kind: unknown, type: type}} +// CHECK:STDOUT: type2: {node: nodeFloatingPointType, value_rep: {kind: copy, type: type2}} +// CHECK:STDOUT: type3: {node: node+3, value_rep: {kind: pointer, type: type4}} +// CHECK:STDOUT: type4: {node: node+5, value_rep: {kind: copy, type: type4}} +// CHECK:STDOUT: type5: {node: nodeFunctionType, value_rep: {kind: copy, type: type5}} +// CHECK:STDOUT: type_blocks: +// CHECK:STDOUT: typeBlock0: +// CHECK:STDOUT: 0: typeTypeType +// CHECK:STDOUT: 1: typeTypeType +// CHECK:STDOUT: typeBlock1: +// CHECK:STDOUT: 0: type0 +// CHECK:STDOUT: 1: type2 +// CHECK:STDOUT: nodes: +// CHECK:STDOUT: node+0: {kind: Parameter, arg0: str1, type: type0} +// CHECK:STDOUT: node+1: {kind: TupleType, arg0: typeBlock0, type: typeTypeType} +// CHECK:STDOUT: node+2: {kind: TupleLiteral, arg0: block2, type: type1} +// CHECK:STDOUT: node+3: {kind: TupleType, arg0: typeBlock1, type: typeTypeType} +// CHECK:STDOUT: node+4: {kind: VarStorage, arg0: str2, type: type3} +// CHECK:STDOUT: node+5: {kind: PointerType, arg0: type3, type: typeTypeType} +// CHECK:STDOUT: node+6: {kind: FunctionDeclaration, arg0: function0, type: type5} +// CHECK:STDOUT: node+7: {kind: NameReference, arg0: str1, arg1: node+0, type: type0} +// CHECK:STDOUT: node+8: {kind: IntegerLiteral, arg0: int3, type: type0} +// CHECK:STDOUT: node+9: {kind: BinaryOperatorAdd, arg0: node+7, arg1: node+8, type: type0} +// CHECK:STDOUT: node+10: {kind: RealLiteral, arg0: real0, type: type2} +// CHECK:STDOUT: node+11: {kind: TupleLiteral, arg0: block5, type: type3} +// CHECK:STDOUT: node+12: {kind: TupleAccess, arg0: node+4, arg1: member0, type: type0} +// CHECK:STDOUT: node+13: {kind: InitializeFrom, arg0: node+9, arg1: node+12, type: type0} +// CHECK:STDOUT: node+14: {kind: TupleAccess, arg0: node+4, arg1: member1, type: type2} +// CHECK:STDOUT: node+15: {kind: InitializeFrom, arg0: node+10, arg1: node+14, type: type2} +// CHECK:STDOUT: node+16: {kind: TupleInit, arg0: node+11, arg1: block6, type: type3} +// CHECK:STDOUT: node+17: {kind: ReturnExpression, arg0: node+16} +// CHECK:STDOUT: node_blocks: +// CHECK:STDOUT: block0: {} +// CHECK:STDOUT: block1: +// CHECK:STDOUT: 0: node+0 +// CHECK:STDOUT: block2: +// CHECK:STDOUT: 0: nodeIntegerType +// CHECK:STDOUT: 1: nodeFloatingPointType +// CHECK:STDOUT: block3: +// CHECK:STDOUT: 0: node+0 +// CHECK:STDOUT: 1: node+1 +// CHECK:STDOUT: 2: node+2 +// CHECK:STDOUT: 3: node+3 +// CHECK:STDOUT: 4: node+4 +// CHECK:STDOUT: block4: +// CHECK:STDOUT: 0: node+7 +// CHECK:STDOUT: 1: node+8 +// CHECK:STDOUT: 2: node+9 +// CHECK:STDOUT: 3: node+10 +// CHECK:STDOUT: 4: node+11 +// CHECK:STDOUT: 5: node+12 +// CHECK:STDOUT: 6: node+13 +// CHECK:STDOUT: 7: node+14 +// CHECK:STDOUT: 8: node+15 +// CHECK:STDOUT: 9: node+16 +// CHECK:STDOUT: 10: node+17 +// CHECK:STDOUT: block5: +// CHECK:STDOUT: 0: node+9 +// CHECK:STDOUT: 1: node+10 +// CHECK:STDOUT: block6: +// CHECK:STDOUT: 0: node+13 +// CHECK:STDOUT: 1: node+15 +// CHECK:STDOUT: block7: +// CHECK:STDOUT: 0: node+5 +// CHECK:STDOUT: 1: node+6 +// CHECK:STDOUT: ... diff --git a/toolchain/driver/testdata/dump_shared_values.carbon b/toolchain/driver/testdata/dump_shared_values.carbon index 03c5d6b3eef9..cfe5382c96e9 100644 --- a/toolchain/driver/testdata/dump_shared_values.carbon +++ b/toolchain/driver/testdata/dump_shared_values.carbon @@ -15,26 +15,28 @@ var real3: f64 = 0.8e9; var str1: String = "abc"; var str2: String = "ab'\"c"; +// CHECK:STDOUT: --- // CHECK:STDOUT: shared_values: -// CHECK:STDOUT: - integers: -// CHECK:STDOUT: - 32 -// CHECK:STDOUT: - 1 -// CHECK:STDOUT: - 32 -// CHECK:STDOUT: - 8 -// CHECK:STDOUT: - 64 -// CHECK:STDOUT: - 64 -// CHECK:STDOUT: - 64 -// CHECK:STDOUT: reals: -// CHECK:STDOUT: - 10*10^-1 -// CHECK:STDOUT: - 8*10^7 -// CHECK:STDOUT: - 8*10^8 -// CHECK:STDOUT: strings: -// CHECK:STDOUT: - "int1" -// CHECK:STDOUT: - "int2" -// CHECK:STDOUT: - "real1" -// CHECK:STDOUT: - "real2" -// CHECK:STDOUT: - "real3" -// CHECK:STDOUT: - "str1" -// CHECK:STDOUT: - "abc" -// CHECK:STDOUT: - "str2" -// CHECK:STDOUT: - "ab'\"c" +// CHECK:STDOUT: integers: +// CHECK:STDOUT: int0: 32 +// CHECK:STDOUT: int1: 1 +// CHECK:STDOUT: int2: 32 +// CHECK:STDOUT: int3: 8 +// CHECK:STDOUT: int4: 64 +// CHECK:STDOUT: int5: 64 +// CHECK:STDOUT: int6: 64 +// CHECK:STDOUT: reals: +// CHECK:STDOUT: real0: 10*10^-1 +// CHECK:STDOUT: real1: 8*10^7 +// CHECK:STDOUT: real2: 8*10^8 +// CHECK:STDOUT: strings: +// CHECK:STDOUT: str0: int1 +// CHECK:STDOUT: str1: int2 +// CHECK:STDOUT: str2: real1 +// CHECK:STDOUT: str3: real2 +// CHECK:STDOUT: str4: real3 +// CHECK:STDOUT: str5: str1 +// CHECK:STDOUT: str6: abc +// CHECK:STDOUT: str7: str2 +// CHECK:STDOUT: str8: 'ab''"c' +// CHECK:STDOUT: ... diff --git a/toolchain/lex/tokenized_buffer_test.cpp b/toolchain/lex/tokenized_buffer_test.cpp index cbec6c8c7290..3e2ce3da5945 100644 --- a/toolchain/lex/tokenized_buffer_test.cpp +++ b/toolchain/lex/tokenized_buffer_test.cpp @@ -1057,7 +1057,7 @@ TEST_F(LexerTest, DiagnosticUnrecognizedChar) { Lex("\b", consumer); } -TEST_F(LexerTest, PrintingAsYaml) { +TEST_F(LexerTest, PrintingOutputYaml) { // Test that we can parse this into YAML and verify line and indent data. auto buffer = Lex("\n ;\n\n\n; ;\n\n\n\n\n\n\n\n\n\n\n"); ASSERT_FALSE(buffer.has_errors()); diff --git a/toolchain/sem_ir/BUILD b/toolchain/sem_ir/BUILD index 074bce5e8d36..14512668f0dc 100644 --- a/toolchain/sem_ir/BUILD +++ b/toolchain/sem_ir/BUILD @@ -69,6 +69,7 @@ cc_library( ":value_stores", "//common:check", "//toolchain/base:value_store", + "//toolchain/base:yaml", "@llvm-project//llvm:Support", ], ) @@ -102,6 +103,7 @@ cc_library( deps = [ ":node", "//toolchain/base:value_store", + "//toolchain/base:yaml", "@llvm-project//llvm:Support", ], ) diff --git a/toolchain/sem_ir/file.cpp b/toolchain/sem_ir/file.cpp index 594bde0d4ce4..5e22e067bccd 100644 --- a/toolchain/sem_ir/file.cpp +++ b/toolchain/sem_ir/file.cpp @@ -8,6 +8,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "toolchain/base/value_store.h" +#include "toolchain/base/yaml.h" #include "toolchain/sem_ir/builtin_kind.h" #include "toolchain/sem_ir/node.h" #include "toolchain/sem_ir/node_kind.h" @@ -129,27 +130,30 @@ auto File::Verify() const -> ErrorOr { return Success(); } -auto File::Print(llvm::raw_ostream& out, bool include_builtins) const -> void { - out << "- filename: " << filename_ << "\n" - << " sem_ir:\n" - << " - cross_reference_irs_size: " << cross_reference_irs_.size() - << "\n"; - - static constexpr int FirstLineIndent = 4; - static constexpr int LaterIndent = 6; - functions_.Print(out, "functions", FirstLineIndent, LaterIndent); - classes_.Print(out, "classes", FirstLineIndent, LaterIndent); - types_.Print(out, "types", FirstLineIndent, LaterIndent); - type_blocks_.Print(out, "type_blocks", FirstLineIndent, LaterIndent); - - auto nodes = nodes_.array_ref(); - if (!include_builtins) { - nodes = nodes.drop_front(BuiltinKind::ValidCount); - } - PrintValueRange(out, llvm::iterator_range(nodes), "nodes", FirstLineIndent, - LaterIndent, /*trailing_newline=*/true); - - node_blocks_.Print(out, "node_blocks", FirstLineIndent, LaterIndent); +auto File::OutputYaml(bool include_builtins) const -> Yaml::OutputMapping { + return Yaml::OutputMapping([this, + include_builtins](Yaml::OutputMapping::Map map) { + map.Add("filename", filename_); + map.Add("sem_ir", Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) { + map.Add("cross_reference_irs_size", + Yaml::OutputScalar(cross_reference_irs_.size())); + map.Add("functions", functions_.OutputYaml()); + map.Add("classes", classes_.OutputYaml()); + map.Add("types", types_.OutputYaml()); + map.Add("type_blocks", type_blocks_.OutputYaml()); + map.Add("nodes", + Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) { + int start = + include_builtins ? 0 : BuiltinKind::ValidCount; + for (int i : llvm::seq(start, nodes_.size())) { + auto id = NodeId(i); + map.Add(PrintToString(id), + Yaml::OutputScalar(nodes_.Get(id))); + } + })); + map.Add("node_blocks", node_blocks_.OutputYaml()); + })); + }); } // Map a node kind representing a type into an integer describing the diff --git a/toolchain/sem_ir/file.h b/toolchain/sem_ir/file.h index e7c1f017a382..79553fefc6a2 100644 --- a/toolchain/sem_ir/file.h +++ b/toolchain/sem_ir/file.h @@ -10,6 +10,7 @@ #include "llvm/Support/Allocator.h" #include "llvm/Support/FormatVariadic.h" #include "toolchain/base/value_store.h" +#include "toolchain/base/yaml.h" #include "toolchain/sem_ir/node.h" #include "toolchain/sem_ir/value_stores.h" @@ -174,11 +175,11 @@ class File : public Printable { // TODO: In the future, the things to print may change, for example by adding // preludes. We may then want the ability to omit other things similar to // builtins. - auto Print(llvm::raw_ostream& out, bool include_builtins) const -> void; - - auto Print(llvm::raw_ostream& out) const -> void { - Print(out, /*include_builtins=*/false); + auto Print(llvm::raw_ostream& out, bool include_builtins = false) const + -> void { + Yaml::Print(out, OutputYaml(include_builtins)); } + auto OutputYaml(bool include_builtins) const -> Yaml::OutputMapping; // Returns array bound value from the bound node. auto GetArrayBoundValue(NodeId bound_id) const -> uint64_t { diff --git a/toolchain/sem_ir/value_stores.h b/toolchain/sem_ir/value_stores.h index e1c8431253e7..d91d277ea884 100644 --- a/toolchain/sem_ir/value_stores.h +++ b/toolchain/sem_ir/value_stores.h @@ -7,6 +7,7 @@ #include "llvm/ADT/DenseMap.h" #include "toolchain/base/value_store.h" +#include "toolchain/base/yaml.h" #include "toolchain/sem_ir/node.h" namespace Carbon::SemIR { @@ -72,7 +73,7 @@ class NameScopeStore { // BlockValueStore is used as-is, but there are also children that expose the // protected members for type-specific functionality. template -class BlockValueStore { +class BlockValueStore : public Yaml::Printable> { public: explicit BlockValueStore(llvm::BumpPtrAllocator& allocator) : allocator_(&allocator) {} @@ -88,18 +89,19 @@ class BlockValueStore { // Returns the requested block. auto Get(IdT id) -> llvm::MutableArrayRef { return values_.Get(id); } - auto Print(llvm::raw_ostream& out) const -> void { - Print(out, std::nullopt, 0, 0); - } - auto Print(llvm::raw_ostream& out, std::optional label, - int first_line_indent, int later_indent) const -> void { - values_.Print(out, label, first_line_indent, later_indent, - [&](llvm::raw_ostream& out, - const llvm::MutableArrayRef& value) { - PrintValueRange(out, llvm::iterator_range(value), - std::nullopt, 0, later_indent + 2, - /*trailing_newline=*/false); - }); + auto OutputYaml() const -> Yaml::OutputMapping { + return Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) { + for (auto block_index : llvm::seq(values_.size())) { + auto block_id = IdT(block_index); + map.Add(PrintToString(block_id), + Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) { + auto block = Get(block_id); + for (auto i : llvm::seq(block.size())) { + map.Add(llvm::itostr(i), Yaml::OutputScalar(block[i])); + } + })); + } + }); } auto size() const -> int { return values_.size(); } diff --git a/toolchain/sem_ir/yaml_test.cpp b/toolchain/sem_ir/yaml_test.cpp index 0f0e58224673..d225ac282882 100644 --- a/toolchain/sem_ir/yaml_test.cpp +++ b/toolchain/sem_ir/yaml_test.cpp @@ -44,40 +44,45 @@ TEST(SemIRTest, YAML) { auto node_id = Yaml::Scalar(MatchesRegex(R"(node\+\d+)")); auto node_builtin = Yaml::Scalar(MatchesRegex(R"(node\w+)")); auto type_id = Yaml::Scalar(MatchesRegex(R"(type\d+)")); - auto type_builtin = Yaml::Mapping(ElementsAre( - Pair("node", node_builtin), Pair("value_rep", Yaml::Mapping(_)))); + auto type_builtin = Pair( + type_id, Yaml::Mapping(ElementsAre(Pair("node", node_builtin), + Pair("value_rep", Yaml::Mapping(_))))); - auto file = Yaml::Sequence(ElementsAre(Yaml::Mapping(ElementsAre( + auto file = Yaml::Mapping(ElementsAre( Pair("cross_reference_irs_size", "1"), - Pair("functions", Yaml::Sequence(SizeIs(1))), - Pair("classes", Yaml::Sequence(SizeIs(0))), - Pair("types", Yaml::Sequence(Each(type_builtin))), - Pair("type_blocks", Yaml::Sequence(IsEmpty())), + Pair("functions", Yaml::Mapping(SizeIs(1))), + Pair("classes", Yaml::Mapping(SizeIs(0))), + Pair("types", Yaml::Mapping(Each(type_builtin))), + Pair("type_blocks", Yaml::Mapping(IsEmpty())), Pair("nodes", - Yaml::Sequence(AllOf( + Yaml::Mapping(AllOf( + Each(Key(node_id)), // kind is required, other parts are optional. - Each(Yaml::Mapping(Contains(Pair("kind", _)))), + Each(Pair(_, Yaml::Mapping(Contains(Pair("kind", _))))), // A 0-arg node. - Contains(Yaml::Mapping(ElementsAre(Pair("kind", "Return")))), + Contains( + Pair(_, Yaml::Mapping(ElementsAre(Pair("kind", "Return"))))), // A 1-arg node. - Contains(Yaml::Mapping(ElementsAre( - Pair("kind", "IntegerLiteral"), Pair("arg0", integer_id), - Pair("type", type_id)))), + Contains(Pair( + _, Yaml::Mapping(ElementsAre(Pair("kind", "IntegerLiteral"), + Pair("arg0", integer_id), + Pair("type", type_id))))), // A 2-arg node. - Contains(Yaml::Mapping(ElementsAre(Pair("kind", "Assign"), - Pair("arg0", node_id), - Pair("arg1", node_id))))))), + Contains(Pair( + _, Yaml::Mapping(ElementsAre(Pair("kind", "Assign"), + Pair("arg0", node_id), + Pair("arg1", node_id)))))))), // This production has only two node blocks. Pair("node_blocks", - Yaml::Sequence(ElementsAre(Yaml::Sequence(IsEmpty()), - Yaml::Sequence(Each(node_id)), - Yaml::Sequence(Each(node_id))))))))); + Yaml::Mapping(ElementsAre( + Pair("block0", Yaml::Mapping(IsEmpty())), + Pair("block1", Yaml::Mapping(Each(Pair(_, node_id)))), + Pair("block2", Yaml::Mapping(Each(Pair(_, node_id))))))))); auto root = Yaml::Sequence(ElementsAre(Yaml::Mapping( ElementsAre(Pair("filename", "test.carbon"), Pair("sem_ir", file))))); - EXPECT_THAT(Yaml::Value::FromText(print_stream.TakeStr()), - IsYaml(ElementsAre(root))); + EXPECT_THAT(Yaml::Value::FromText(print_stream.TakeStr()), IsYaml(root)); } } // namespace