Files
carbon-lang/toolchain/semantics/semantics_ir_factory.cpp
T
Jon Ross-Perkins 1f8508204b Rewrite semantics towards a more pure instruction model (#2320)
This rewrites semantics towards a more pure instruction model, in pursuit of the simple instruction-style output.

I think I can get this approach to type-check as it goes along, but obviously this change doesn't prove that yet. I'm separating it out because it's a large rewrite of the semantics structure, tossing out a lot of what was there before. But I think it does help towards several requests, like setting up a clear path for consolidating duplicate identifiers and making the node style more standardized.

I expect to need to pass multiple args to function calls, that'd probably be storing vectors of args similar to how I'm showing identifiers and integer literals stored.

This removes the semantics namespace because (a) it was getting annoying writing the `::` everywhere, and (b) I think the leaning with Carbon is to avoid namespaces (@chandlerc asked not to put SemanticsIR/SemanticsFactory in a namespace, which is the crux of the issue). But, it's still necessary to avoid name conflicts so I just prefix everything with "Semantics" (still a lot of typing, but no `::`).
2022-10-20 12:50:10 -07:00

131 lines
4.7 KiB
C++

// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "toolchain/semantics/semantics_ir_factory.h"
#include <stack>
#include "toolchain/lexer/token_kind.h"
#include "toolchain/lexer/tokenized_buffer.h"
#include "toolchain/parser/parse_node_kind.h"
#include "toolchain/semantics/semantics_node.h"
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();
for (auto it = range.begin();; ++it) {
auto parse_node = *it;
switch (auto parse_kind = parse_tree().node_kind(parse_node)) {
case ParseNodeKind::DeclaredName(): {
auto text = parse_tree().GetNodeText(parse_node);
auto identifier_id = semantics_.AddIdentifier(text);
Push(parse_node, SemanticsNode::MakeIdentifier(identifier_id));
break;
}
case ParseNodeKind::FunctionDefinition(): {
// Merges code block children up under the FunctionDefinitionStart.
while (parse_tree().node_kind(node_stack_.back().parse_node) !=
ParseNodeKind::FunctionDefinitionStart()) {
node_stack_.pop_back();
}
Pop(ParseNodeKind::FunctionDefinitionStart());
semantics_.AddNode(SemanticsNode::MakeFunctionDefinitionEnd());
Push(parse_node);
break;
}
case ParseNodeKind::FunctionDefinitionStart(): {
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));
Push(parse_node);
break;
}
case ParseNodeKind::FileEnd(): {
++it;
CARBON_CHECK(it == range.end())
<< "FileEnd should always be last, found "
<< parse_tree().node_kind(*it);
return;
}
case ParseNodeKind::InfixOperator(): {
auto rhs_id = PopWithResult();
auto lhs_id = PopWithResult();
// Figure out the operator for the token.
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));
break;
default:
CARBON_FATAL() << "Unrecognized token kind: " << token_kind.Name();
}
break;
}
case ParseNodeKind::Literal(): {
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));
Push(parse_node, SemanticsNode::MakeIntegerLiteral(id));
break;
}
default:
CARBON_FATAL() << "Unhandled kind: " << token_kind.Name();
}
break;
}
case ParseNodeKind::ReturnStatement(): {
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) {
Push(parse_node, SemanticsNode::MakeReturn());
} else {
auto arg = PopWithResult();
Push(parse_node, SemanticsNode::MakeReturnExpression(arg));
}
break;
}
case ParseNodeKind::ParameterList(): {
// TODO: This should transform into a usable parameter list. For now
// it's unused and only stored so that node counts match.
// TODO: Reorder with ParameterListStart so that we can traverse without
// subtree_size.
Pop(ParseNodeKind::ParameterListEnd());
Push(parse_node);
break;
}
case ParseNodeKind::FunctionIntroducer():
case ParseNodeKind::ParameterListEnd():
case ParseNodeKind::StatementEnd(): {
// The token has no action, but we still track it for the stack.
Push(parse_node);
break;
}
default: {
CARBON_FATAL() << "In ParseTree at index " << parse_node.index()
<< ", unhandled NodeKind " << parse_kind;
}
}
}
llvm_unreachable("Should always end at FileEnd");
}
} // namespace Carbon