|
@@ -6,13 +6,10 @@
|
|
|
|
|
|
|
|
#include <stack>
|
|
#include <stack>
|
|
|
|
|
|
|
|
-#include "common/check.h"
|
|
|
|
|
#include "toolchain/lexer/token_kind.h"
|
|
#include "toolchain/lexer/token_kind.h"
|
|
|
#include "toolchain/lexer/tokenized_buffer.h"
|
|
#include "toolchain/lexer/tokenized_buffer.h"
|
|
|
#include "toolchain/parser/parse_node_kind.h"
|
|
#include "toolchain/parser/parse_node_kind.h"
|
|
|
-#include "toolchain/semantics/node_ref.h"
|
|
|
|
|
-#include "toolchain/semantics/nodes/binary_operator.h"
|
|
|
|
|
-#include "toolchain/semantics/nodes/integer_literal.h"
|
|
|
|
|
|
|
+#include "toolchain/semantics/semantics_node.h"
|
|
|
|
|
|
|
|
namespace Carbon {
|
|
namespace Carbon {
|
|
|
|
|
|
|
@@ -23,107 +20,36 @@ auto SemanticsIRFactory::Build(const TokenizedBuffer& tokens,
|
|
|
return builder.semantics_;
|
|
return builder.semantics_;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// An entry in the stack for traversing the ParseTree.
|
|
|
|
|
-// TODO: This is badly structured, and a redesign may be able to get rid of
|
|
|
|
|
-// the need for `sem_ir`. Need to keep thinking about this, but for now
|
|
|
|
|
-// this setup allows for test consistency.
|
|
|
|
|
-// Alternately, maybe think about if we can group semantics for multiple nodes
|
|
|
|
|
-// so that we aren't constantly copying/reallocating vectors of NodeRefs.
|
|
|
|
|
-struct TraversalStackEntry {
|
|
|
|
|
- explicit TraversalStackEntry(ParseTree::Node parse_node)
|
|
|
|
|
- : parse_node(parse_node) {}
|
|
|
|
|
-
|
|
|
|
|
- TraversalStackEntry(ParseTree::Node parse_node,
|
|
|
|
|
- llvm::SmallVector<Semantics::NodeRef, 0> sem_ir)
|
|
|
|
|
- : parse_node(parse_node), sem_ir(std::move(sem_ir)) {}
|
|
|
|
|
-
|
|
|
|
|
- TraversalStackEntry(ParseTree::Node parse_node,
|
|
|
|
|
- llvm::SmallVector<Semantics::NodeRef, 0> sem_ir,
|
|
|
|
|
- Semantics::NodeId result_id)
|
|
|
|
|
- : parse_node(parse_node),
|
|
|
|
|
- sem_ir(std::move(sem_ir)),
|
|
|
|
|
- result_id(result_id) {}
|
|
|
|
|
-
|
|
|
|
|
- ParseTree::Node parse_node;
|
|
|
|
|
- llvm::SmallVector<Semantics::NodeRef> sem_ir;
|
|
|
|
|
- llvm::Optional<Semantics::NodeId> result_id;
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
-// Converts a TokenKind to a BinaryOperator operator.
|
|
|
|
|
-static auto GetBinaryOp(TokenKind kind) -> Semantics::BinaryOperator::Op {
|
|
|
|
|
- switch (kind) {
|
|
|
|
|
- case TokenKind::Plus():
|
|
|
|
|
- return Semantics::BinaryOperator::Op::Add;
|
|
|
|
|
- default:
|
|
|
|
|
- CARBON_FATAL() << "Unrecognized token kind: " << kind.Name();
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
void SemanticsIRFactory::Build() {
|
|
void SemanticsIRFactory::Build() {
|
|
|
- llvm::SmallVector<TraversalStackEntry> node_stack;
|
|
|
|
|
auto range = parse_tree().postorder();
|
|
auto range = parse_tree().postorder();
|
|
|
for (auto it = range.begin();; ++it) {
|
|
for (auto it = range.begin();; ++it) {
|
|
|
auto parse_node = *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(): {
|
|
case ParseNodeKind::DeclaredName(): {
|
|
|
- // DeclaredNames will be acted upon as part of the declaring construct.
|
|
|
|
|
- node_stack.push_back(TraversalStackEntry(parse_node));
|
|
|
|
|
|
|
+ auto text = parse_tree().GetNodeText(parse_node);
|
|
|
|
|
+ auto identifier_id = semantics_.AddIdentifier(text);
|
|
|
|
|
+ Push(parse_node, SemanticsNode::MakeIdentifier(identifier_id));
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
case ParseNodeKind::FunctionDefinition(): {
|
|
case ParseNodeKind::FunctionDefinition(): {
|
|
|
// Merges code block children up under the FunctionDefinitionStart.
|
|
// Merges code block children up under the FunctionDefinitionStart.
|
|
|
- llvm::SmallVector<Semantics::NodeRef> body;
|
|
|
|
|
- while (parse_tree().node_kind(node_stack.back().parse_node) !=
|
|
|
|
|
|
|
+ while (parse_tree().node_kind(node_stack_.back().parse_node) !=
|
|
|
ParseNodeKind::FunctionDefinitionStart()) {
|
|
ParseNodeKind::FunctionDefinitionStart()) {
|
|
|
- body.insert(body.begin(), node_stack.back().sem_ir.begin(),
|
|
|
|
|
- node_stack.back().sem_ir.end());
|
|
|
|
|
- node_stack.pop_back();
|
|
|
|
|
|
|
+ node_stack_.pop_back();
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // Next is the FunctionDefinitionStart.
|
|
|
|
|
- llvm::SmallVector<Semantics::NodeRef> sig =
|
|
|
|
|
- std::move(node_stack.back().sem_ir);
|
|
|
|
|
- node_stack.pop_back();
|
|
|
|
|
-
|
|
|
|
|
- // TODO: This replacement is in particular why I want to change
|
|
|
|
|
- // the IR setup now, but for now I want to just produce output that
|
|
|
|
|
- // satisfies tests without changes.
|
|
|
|
|
- auto orig_function = semantics_.nodes_.Get<Semantics::Function>(sig[0]);
|
|
|
|
|
- auto orig_set_name = semantics_.nodes_.Get<Semantics::SetName>(sig[1]);
|
|
|
|
|
- llvm::SmallVector<Semantics::NodeRef> function_sem_ir;
|
|
|
|
|
- auto function_id = next_id();
|
|
|
|
|
- function_sem_ir.push_back(semantics_.nodes_.Store(
|
|
|
|
|
- Semantics::Function(orig_function.node(), function_id, body)));
|
|
|
|
|
- function_sem_ir.push_back(semantics_.nodes_.Store(Semantics::SetName(
|
|
|
|
|
- orig_set_name.node(), orig_set_name.name(), function_id)));
|
|
|
|
|
-
|
|
|
|
|
- node_stack.push_back(
|
|
|
|
|
- TraversalStackEntry(parse_node, std::move(function_sem_ir)));
|
|
|
|
|
|
|
+ Pop(ParseNodeKind::FunctionDefinitionStart());
|
|
|
|
|
+ semantics_.AddNode(SemanticsNode::MakeFunctionDefinitionEnd());
|
|
|
|
|
+ Push(parse_node);
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
case ParseNodeKind::FunctionDefinitionStart(): {
|
|
case ParseNodeKind::FunctionDefinitionStart(): {
|
|
|
- // TODO: Skip over the parameter list for now.
|
|
|
|
|
- node_stack.pop_back();
|
|
|
|
|
-
|
|
|
|
|
- // TODO: At this point, it should be possible to forward-declare the
|
|
|
|
|
- // function so that it can be called from its code block. For now, we
|
|
|
|
|
- // just assemble the semantic function to associate the body.
|
|
|
|
|
- llvm::SmallVector<Semantics::NodeRef> sem_ir;
|
|
|
|
|
-
|
|
|
|
|
- auto function_id = next_id();
|
|
|
|
|
- sem_ir.push_back(semantics_.nodes_.Store(
|
|
|
|
|
- Semantics::Function(parse_node, function_id, {})));
|
|
|
|
|
-
|
|
|
|
|
- auto name_node = node_stack.back().parse_node;
|
|
|
|
|
- sem_ir.push_back(semantics_.nodes_.Store(Semantics::SetName(
|
|
|
|
|
- name_node, parse_tree().GetNodeText(name_node), function_id)));
|
|
|
|
|
- node_stack.pop_back();
|
|
|
|
|
-
|
|
|
|
|
- // Do nothing with the `fn`.
|
|
|
|
|
- node_stack.pop_back();
|
|
|
|
|
-
|
|
|
|
|
- node_stack.push_back(
|
|
|
|
|
- TraversalStackEntry(parse_node, std::move(sem_ir)));
|
|
|
|
|
|
|
+ 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;
|
|
break;
|
|
|
}
|
|
}
|
|
|
case ParseNodeKind::FileEnd(): {
|
|
case ParseNodeKind::FileEnd(): {
|
|
@@ -131,77 +57,48 @@ void SemanticsIRFactory::Build() {
|
|
|
CARBON_CHECK(it == range.end())
|
|
CARBON_CHECK(it == range.end())
|
|
|
<< "FileEnd should always be last, found "
|
|
<< "FileEnd should always be last, found "
|
|
|
<< parse_tree().node_kind(*it);
|
|
<< parse_tree().node_kind(*it);
|
|
|
-
|
|
|
|
|
- for (const auto& entry : node_stack) {
|
|
|
|
|
- semantics_.root_block_.append(entry.sem_ir.begin(),
|
|
|
|
|
- entry.sem_ir.end());
|
|
|
|
|
- }
|
|
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
case ParseNodeKind::InfixOperator(): {
|
|
case ParseNodeKind::InfixOperator(): {
|
|
|
- llvm::SmallVector<Semantics::NodeRef> sem_ir;
|
|
|
|
|
-
|
|
|
|
|
- sem_ir.insert(sem_ir.begin(), node_stack.back().sem_ir.begin(),
|
|
|
|
|
- node_stack.back().sem_ir.end());
|
|
|
|
|
- auto rhs_id = *node_stack.back().result_id;
|
|
|
|
|
- node_stack.pop_back();
|
|
|
|
|
-
|
|
|
|
|
- sem_ir.insert(sem_ir.begin(), node_stack.back().sem_ir.begin(),
|
|
|
|
|
- node_stack.back().sem_ir.end());
|
|
|
|
|
- auto lhs_id = *node_stack.back().result_id;
|
|
|
|
|
- node_stack.pop_back();
|
|
|
|
|
|
|
+ auto rhs_id = PopWithResult();
|
|
|
|
|
+ auto lhs_id = PopWithResult();
|
|
|
|
|
|
|
|
// Figure out the operator for the token.
|
|
// Figure out the operator for the token.
|
|
|
auto token = parse_tree().node_token(parse_node);
|
|
auto token = parse_tree().node_token(parse_node);
|
|
|
- auto token_kind = tokens_->GetKind(token);
|
|
|
|
|
- auto op = GetBinaryOp(token_kind);
|
|
|
|
|
-
|
|
|
|
|
- auto literal_id = next_id();
|
|
|
|
|
- sem_ir.push_back(semantics_.nodes_.Store(Semantics::BinaryOperator(
|
|
|
|
|
- parse_node, literal_id, op, lhs_id, rhs_id)));
|
|
|
|
|
- node_stack.push_back(
|
|
|
|
|
- TraversalStackEntry(parse_node, std::move(sem_ir), literal_id));
|
|
|
|
|
|
|
+ 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;
|
|
break;
|
|
|
}
|
|
}
|
|
|
case ParseNodeKind::Literal(): {
|
|
case ParseNodeKind::Literal(): {
|
|
|
- auto literal_id = next_id();
|
|
|
|
|
-
|
|
|
|
|
- llvm::SmallVector<Semantics::NodeRef> sem_ir;
|
|
|
|
|
auto token = parse_tree().node_token(parse_node);
|
|
auto token = parse_tree().node_token(parse_node);
|
|
|
switch (auto token_kind = tokens_->GetKind(token)) {
|
|
switch (auto token_kind = tokens_->GetKind(token)) {
|
|
|
case TokenKind::IntegerLiteral(): {
|
|
case TokenKind::IntegerLiteral(): {
|
|
|
- sem_ir.push_back(semantics_.nodes_.Store(Semantics::IntegerLiteral(
|
|
|
|
|
- parse_node, literal_id, tokens_->GetIntegerLiteral(token))));
|
|
|
|
|
|
|
+ auto id =
|
|
|
|
|
+ semantics_.AddIntegerLiteral(tokens_->GetIntegerLiteral(token));
|
|
|
|
|
+ Push(parse_node, SemanticsNode::MakeIntegerLiteral(id));
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
default:
|
|
default:
|
|
|
CARBON_FATAL() << "Unhandled kind: " << token_kind.Name();
|
|
CARBON_FATAL() << "Unhandled kind: " << token_kind.Name();
|
|
|
}
|
|
}
|
|
|
- node_stack.push_back(
|
|
|
|
|
- TraversalStackEntry(parse_node, std::move(sem_ir), literal_id));
|
|
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
case ParseNodeKind::ReturnStatement(): {
|
|
case ParseNodeKind::ReturnStatement(): {
|
|
|
- CARBON_CHECK(parse_tree().node_kind(node_stack.back().parse_node) ==
|
|
|
|
|
- ParseNodeKind::StatementEnd());
|
|
|
|
|
- node_stack.pop_back();
|
|
|
|
|
|
|
+ Pop(ParseNodeKind::StatementEnd());
|
|
|
|
|
|
|
|
// TODO: Restructure ReturnStatement so that we can do this without
|
|
// TODO: Restructure ReturnStatement so that we can do this without
|
|
|
// looking at the subtree size.
|
|
// looking at the subtree size.
|
|
|
if (parse_tree().node_subtree_size(parse_node) == 2) {
|
|
if (parse_tree().node_subtree_size(parse_node) == 2) {
|
|
|
- node_stack.push_back(TraversalStackEntry(
|
|
|
|
|
- parse_node, {semantics_.nodes_.Store(
|
|
|
|
|
- Semantics::Return(parse_node, llvm::None))}));
|
|
|
|
|
|
|
+ Push(parse_node, SemanticsNode::MakeReturn());
|
|
|
} else {
|
|
} else {
|
|
|
- // Return should only ever have one expression child.
|
|
|
|
|
- llvm::SmallVector<Semantics::NodeRef> sem_ir =
|
|
|
|
|
- std::move(node_stack.back().sem_ir);
|
|
|
|
|
- Semantics::NodeId result_id = *node_stack.back().result_id;
|
|
|
|
|
- node_stack.pop_back();
|
|
|
|
|
- sem_ir.push_back(semantics_.nodes_.Store(
|
|
|
|
|
- Semantics::Return(parse_node, result_id)));
|
|
|
|
|
- node_stack.push_back(
|
|
|
|
|
- TraversalStackEntry(parse_node, std::move(sem_ir)));
|
|
|
|
|
|
|
+ auto arg = PopWithResult();
|
|
|
|
|
+ Push(parse_node, SemanticsNode::MakeReturnExpression(arg));
|
|
|
}
|
|
}
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
@@ -210,17 +107,15 @@ void SemanticsIRFactory::Build() {
|
|
|
// it's unused and only stored so that node counts match.
|
|
// it's unused and only stored so that node counts match.
|
|
|
// TODO: Reorder with ParameterListStart so that we can traverse without
|
|
// TODO: Reorder with ParameterListStart so that we can traverse without
|
|
|
// subtree_size.
|
|
// subtree_size.
|
|
|
- CARBON_CHECK(parse_tree().node_kind(node_stack.back().parse_node) ==
|
|
|
|
|
- ParseNodeKind::ParameterListEnd());
|
|
|
|
|
- node_stack.pop_back();
|
|
|
|
|
- node_stack.push_back(TraversalStackEntry(parse_node));
|
|
|
|
|
|
|
+ Pop(ParseNodeKind::ParameterListEnd());
|
|
|
|
|
+ Push(parse_node);
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
case ParseNodeKind::FunctionIntroducer():
|
|
case ParseNodeKind::FunctionIntroducer():
|
|
|
case ParseNodeKind::ParameterListEnd():
|
|
case ParseNodeKind::ParameterListEnd():
|
|
|
case ParseNodeKind::StatementEnd(): {
|
|
case ParseNodeKind::StatementEnd(): {
|
|
|
// The token has no action, but we still track it for the stack.
|
|
// The token has no action, but we still track it for the stack.
|
|
|
- node_stack.push_back(TraversalStackEntry(parse_node));
|
|
|
|
|
|
|
+ Push(parse_node);
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
default: {
|
|
default: {
|