From d51ca271af8f9978b86d6304ab19e9c9a63fb99e Mon Sep 17 00:00:00 2001 From: Jon Ross-Perkins Date: Tue, 25 Oct 2022 12:55:26 -0700 Subject: [PATCH] Refactory the IR/builder relationship (#2342) I'm thinking about how to handle multiple files, and I think the current IRFactory is useful as a file-focused thing. So shifting/renaming accordingly. (doing this in its own PR to make the history a little cleaner for git's move detection) --- bazel/check_deps/BUILD | 2 +- migrate_cpp/BUILD | 4 ++ toolchain/README.md | 3 +- toolchain/driver/BUILD | 2 +- toolchain/driver/driver.cpp | 4 +- toolchain/semantics/BUILD | 15 +---- toolchain/semantics/semantics_ir.cpp | 6 ++ toolchain/semantics/semantics_ir.h | 9 +-- ...y.cpp => semantics_parse_tree_handler.cpp} | 59 ++++++++----------- ...ctory.h => semantics_parse_tree_handler.h} | 43 +++++++------- 10 files changed, 67 insertions(+), 80 deletions(-) rename toolchain/semantics/{semantics_ir_factory.cpp => semantics_parse_tree_handler.cpp} (69%) rename toolchain/semantics/{semantics_ir_factory.h => semantics_parse_tree_handler.h} (70%) diff --git a/bazel/check_deps/BUILD b/bazel/check_deps/BUILD index 6cc534327b14..7092fd492389 100644 --- a/bazel/check_deps/BUILD +++ b/bazel/check_deps/BUILD @@ -13,10 +13,10 @@ filegroup( data = [ "//explorer", "//installers/local:carbon", + "//migrate_cpp:rewriter", "//migrate_cpp/cpp_refactoring", "//toolchain/diagnostics:null_diagnostics", "//toolchain/driver:carbon", - "//toolchain/semantics:semantics_ir_factory", ], ) diff --git a/migrate_cpp/BUILD b/migrate_cpp/BUILD index 0ec7ae6ea78a..2d294d3456a3 100644 --- a/migrate_cpp/BUILD +++ b/migrate_cpp/BUILD @@ -36,6 +36,10 @@ cc_library( "@llvm-project//clang:tooling_core", "@llvm-project//llvm:Support", ], + visibility = [ + # For dependency checking. Remove once it has a binary using it. + "//bazel/check_deps:__pkg__", + ], ) cc_test( diff --git a/toolchain/README.md b/toolchain/README.md index 416bcf34016d..f97416ce9029 100644 --- a/toolchain/README.md +++ b/toolchain/README.md @@ -124,8 +124,7 @@ keeping the code simple seems better until the language design stabilizes. ## Semantics The [SemanticsIR](semantics/semantics_ir.h) is the output of semantic -processing. It's currently built using -[a factory](semantics/semantics_ir_factory.h). +processing. The intent is that a `SemanticsIR` looks closer to a series of instructions than a tree. This is in order to better align with the LLVM IR structure which will diff --git a/toolchain/driver/BUILD b/toolchain/driver/BUILD index 2e99dd7d4021..41c40d14f239 100644 --- a/toolchain/driver/BUILD +++ b/toolchain/driver/BUILD @@ -19,7 +19,7 @@ cc_library( "//toolchain/diagnostics:sorting_diagnostic_consumer", "//toolchain/lexer:tokenized_buffer", "//toolchain/parser:parse_tree", - "//toolchain/semantics:semantics_ir_factory", + "//toolchain/semantics:semantics_ir", "//toolchain/source:source_buffer", "@llvm-project//llvm:Support", ], diff --git a/toolchain/driver/driver.cpp b/toolchain/driver/driver.cpp index 051f233a0fa3..faaec5a3283a 100644 --- a/toolchain/driver/driver.cpp +++ b/toolchain/driver/driver.cpp @@ -14,7 +14,7 @@ #include "toolchain/diagnostics/sorting_diagnostic_consumer.h" #include "toolchain/lexer/tokenized_buffer.h" #include "toolchain/parser/parse_tree.h" -#include "toolchain/semantics/semantics_ir_factory.h" +#include "toolchain/semantics/semantics_ir.h" #include "toolchain/source/source_buffer.h" namespace Carbon { @@ -162,7 +162,7 @@ auto Driver::RunDumpSubcommand(DiagnosticConsumer& consumer, return !tokenized_source.has_errors() && !parse_tree.has_errors(); } - auto semantics_ir = SemanticsIRFactory::Build(tokenized_source, parse_tree); + SemanticsIR semantics_ir(tokenized_source, parse_tree); if (dump_mode == DumpMode::SemanticsIR) { consumer.Flush(); semantics_ir.Print(output_stream_); diff --git a/toolchain/semantics/BUILD b/toolchain/semantics/BUILD index 89f22ebb1d6b..d0943b1b2846 100644 --- a/toolchain/semantics/BUILD +++ b/toolchain/semantics/BUILD @@ -18,10 +18,12 @@ cc_library( cc_library( name = "semantics_ir", srcs = [ + "semantics_parse_tree_handler.cpp", "semantics_ir.cpp", "semantics_node.cpp", ], hdrs = [ + "semantics_parse_tree_handler.h", "semantics_ir.h", "semantics_node.h", ], @@ -29,19 +31,6 @@ cc_library( ":semantics_node_kind", "//common:check", "//common:ostream", - "//toolchain/lexer:tokenized_buffer", - "//toolchain/parser:parse_tree", - "@llvm-project//llvm:Support", - ], -) - -cc_library( - name = "semantics_ir_factory", - srcs = ["semantics_ir_factory.cpp"], - hdrs = ["semantics_ir_factory.h"], - deps = [ - ":semantics_ir", - "//common:check", "//toolchain/lexer:token_kind", "//toolchain/lexer:tokenized_buffer", "//toolchain/parser:parse_node_kind", diff --git a/toolchain/semantics/semantics_ir.cpp b/toolchain/semantics/semantics_ir.cpp index b685f6eb6310..f9c186bcd152 100644 --- a/toolchain/semantics/semantics_ir.cpp +++ b/toolchain/semantics/semantics_ir.cpp @@ -8,9 +8,15 @@ #include "llvm/Support/FormatVariadic.h" #include "toolchain/lexer/tokenized_buffer.h" #include "toolchain/semantics/semantics_node.h" +#include "toolchain/semantics/semantics_parse_tree_handler.h" namespace Carbon { +SemanticsIR::SemanticsIR(const TokenizedBuffer& tokens, + const ParseTree& parse_tree) { + SemanticsParseTreeHandler(tokens, parse_tree, *this).Build(); +} + auto SemanticsIR::Print(llvm::raw_ostream& out) const -> void { out << "identifiers = {\n"; for (int32_t i = 0; i < static_cast(identifiers_.size()); ++i) { diff --git a/toolchain/semantics/semantics_ir.h b/toolchain/semantics/semantics_ir.h index 736f1cf80192..a8c76c889e56 100644 --- a/toolchain/semantics/semantics_ir.h +++ b/toolchain/semantics/semantics_ir.h @@ -19,14 +19,13 @@ namespace Carbon { // Provides semantic analysis on a ParseTree. class SemanticsIR { public: + SemanticsIR(const TokenizedBuffer& tokens, const ParseTree& parse_tree); + // Prints the full IR. auto Print(llvm::raw_ostream& out) const -> void; private: - friend class SemanticsIRFactory; - - explicit SemanticsIR(const ParseTree& parse_tree) - : parse_tree_(&parse_tree) {} + friend class SemanticsParseTreeHandler; auto AddIdentifier(llvm::StringRef identifier) -> SemanticsIdentifierId { SemanticsIdentifierId id(identifiers_.size()); @@ -50,8 +49,6 @@ class SemanticsIR { llvm::SmallVector identifiers_; llvm::SmallVector integer_literals_; llvm::SmallVector nodes_; - - const ParseTree* parse_tree_; }; } // namespace Carbon diff --git a/toolchain/semantics/semantics_ir_factory.cpp b/toolchain/semantics/semantics_parse_tree_handler.cpp similarity index 69% rename from toolchain/semantics/semantics_ir_factory.cpp rename to toolchain/semantics/semantics_parse_tree_handler.cpp index b7bbc325a5d4..0d885d0914db 100644 --- a/toolchain/semantics/semantics_ir_factory.cpp +++ b/toolchain/semantics/semantics_parse_tree_handler.cpp @@ -2,9 +2,7 @@ // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#include "toolchain/semantics/semantics_ir_factory.h" - -#include +#include "toolchain/semantics/semantics_parse_tree_handler.h" #include "toolchain/lexer/token_kind.h" #include "toolchain/lexer/tokenized_buffer.h" @@ -13,18 +11,11 @@ namespace Carbon { -auto SemanticsIRFactory::Build(const TokenizedBuffer& tokens, - const ParseTree& parse_tree) -> SemanticsIR { - SemanticsIRFactory builder(tokens, parse_tree); - builder.Build(); - return builder.semantics_; -} - -void SemanticsIRFactory::Build() { - auto range = parse_tree().postorder(); +auto SemanticsParseTreeHandler::Build() -> void { + auto range = parse_tree_->postorder(); for (auto it = range.begin();; ++it) { auto parse_node = *it; - switch (auto parse_kind = parse_tree().node_kind(parse_node)) { + switch (auto parse_kind = parse_tree_->node_kind(parse_node)) { case ParseNodeKind::DeclaredName(): { HandleDeclaredName(parse_node); break; @@ -41,7 +32,7 @@ void SemanticsIRFactory::Build() { ++it; CARBON_CHECK(it == range.end()) << "FileEnd should always be last, found " - << parse_tree().node_kind(*it); + << parse_tree_->node_kind(*it); return; } case ParseNodeKind::InfixOperator(): { @@ -76,43 +67,43 @@ void SemanticsIRFactory::Build() { llvm_unreachable("Should always end at FileEnd"); } -auto SemanticsIRFactory::HandleDeclaredName(ParseTree::Node parse_node) +auto SemanticsParseTreeHandler::HandleDeclaredName(ParseTree::Node parse_node) -> void { - auto text = parse_tree().GetNodeText(parse_node); - auto identifier_id = semantics_.AddIdentifier(text); + auto text = parse_tree_->GetNodeText(parse_node); + auto identifier_id = semantics_->AddIdentifier(text); Push(parse_node, SemanticsNode::MakeIdentifier(identifier_id)); } -auto SemanticsIRFactory::HandleFunctionDefinition(ParseTree::Node parse_node) - -> void { +auto SemanticsParseTreeHandler::HandleFunctionDefinition( + ParseTree::Node parse_node) -> void { // Merges code block children up under the FunctionDefinitionStart. - while (parse_tree().node_kind(node_stack_.back().parse_node) != + while (parse_tree_->node_kind(node_stack_.back().parse_node) != ParseNodeKind::FunctionDefinitionStart()) { node_stack_.pop_back(); } Pop(ParseNodeKind::FunctionDefinitionStart()); - semantics_.AddNode(SemanticsNode::MakeFunctionDefinitionEnd()); + semantics_->AddNode(SemanticsNode::MakeFunctionDefinitionEnd()); Push(parse_node); } -auto SemanticsIRFactory::HandleFunctionDefinitionStart( +auto SemanticsParseTreeHandler::HandleFunctionDefinitionStart( ParseTree::Node parse_node) -> void { Pop(ParseNodeKind::ParameterList()); auto name_node_id = PopWithResult(ParseNodeKind::DeclaredName()); Pop(ParseNodeKind::FunctionIntroducer()); auto decl_id = - semantics_.AddNode(SemanticsNode::MakeFunctionDeclaration(name_node_id)); - semantics_.AddNode(SemanticsNode::MakeFunctionDefinitionStart(decl_id)); + semantics_->AddNode(SemanticsNode::MakeFunctionDeclaration(name_node_id)); + semantics_->AddNode(SemanticsNode::MakeFunctionDefinitionStart(decl_id)); Push(parse_node); } -auto SemanticsIRFactory::HandleInfixOperator(ParseTree::Node parse_node) +auto SemanticsParseTreeHandler::HandleInfixOperator(ParseTree::Node parse_node) -> void { auto rhs_id = PopWithResult(); auto lhs_id = PopWithResult(); // Figure out the operator for the token. - auto token = parse_tree().node_token(parse_node); + auto token = parse_tree_->node_token(parse_node); switch (auto token_kind = tokens_->GetKind(token)) { case TokenKind::Plus(): Push(parse_node, SemanticsNode::MakeBinaryOperatorAdd(lhs_id, rhs_id)); @@ -122,11 +113,13 @@ auto SemanticsIRFactory::HandleInfixOperator(ParseTree::Node parse_node) } } -auto SemanticsIRFactory::HandleLiteral(ParseTree::Node parse_node) -> void { - auto token = parse_tree().node_token(parse_node); +auto SemanticsParseTreeHandler::HandleLiteral(ParseTree::Node parse_node) + -> void { + auto token = parse_tree_->node_token(parse_node); switch (auto token_kind = tokens_->GetKind(token)) { case TokenKind::IntegerLiteral(): { - auto id = semantics_.AddIntegerLiteral(tokens_->GetIntegerLiteral(token)); + auto id = + semantics_->AddIntegerLiteral(tokens_->GetIntegerLiteral(token)); Push(parse_node, SemanticsNode::MakeIntegerLiteral(id)); break; } @@ -135,7 +128,7 @@ auto SemanticsIRFactory::HandleLiteral(ParseTree::Node parse_node) -> void { } } -auto SemanticsIRFactory::HandleParameterList(ParseTree::Node parse_node) +auto SemanticsParseTreeHandler::HandleParameterList(ParseTree::Node parse_node) -> void { // TODO: This should transform into a usable parameter list. For now // it's unused and only stored so that node counts match. @@ -145,13 +138,13 @@ auto SemanticsIRFactory::HandleParameterList(ParseTree::Node parse_node) Push(parse_node); } -auto SemanticsIRFactory::HandleReturnStatement(ParseTree::Node parse_node) - -> void { +auto SemanticsParseTreeHandler::HandleReturnStatement( + ParseTree::Node parse_node) -> void { Pop(ParseNodeKind::StatementEnd()); // TODO: Restructure ReturnStatement so that we can do this without // looking at the subtree size. - if (parse_tree().node_subtree_size(parse_node) == 2) { + if (parse_tree_->node_subtree_size(parse_node) == 2) { Push(parse_node, SemanticsNode::MakeReturn()); } else { auto arg = PopWithResult(); diff --git a/toolchain/semantics/semantics_ir_factory.h b/toolchain/semantics/semantics_parse_tree_handler.h similarity index 70% rename from toolchain/semantics/semantics_ir_factory.h rename to toolchain/semantics/semantics_parse_tree_handler.h index aba86f80e899..d565e779f54a 100644 --- a/toolchain/semantics/semantics_ir_factory.h +++ b/toolchain/semantics/semantics_parse_tree_handler.h @@ -2,8 +2,8 @@ // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#ifndef CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_IR_FACTORY_H_ -#define CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_IR_FACTORY_H_ +#ifndef CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_PARSE_TREE_HANDLER_H_ +#define CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_PARSE_TREE_HANDLER_H_ #include "common/check.h" #include "toolchain/parser/parse_tree.h" @@ -11,12 +11,17 @@ namespace Carbon { -// The main semantic analysis entry. -class SemanticsIRFactory { +// Handles processing of a ParseTree for semantics. +class SemanticsParseTreeHandler { public: - // Builds the SemanticsIR without doing any substantial semantic analysis. - static auto Build(const TokenizedBuffer& tokens, const ParseTree& parse_tree) - -> SemanticsIR; + // Stores references for work. + explicit SemanticsParseTreeHandler(const TokenizedBuffer& tokens, + const ParseTree& parse_tree, + SemanticsIR& semantics) + : tokens_(&tokens), parse_tree_(&parse_tree), semantics_(&semantics) {} + + // Outputs the ParseTree information into SemanticsIR. + auto Build() -> void; private: struct TraversalStackEntry { @@ -24,24 +29,18 @@ class SemanticsIRFactory { llvm::Optional result_id; }; - explicit SemanticsIRFactory(const TokenizedBuffer& tokens, - const ParseTree& parse_tree) - : tokens_(&tokens), semantics_(parse_tree) {} - - auto Build() -> void; - auto Push(ParseTree::Node parse_node) -> void { node_stack_.push_back({parse_node, llvm::None}); } auto Push(ParseTree::Node parse_node, SemanticsNode node) -> void { - auto node_id = semantics_.AddNode(node); + auto node_id = semantics_->AddNode(node); node_stack_.push_back({parse_node, node_id}); } auto Pop(ParseNodeKind pop_parse_kind) -> void { auto back = node_stack_.back(); - auto parse_kind = parse_tree().node_kind(back.parse_node); + auto parse_kind = parse_tree_->node_kind(back.parse_node); CARBON_CHECK(parse_kind == pop_parse_kind) << "Expected " << pop_parse_kind << ", found " << parse_kind; CARBON_CHECK(!back.result_id) << "Expected no result ID on " << parse_kind; @@ -57,7 +56,7 @@ class SemanticsIRFactory { auto PopWithResult(ParseNodeKind pop_parse_kind) -> SemanticsNodeId { auto back = node_stack_.back(); - auto parse_kind = parse_tree().node_kind(back.parse_node); + auto parse_kind = parse_tree_->node_kind(back.parse_node); auto node_id = *back.result_id; CARBON_CHECK(parse_kind == pop_parse_kind) << "Expected " << pop_parse_kind << ", found " << parse_kind; @@ -74,14 +73,14 @@ class SemanticsIRFactory { auto HandleParameterList(ParseTree::Node parse_node) -> void; auto HandleReturnStatement(ParseTree::Node parse_node) -> void; - // Convenience accessor. - auto parse_tree() -> const ParseTree& { return *semantics_.parse_tree_; } - // Tokens for getting data on literals. const TokenizedBuffer* tokens_; - // The SemanticsIR being constructed. - SemanticsIR semantics_; + // The file's parse tree. + const ParseTree* parse_tree_; + + // The SemanticsIR being added to. + SemanticsIR* semantics_; // The stack during Build. Will contain file-level parse nodes on return. llvm::SmallVector node_stack_; @@ -89,4 +88,4 @@ class SemanticsIRFactory { } // namespace Carbon -#endif // CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_IR_FACTORY_H_ +#endif // CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_PARSE_TREE_HANDLER_H_