Working on toolchain semantics:

- SemanticsIR is set up as a container for the semantic tree.
- SemanticsIRFactory builds the tree, with separate transformations for each ParseNodeKind.
- ParseSubtreeConsumer is a helper for transforming a ParseTree::Node's children, managing size/nodes to prevent errors.
- The nodes subdirectory contains SemanticIR nodes.
- MetaNode is used to represent nodes which have "sub-classes": Statements, Declarations, and Expressions.
- MetaNodeBlock is used to represent nodes which exist together in a block with name lookup: Statements and Declarations (not Expressions).

This is traversing children first in order to address the RPO format of ParseTree. This means that when lists are formed, they're reversed to be in code-order (`FixReverseOrdering`).

This is still very much incomplete -- the main intent at present is to demonstrate structure.
This commit is contained in:
Jon Ross-Perkins
2022-06-15 12:40:07 -07:00
committed by GitHub
parent 9512a9fcc1
commit 4113ec8a67
31 changed files with 1532 additions and 143 deletions
+191 -28
View File
@@ -4,55 +4,218 @@
#include "toolchain/semantics/semantics_ir_factory.h"
#include <stack>
#include "common/check.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/FormatVariadic.h"
#include "toolchain/lexer/tokenized_buffer.h"
#include "toolchain/parser/parse_node_kind.h"
#include "toolchain/semantics/meta_node_block.h"
#include "toolchain/semantics/nodes/expression_statement.h"
#include "toolchain/semantics/parse_subtree_consumer.h"
namespace Carbon {
// The ParseTree is walked in reverse post order, meaning a lot of nodes are
// added in reverse. This fixes that ordering to be the easier to understand
// code ordering.
template <typename T>
static void FixReverseOrdering(T& container) {
std::reverse(container.begin(), container.end());
}
auto SemanticsIRFactory::Build(const ParseTree& parse_tree) -> SemanticsIR {
SemanticsIRFactory builder(parse_tree);
builder.ProcessRoots();
builder.Build();
return builder.semantics_;
}
void SemanticsIRFactory::ProcessRoots() {
for (ParseTree::Node node : semantics_.parse_tree_->roots()) {
switch (semantics_.parse_tree_->node_kind(node)) {
case ParseNodeKind::FunctionDeclaration():
ProcessFunctionNode(semantics_.root_block_, node);
void SemanticsIRFactory::Build() {
auto subtree = ParseSubtreeConsumer::ForTree(parse_tree());
// FileEnd is a placeholder node which can be discarded.
RequireNodeEmpty(subtree.RequireConsume(ParseNodeKind::FileEnd()));
llvm::SmallVector<Semantics::Declaration, 0> nodes;
llvm::StringMap<Semantics::Declaration> name_lookup;
while (llvm::Optional<ParseTree::Node> node = subtree.TryConsume()) {
switch (auto node_kind = parse_tree().node_kind(*node)) {
case ParseNodeKind::FunctionDeclaration(): {
auto [name, decl] = TransformFunctionDeclaration(*node);
nodes.push_back(decl);
name_lookup[name] = decl;
break;
case ParseNodeKind::FileEnd():
// No action needed.
}
default:
CARBON_FATAL() << "At index " << node->index() << ", unexpected "
<< node_kind;
}
}
FixReverseOrdering(nodes);
semantics_.root_block_ =
Semantics::DeclarationBlock(std::move(nodes), std::move(name_lookup));
}
void SemanticsIRFactory::RequireNodeEmpty(ParseTree::Node node) {
auto subtree_size = parse_tree().node_subtree_size(node);
CARBON_CHECK(subtree_size == 1)
<< "At index " << node.index() << ", expected "
<< parse_tree().node_kind(node)
<< "would have subtree_size of 1, but was " << subtree_size;
}
auto SemanticsIRFactory::TransformCodeBlock(ParseTree::Node node)
-> Semantics::StatementBlock {
CARBON_CHECK(parse_tree().node_kind(node) == ParseNodeKind::CodeBlock());
auto subtree = ParseSubtreeConsumer::ForParent(parse_tree(), node);
RequireNodeEmpty(subtree.RequireConsume(ParseNodeKind::CodeBlockEnd()));
llvm::SmallVector<Semantics::Statement, 0> nodes;
while (llvm::Optional<ParseTree::Node> child = subtree.TryConsume()) {
switch (auto child_kind = parse_tree().node_kind(*child)) {
case ParseNodeKind::ExpressionStatement():
nodes.push_back(TransformExpressionStatement(*child));
break;
case ParseNodeKind::ReturnStatement():
nodes.push_back(TransformReturnStatement(*child));
break;
case ParseNodeKind::VariableDeclaration():
// TODO: Handle.
break;
default:
CARBON_FATAL() << "Unhandled node kind: "
<< semantics_.parse_tree_->node_kind(node).name();
CARBON_FATAL() << "At index " << child->index() << ", unexpected "
<< child_kind;
}
}
FixReverseOrdering(nodes);
return Semantics::StatementBlock(std::move(nodes),
/*name_lookup=*/{});
}
auto SemanticsIRFactory::TransformDeclaredName(ParseTree::Node node)
-> Semantics::DeclaredName {
CARBON_CHECK(parse_tree().node_kind(node) == ParseNodeKind::DeclaredName());
RequireNodeEmpty(node);
return Semantics::DeclaredName(node);
}
auto SemanticsIRFactory::TransformExpression(ParseTree::Node node)
-> Semantics::Expression {
switch (auto node_kind = parse_tree().node_kind(node)) {
case ParseNodeKind::Literal():
RequireNodeEmpty(node);
return semantics_.expressions_.Store(Semantics::Literal(node));
case ParseNodeKind::InfixOperator():
return semantics_.expressions_.Store(TransformInfixOperator(node));
default:
CARBON_FATAL() << "At index " << node.index() << ", unexpected "
<< node_kind;
break;
}
}
void SemanticsIRFactory::ProcessFunctionNode(SemanticsIR::Block& block,
ParseTree::Node decl_node) {
llvm::Optional<Semantics::Function> fn;
for (ParseTree::Node node : semantics_.parse_tree_->children(decl_node)) {
switch (semantics_.parse_tree_->node_kind(node)) {
case ParseNodeKind::DeclaredName():
fn = semantics_.AddFunction(block, decl_node, node);
break;
case ParseNodeKind::ParameterList():
// TODO: Maybe something like Semantics::AddVariable passed to
// Function::AddParameter.
break;
case ParseNodeKind::CodeBlock():
// TODO: Should accumulate the definition into the code block.
break;
default:
CARBON_FATAL() << "Unhandled node kind: "
<< semantics_.parse_tree_->node_kind(node).name();
auto SemanticsIRFactory::TransformExpressionStatement(ParseTree::Node node)
-> Semantics::Statement {
CARBON_CHECK(parse_tree().node_kind(node) ==
ParseNodeKind::ExpressionStatement());
auto subtree = ParseSubtreeConsumer::ForParent(parse_tree(), node);
RequireNodeEmpty(subtree.RequireConsume(ParseNodeKind::StatementEnd()));
return semantics_.statements_.Store(Semantics::ExpressionStatement(
TransformExpression(subtree.RequireConsume())));
}
auto SemanticsIRFactory::TransformFunctionDeclaration(ParseTree::Node node)
-> std::tuple<llvm::StringRef, Semantics::Declaration> {
CARBON_CHECK(parse_tree().node_kind(node) ==
ParseNodeKind::FunctionDeclaration());
auto subtree = ParseSubtreeConsumer::ForParent(parse_tree(), node);
auto body =
TransformCodeBlock(subtree.RequireConsume(ParseNodeKind::CodeBlock()));
llvm::Optional<Semantics::Expression> return_type_expr;
if (auto return_type_node = subtree.TryConsume(ParseNodeKind::ReturnType())) {
return_type_expr = TransformReturnType(*return_type_node);
}
auto params = TransformParameterList(
subtree.RequireConsume(ParseNodeKind::ParameterList()));
auto name = TransformDeclaredName(
subtree.RequireConsume(ParseNodeKind::DeclaredName()));
auto decl = semantics_.declarations_.Store(
Semantics::Function(node, name, params, return_type_expr, body));
return std::make_tuple(parse_tree().GetNodeText(name.node()), decl);
}
auto SemanticsIRFactory::TransformInfixOperator(ParseTree::Node node)
-> Semantics::InfixOperator {
CARBON_CHECK(parse_tree().node_kind(node) == ParseNodeKind::InfixOperator());
auto subtree = ParseSubtreeConsumer::ForParent(parse_tree(), node);
auto rhs = TransformExpression(subtree.RequireConsume());
auto lhs = TransformExpression(subtree.RequireConsume());
return Semantics::InfixOperator(node, lhs, rhs);
}
auto SemanticsIRFactory::TransformParameterList(ParseTree::Node node)
-> llvm::SmallVector<Semantics::PatternBinding, 0> {
CARBON_CHECK(parse_tree().node_kind(node) == ParseNodeKind::ParameterList());
auto subtree = ParseSubtreeConsumer::ForParent(parse_tree(), node);
RequireNodeEmpty(subtree.RequireConsume(ParseNodeKind::ParameterListEnd()));
llvm::SmallVector<Semantics::PatternBinding, 0> params;
if (auto first_param_node =
subtree.TryConsume(ParseNodeKind::PatternBinding())) {
params.push_back(TransformPatternBinding(*first_param_node));
while (auto comma_node =
subtree.TryConsume(ParseNodeKind::ParameterListComma())) {
RequireNodeEmpty(*comma_node);
params.push_back(TransformPatternBinding(
subtree.RequireConsume(ParseNodeKind::PatternBinding())));
}
}
FixReverseOrdering(params);
return params;
}
auto SemanticsIRFactory::TransformPatternBinding(ParseTree::Node node)
-> Semantics::PatternBinding {
CARBON_CHECK(parse_tree().node_kind(node) == ParseNodeKind::PatternBinding());
auto subtree = ParseSubtreeConsumer::ForParent(parse_tree(), node);
auto type = TransformExpression(subtree.RequireConsume());
auto name = TransformDeclaredName(
subtree.RequireConsume(ParseNodeKind::DeclaredName()));
return Semantics::PatternBinding(node, name, type);
}
auto SemanticsIRFactory::TransformReturnStatement(ParseTree::Node node)
-> Semantics::Statement {
CARBON_CHECK(parse_tree().node_kind(node) ==
ParseNodeKind::ReturnStatement());
auto subtree = ParseSubtreeConsumer::ForParent(parse_tree(), node);
RequireNodeEmpty(subtree.RequireConsume(ParseNodeKind::StatementEnd()));
auto expr = subtree.TryConsume();
if (expr) {
// return expr;
return semantics_.statements_.Store(
Semantics::Return(node, TransformExpression(*expr)));
} else {
// return;
return semantics_.statements_.Store(Semantics::Return(node, llvm::None));
}
}
auto SemanticsIRFactory::TransformReturnType(ParseTree::Node node)
-> Semantics::Expression {
CARBON_CHECK(parse_tree().node_kind(node) == ParseNodeKind::ReturnType());
auto subtree = ParseSubtreeConsumer::ForParent(parse_tree(), node);
return TransformExpression(subtree.RequireConsume());
}
} // namespace Carbon