From a6143a7cf178b120e9d8608d530fa60d0aee442f Mon Sep 17 00:00:00 2001 From: Mark Heffernan Date: Tue, 9 Jul 2024 17:44:08 -0700 Subject: [PATCH] Sanitize C++ keywords in DSLX->C++ type converter. C++ keywords are prefixed with an underscore. PiperOrigin-RevId: 650810801 --- xls/dslx/cpp_transpiler/BUILD | 4 + xls/dslx/cpp_transpiler/cpp_emitter.cc | 109 +++++++++++++++++- xls/dslx/cpp_transpiler/cpp_emitter.h | 3 + xls/dslx/cpp_transpiler/cpp_type_generator.cc | 37 +++--- xls/dslx/cpp_transpiler/test_types.x | 12 ++ xls/dslx/cpp_transpiler/test_types_test.cc | 9 ++ 6 files changed, 158 insertions(+), 16 deletions(-) diff --git a/xls/dslx/cpp_transpiler/BUILD b/xls/dslx/cpp_transpiler/BUILD index 27ce9adb12..845e926921 100644 --- a/xls/dslx/cpp_transpiler/BUILD +++ b/xls/dslx/cpp_transpiler/BUILD @@ -48,7 +48,9 @@ cc_library( srcs = ["cpp_emitter.cc"], hdrs = ["cpp_emitter.h"], deps = [ + "@com_google_absl//absl/base:no_destructor", "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/container:flat_hash_set", "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", @@ -75,7 +77,9 @@ cc_library( hdrs = ["cpp_type_generator.h"], deps = [ ":cpp_emitter", + "@com_google_absl//absl/base:no_destructor", "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/container:flat_hash_set", "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", diff --git a/xls/dslx/cpp_transpiler/cpp_emitter.cc b/xls/dslx/cpp_transpiler/cpp_emitter.cc index 8318b88b80..627d820fd0 100644 --- a/xls/dslx/cpp_transpiler/cpp_emitter.cc +++ b/xls/dslx/cpp_transpiler/cpp_emitter.cc @@ -24,7 +24,9 @@ #include #include +#include "absl/base/no_destructor.h" #include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" #include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/str_cat.h" @@ -626,8 +628,113 @@ class TupleCppEmitter : public CppEmitter { } // namespace +std::string SanitizeCppName(std::string_view name) { + static const absl::NoDestructor> + kCppKeywords({"alignas", + "alignof", + "and", + "and_eq", + "asm", + "atomic_cancel", + "atomic_commit", + "atomic_noexcept", + "auto", + "bitand", + "bitor", + "bool", + "break", + "case", + "catch", + "char", + "char8_t", + "char16_t", + "char32_t", + "class", + "compl", + "concept", + "const", + "consteval", + "constexpr", + "constinit", + "const_cast", + "continue", + "co_await", + "co_return", + "co_yield", + "decltype", + "default", + "delete", + "do", + "double", + "dynamic_cast", + "else", + "enum", + "explicit", + "export", + "extern", + "false", + "float", + "for", + "friend", + "goto", + "if", + "inline", + "int", + "long", + "mutable", + "namespace", + "new", + "noexcept", + "not", + "not_eq", + "nullptr", + "operator", + "or", + "or_eq", + "private", + "protected", + "public", + "reflexpr", + "register", + "reinterpret_cast", + "requires", + "return", + "short", + "signed", + "sizeof", + "static", + "static_assert", + "static_cast", + "struct", + "switch", + "synchronized", + "template", + "this", + "thread_local", + "throw", + "true", + "try", + "typedef", + "typeid", + "typename", + "union", + "unsigned", + "using", + "virtual", + "void", + "volatile", + "wchar_t", + "while", + "xor", + "xor_eq"}); + if (kCppKeywords->contains(name)) { + return absl::StrCat("_", name); + } + return std::string{name}; +} + std::string DslxTypeNameToCpp(std::string_view dslx_type) { - return Camelize(dslx_type); + return SanitizeCppName(Camelize(dslx_type)); } /* static */ absl::StatusOr> CppEmitter::Create( diff --git a/xls/dslx/cpp_transpiler/cpp_emitter.h b/xls/dslx/cpp_transpiler/cpp_emitter.h index f32a909fa6..fdfeaf7c77 100644 --- a/xls/dslx/cpp_transpiler/cpp_emitter.h +++ b/xls/dslx/cpp_transpiler/cpp_emitter.h @@ -28,6 +28,9 @@ namespace xls::dslx { +// Sanitizes the given name for C++. C++ keywords are prefixed with "_". +std::string SanitizeCppName(std::string_view name); + // Returns the C++ type name used to represent the given DSLX type name. std::string DslxTypeNameToCpp(std::string_view dslx_type); diff --git a/xls/dslx/cpp_transpiler/cpp_type_generator.cc b/xls/dslx/cpp_transpiler/cpp_type_generator.cc index 2e1bb01d0e..2a631b7986 100644 --- a/xls/dslx/cpp_transpiler/cpp_type_generator.cc +++ b/xls/dslx/cpp_transpiler/cpp_type_generator.cc @@ -418,7 +418,15 @@ class StructCppTypeGenerator : public CppTypeGenerator { std::vector> member_emitters) : CppTypeGenerator(cpp_type, dslx_type), struct_def_(struct_def), - member_emitters_(std::move(member_emitters)) {} + member_emitters_(std::move(member_emitters)), + cpp_member_names_([struct_def]() { + std::vector names; + names.reserve(struct_def->size()); + for (int64_t i = 0; i < struct_def->size(); ++i) { + names.push_back(SanitizeCppName(struct_def->GetMemberName(i))); + } + return names; + }()) {} ~StructCppTypeGenerator() override = default; static absl::StatusOr> Create( @@ -440,7 +448,7 @@ class StructCppTypeGenerator : public CppTypeGenerator { std::vector member_decls; std::vector scalar_widths; for (int64_t i = 0; i < struct_def_->size(); ++i) { - std::string member_name = struct_def_->GetMemberName(i); + std::string member_name = cpp_member_names_[i]; member_decls.push_back(absl::StrFormat( "%s %s;", member_emitters_[i]->cpp_type(), member_name)); std::optional width = @@ -506,7 +514,7 @@ class StructCppTypeGenerator : public CppTypeGenerator { pieces.push_back(absl::StrFormat("%s result;", cpp_type())); for (int i = 0; i < struct_def_->members().size(); i++) { std::string assignment = member_emitters_[i]->AssignFromValue( - /*lhs=*/absl::StrFormat("result.%s", struct_def_->GetMemberName(i)), + /*lhs=*/absl::StrFormat("result.%s", cpp_member_names_[i]), /*rhs=*/absl::StrFormat("value.element(%d)", i), /*nesting=*/0); pieces.push_back(assignment); } @@ -531,7 +539,7 @@ class StructCppTypeGenerator : public CppTypeGenerator { for (int i = 0; i < struct_def_->members().size(); i++) { std::string assignment = member_emitters_[i]->AssignToValue( /*lhs=*/absl::StrFormat("members[%d]", i), - /*rhs=*/struct_def_->GetMemberName(i), /*nesting=*/0); + /*rhs=*/cpp_member_names_[i], /*nesting=*/0); pieces.push_back(assignment); } pieces.push_back("return ::xls::Value::Tuple(members);"); @@ -548,8 +556,8 @@ class StructCppTypeGenerator : public CppTypeGenerator { std::vector pieces; for (int i = 0; i < struct_def_->members().size(); i++) { std::string verification = member_emitters_[i]->Verify( - struct_def_->GetMemberName(i), - absl::StrFormat("%s.%s", cpp_type(), struct_def_->GetMemberName(i)), + cpp_member_names_[i], + absl::StrFormat("%s.%s", cpp_type(), cpp_member_names_[i]), /*nesting=*/0); pieces.push_back(verification); } @@ -567,11 +575,10 @@ class StructCppTypeGenerator : public CppTypeGenerator { pieces.push_back( absl::StrFormat("std::string result = \"%s {\\n\";", cpp_type())); for (int i = 0; i < struct_def_->members().size(); i++) { - pieces.push_back( - absl::StrFormat("result += __indent(indent + 1) + \"%s: \";", - struct_def_->GetMemberName(i))); + pieces.push_back(absl::StrFormat( + "result += __indent(indent + 1) + \"%s: \";", cpp_member_names_[i])); std::string to_string = member_emitters_[i]->ToString( - "result", "indent + 2", struct_def_->GetMemberName(i), /*nesting=*/0); + "result", "indent + 2", cpp_member_names_[i], /*nesting=*/0); pieces.push_back(to_string); pieces.push_back("result += \",\\n\";"); } @@ -590,11 +597,10 @@ class StructCppTypeGenerator : public CppTypeGenerator { pieces.push_back( absl::StrFormat("std::string result = \"%s {\\n\";", dslx_type())); for (int i = 0; i < struct_def_->members().size(); i++) { - pieces.push_back( - absl::StrFormat("result += __indent(indent + 1) + \"%s: \";", - struct_def_->GetMemberName(i))); + pieces.push_back(absl::StrFormat( + "result += __indent(indent + 1) + \"%s: \";", cpp_member_names_[i])); std::string to_string = member_emitters_[i]->ToDslxString( - "result", "indent + 2", struct_def_->GetMemberName(i), /*nesting=*/0); + "result", "indent + 2", cpp_member_names_[i], /*nesting=*/0); pieces.push_back(to_string); pieces.push_back("result += \",\\n\";"); } @@ -617,7 +623,7 @@ class StructCppTypeGenerator : public CppTypeGenerator { } else { std::vector member_comparisons; for (int i = 0; i < struct_def_->members().size(); i++) { - const std::string& member_name = struct_def_->GetMemberName(i); + const std::string& member_name = cpp_member_names_[i]; member_comparisons.push_back( absl::StrFormat("%s == other.%s", member_name, member_name)); } @@ -650,6 +656,7 @@ class StructCppTypeGenerator : public CppTypeGenerator { const StructDef* struct_def_; std::vector> member_emitters_; + std::vector cpp_member_names_; }; } // namespace diff --git a/xls/dslx/cpp_transpiler/test_types.x b/xls/dslx/cpp_transpiler/test_types.x index b64998f4f1..fddb011676 100644 --- a/xls/dslx/cpp_transpiler/test_types.x +++ b/xls/dslx/cpp_transpiler/test_types.x @@ -105,3 +105,15 @@ struct snake_case_struct_t { some_field: snake_case_type_t, some_other_field: snake_case_enum_t, } + +struct StructWithKeywordFields { + float: u32, + int: u42, +} + +enum EnumWithKeywordValues : u8 { + float = 0, + static = 1, +} + +type float = u33; diff --git a/xls/dslx/cpp_transpiler/test_types_test.cc b/xls/dslx/cpp_transpiler/test_types_test.cc index a47629aaeb..c874dbcfeb 100644 --- a/xls/dslx/cpp_transpiler/test_types_test.cc +++ b/xls/dslx/cpp_transpiler/test_types_test.cc @@ -618,5 +618,14 @@ TEST(TestTypesTest, SnakeCaseToString) { })"); } +TEST(TestTypesTest, StructWithKeywordFields) { + test::StructWithKeywordFields a{._float = 42, ._int = 1}; + + EXPECT_EQ(a.ToString(), R"(StructWithKeywordFields { + _float: bits[32]:0x2a, + _int: bits[42]:0x1, +})"); +} + } // namespace } // namespace xls