diff --git a/verilog/analysis/verilog_project.cc b/verilog/analysis/verilog_project.cc index d3458ecdb3..03a3996d62 100644 --- a/verilog/analysis/verilog_project.cc +++ b/verilog/analysis/verilog_project.cc @@ -91,6 +91,23 @@ absl::Status InMemoryVerilogSourceFile::Open() { return status_; } +absl::Status ParsedVerilogSourceFile::Open() { + state_ = State::kOpened; + status_ = absl::OkStatus(); + return status_; +} + +absl::Status ParsedVerilogSourceFile::Parse() { + state_ = State::kParsed; + status_ = absl::OkStatus(); + return status_; +} + +const verible::TextStructureView* ParsedVerilogSourceFile::GetTextStructure() + const { + return &text_structure_; +} + absl::StatusOr VerilogProject::OpenFile( absl::string_view referenced_filename, absl::string_view resolved_filename, absl::string_view corpus) { diff --git a/verilog/analysis/verilog_project.h b/verilog/analysis/verilog_project.h index b2e0360944..b518350166 100644 --- a/verilog/analysis/verilog_project.h +++ b/verilog/analysis/verilog_project.h @@ -60,12 +60,12 @@ class VerilogSourceFile { // Attempts to lex and parse the file (without preprocessing). // Will Open() if the file is not already opened. // Depending on context, not all files are suitable for standalone parsing. - absl::Status Parse(); + virtual absl::Status Parse(); // After Open(), the underlying text structure contains at least the file's // contents. After Parse(), it may contain other analyzed structural forms. // Before Open(), this returns nullptr. - const verible::TextStructureView* GetTextStructure() const; + virtual const verible::TextStructureView* GetTextStructure() const; // Returns the first non-Ok status if there is one, else OkStatus(). absl::Status Status() const { return status_; } @@ -165,6 +165,30 @@ class InMemoryVerilogSourceFile : public VerilogSourceFile { const absl::string_view contents_for_open_; }; +// Source file that was already parsed and got its own TextStructure. +// Doesn't require file-system access, nor create temporary files. +class ParsedVerilogSourceFile : public VerilogSourceFile { + public: + // filename can be fake, it is not used to open any file. + ParsedVerilogSourceFile(absl::string_view filename, + const verible::TextStructureView& text_structure, + absl::string_view corpus = "") + : VerilogSourceFile(filename, filename, corpus), + text_structure_(text_structure) {} + + // Do nothing (file contents already loaded) + absl::Status Open() override; + + // Do nothing (contents already parsed) + absl::Status Parse() override; + + // Return TextStructureView provided previously in constructor + const verible::TextStructureView* GetTextStructure() const override; + + private: + const verible::TextStructureView& text_structure_; +}; + // VerilogProject represents a set of files as a cohesive unit of compilation. // Files can include top-level translation units and preprocessor included // files. This is responsible for owning string memory that corresponds diff --git a/verilog/analysis/verilog_project_test.cc b/verilog/analysis/verilog_project_test.cc index a41ad243d9..5cc665c421 100644 --- a/verilog/analysis/verilog_project_test.cc +++ b/verilog/analysis/verilog_project_test.cc @@ -197,6 +197,36 @@ TEST(InMemoryVerilogSourceFileTest, ParseInvalidFile) { EXPECT_EQ(&text_structure->SyntaxTree(), tree); } +TEST(ParsedVerilogSourceFileTest, ParseValidFile) { + constexpr absl::string_view text("localparam int p = 1;\n"); + std::unique_ptr analyzed_structure = + absl::make_unique(text, "internal"); + absl::Status status = analyzed_structure->Analyze(); + EXPECT_TRUE(status.ok()); + const TextStructureView& input_text_structure = analyzed_structure->Data(); + + ParsedVerilogSourceFile file("internal", input_text_structure); + // Parse automatically opens. + EXPECT_TRUE(file.Parse().ok()); + EXPECT_TRUE(file.Status().ok()); + const TextStructureView* text_structure = + ABSL_DIE_IF_NULL(file.GetTextStructure()); + EXPECT_EQ(&input_text_structure, text_structure); + const absl::string_view owned_string_range(text_structure->Contents()); + EXPECT_EQ(owned_string_range, text); + const auto* tokens = &text_structure->TokenStream(); + EXPECT_NE(tokens, nullptr); + const auto* tree = &text_structure->SyntaxTree(); + EXPECT_NE(tree, nullptr); + + // Re-parsing doesn't change anything + EXPECT_TRUE(file.Parse().ok()); + EXPECT_TRUE(file.Status().ok()); + EXPECT_EQ(file.GetTextStructure(), text_structure); + EXPECT_EQ(&text_structure->TokenStream(), tokens); + EXPECT_EQ(&text_structure->SyntaxTree(), tree); +} + TEST(VerilogProjectTest, Initialization) { const auto tempdir = ::testing::TempDir(); VerilogProject project(tempdir, {tempdir});