From c61964abeb7dad40b6032dfa344a89d4fbdba20b Mon Sep 17 00:00:00 2001 From: Chris Leary Date: Mon, 30 Dec 2024 13:12:40 -0800 Subject: [PATCH] [DSLX:FE] Add feature flag to gate `use` syntax. --- xls/dslx/fmt/ast_fmt.cc | 4 ++++ xls/dslx/frontend/ast_cloner_test.cc | 4 +++- xls/dslx/frontend/module.cc | 3 +++ xls/dslx/frontend/module.h | 3 +++ xls/dslx/frontend/parser.cc | 24 ++++++++++++++++++++++++ xls/dslx/frontend/parser_test.cc | 26 ++++++++++++++++++-------- 6 files changed, 55 insertions(+), 9 deletions(-) diff --git a/xls/dslx/fmt/ast_fmt.cc b/xls/dslx/fmt/ast_fmt.cc index 9a4cf9d3d0..bb9eb35eb4 100644 --- a/xls/dslx/fmt/ast_fmt.cc +++ b/xls/dslx/fmt/ast_fmt.cc @@ -2897,6 +2897,10 @@ absl::StatusOr Formatter::Format(const Module& n) { pieces.push_back(arena_.MakeText("#![type_inference_version = 2]")); pieces.push_back(arena_.hard_line()); break; + case ModuleAnnotation::kAllowUseSyntax: + pieces.push_back(arena_.MakeText("#![feature(use_syntax)]")); + pieces.push_back(arena_.hard_line()); + break; } } pieces.push_back(arena_.hard_line()); diff --git a/xls/dslx/frontend/ast_cloner_test.cc b/xls/dslx/frontend/ast_cloner_test.cc index 60fd4b1333..5b70a14560 100644 --- a/xls/dslx/frontend/ast_cloner_test.cc +++ b/xls/dslx/frontend/ast_cloner_test.cc @@ -1738,7 +1738,9 @@ fn divmod() {})*"; TEST(AstClonerTest, Use) { constexpr std::string_view kProgram = - R"(use foo::bar::{baz::{bat, qux}, ipsum};)"; + R"(#![feature(use_syntax)] + +use foo::bar::{baz::{bat, qux}, ipsum};)"; FileTable file_table; XLS_ASSERT_OK_AND_ASSIGN(auto module, ParseModule(kProgram, "fake_path.x", diff --git a/xls/dslx/frontend/module.cc b/xls/dslx/frontend/module.cc index 43ce2c9c21..336146defc 100644 --- a/xls/dslx/frontend/module.cc +++ b/xls/dslx/frontend/module.cc @@ -85,6 +85,9 @@ std::string Module::ToString() const { case ModuleAnnotation::kTypeInferenceVersion2: absl::StrAppend(out, "#![type_inference_version = 2]"); break; + case ModuleAnnotation::kAllowUseSyntax: + absl::StrAppend(out, "#![feature(use_syntax)]"); + break; } }); return absl::StrCat(header, "\n\n", body); diff --git a/xls/dslx/frontend/module.h b/xls/dslx/frontend/module.h index ebbfe89a5b..b0a497ad97 100644 --- a/xls/dslx/frontend/module.h +++ b/xls/dslx/frontend/module.h @@ -69,6 +69,9 @@ enum class ModuleAnnotation : uint8_t { kAllowNonstandardMemberNaming, kTypeInferenceVersion2, + + // Enable "use" syntax instead of "import" for this module. + kAllowUseSyntax, }; // Represents a syntactic module in the AST. diff --git a/xls/dslx/frontend/parser.cc b/xls/dslx/frontend/parser.cc index 98814efc05..d644d51656 100644 --- a/xls/dslx/frontend/parser.cc +++ b/xls/dslx/frontend/parser.cc @@ -257,6 +257,16 @@ absl::Status Parser::ParseModuleAttribute() { Span identifier_span; XLS_ASSIGN_OR_RETURN(std::string identifier, PopIdentifierOrError(&identifier_span)); + if (identifier == "feature") { + XLS_RETURN_IF_ERROR(DropTokenOrError(TokenKind::kOParen)); + XLS_ASSIGN_OR_RETURN(std::string feature, PopIdentifierOrError()); + if (feature == "use_syntax") { + module_->AddAnnotation(ModuleAnnotation::kAllowUseSyntax); + } + XLS_RETURN_IF_ERROR(DropTokenOrError(TokenKind::kCParen)); + XLS_RETURN_IF_ERROR(DropTokenOrError(TokenKind::kCBrack)); + return absl::OkStatus(); + } if (identifier == "type_inference_version") { XLS_RETURN_IF_ERROR(DropTokenOrError(TokenKind::kEquals)); XLS_RETURN_IF_ERROR(ParseTypeInferenceVersionAttribute()); @@ -474,11 +484,25 @@ absl::StatusOr> Parser::ParseModule( break; } case Keyword::kImport: { + if (module_->annotations().contains( + ModuleAnnotation::kAllowUseSyntax)) { + return ParseErrorStatus( + peek->span(), + "`import` syntax is disabled for this module via " + "`#![feature(use_syntax)]` at module scope; use `use` instead"); + } XLS_ASSIGN_OR_RETURN(Import * import, ParseImport(*bindings)); XLS_RETURN_IF_ERROR(module_->AddTop(import, make_collision_error)); break; } case Keyword::kUse: { + if (!module_->annotations().contains( + ModuleAnnotation::kAllowUseSyntax)) { + return ParseErrorStatus( + peek->span(), + "`use` syntax is not enabled for this module; enable with " + "`#![feature(use_syntax)]` at module scope"); + } XLS_ASSIGN_OR_RETURN(Use * use, ParseUse(*bindings)); XLS_RETURN_IF_ERROR(module_->AddTop(use, make_collision_error)); break; diff --git a/xls/dslx/frontend/parser_test.cc b/xls/dslx/frontend/parser_test.cc index d56478ba8e..53d9b4606f 100644 --- a/xls/dslx/frontend/parser_test.cc +++ b/xls/dslx/frontend/parser_test.cc @@ -1666,38 +1666,48 @@ fn foo() -> bar::T<2>[3] { } TEST_F(ParserTest, UseOneItemFromModule) { - RoundTrip(R"(use foo::BAR; + RoundTrip(R"(#![feature(use_syntax)] + +use foo::BAR; fn main() -> u32 { BAR })"); } TEST_F(ParserTest, UseTwoItemsFromModule) { - RoundTrip(R"(use foo::{BAR, BAZ}; + RoundTrip(R"(#![feature(use_syntax)] + +use foo::{BAR, BAZ}; fn main() -> u32 { BAR + BAZ })"); } TEST_F(ParserTest, UseWithNestedLevels) { - RoundTrip(R"(use foo::{bar::{baz, qux}, quux}; + RoundTrip(R"(#![feature(use_syntax)] + +use foo::{bar::{baz, qux}, quux}; fn main() -> u32 { baz + qux + quux })"); } TEST_F(ParserTest, UseCollidesWithImport) { - constexpr std::string_view kProgram = "use foo; import foo;"; + constexpr std::string_view kProgram = R"(#![feature(use_syntax)] + +use foo; import foo; +)"; absl::StatusOr> module = Parse(kProgram); EXPECT_THAT( module.status(), - StatusIs( - absl::StatusCode::kInvalidArgument, - HasSubstr("Import of `foo` is shadowing an existing definition"))); + StatusIs(absl::StatusCode::kInvalidArgument, + HasSubstr("`import` syntax is disabled for this module via " + "`#![feature(use_syntax)]` at module scope"))); } TEST_F(ParserTest, UseWithPeersAtTopLevelNotAllowed) { - constexpr std::string_view kProgram = "use {foo, bar};"; + constexpr std::string_view kProgram = R"(#![feature(use_syntax)] +use {foo, bar};)"; absl::StatusOr> module = Parse(kProgram); EXPECT_THAT( module.status(),