mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 22:02:23 +01:00
This adds a distinction between Unused and SoloParseNode, rather than equating the two. This is intended to help identify nodes which are getting pushed but maybe don't need to be. Not totally done because I want to adjust declaration name handling due to a quirk with how it mixes Name with Expression, but almost done. Once that's done the type punning will be completely gone.
140 lines
5.3 KiB
C++
140 lines
5.3 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_context.h"
|
|
|
|
namespace Carbon {
|
|
|
|
auto SemanticsHandleInfixOperator(SemanticsContext& context,
|
|
ParseTree::Node parse_node) -> bool {
|
|
auto rhs_id = context.node_stack().PopExpression();
|
|
auto lhs_id = context.node_stack().PopExpression();
|
|
|
|
// Figure out the operator for the token.
|
|
auto token = context.parse_tree().node_token(parse_node);
|
|
switch (auto token_kind = context.tokens().GetKind(token)) {
|
|
case TokenKind::Plus:
|
|
// TODO: This should search for a compatible interface. For now, it's a
|
|
// very trivial check of validity on the operation.
|
|
lhs_id = context.ImplicitAsRequired(
|
|
parse_node, lhs_id, context.semantics_ir().GetNode(rhs_id).type_id());
|
|
|
|
context.AddNodeAndPush(
|
|
parse_node,
|
|
SemanticsNode::BinaryOperatorAdd::Make(
|
|
parse_node, context.semantics_ir().GetNode(lhs_id).type_id(),
|
|
lhs_id, rhs_id));
|
|
break;
|
|
|
|
case TokenKind::And:
|
|
case TokenKind::Or: {
|
|
// The first operand is wrapped in a ShortCircuitOperand, which we
|
|
// already handled by creating a RHS block and a resumption block, which
|
|
// are the current block and its enclosing block.
|
|
rhs_id = context.ImplicitAsBool(parse_node, rhs_id);
|
|
|
|
// When the second operand is evaluated, the result of `and` and `or` is
|
|
// its value.
|
|
auto rhs_block_id = context.node_block_stack().PopForAdd();
|
|
auto resume_block_id = context.node_block_stack().PeekForAdd();
|
|
context.AddNodeToBlock(rhs_block_id,
|
|
SemanticsNode::BranchWithArg::Make(
|
|
parse_node, resume_block_id, rhs_id));
|
|
context.AddCurrentCodeBlockToFunction();
|
|
|
|
// Collect the result from either the first or second operand.
|
|
context.AddNodeAndPush(
|
|
parse_node,
|
|
SemanticsNode::BlockArg::Make(
|
|
parse_node, context.semantics_ir().GetNode(rhs_id).type_id(),
|
|
resume_block_id));
|
|
break;
|
|
}
|
|
|
|
default:
|
|
return context.TODO(parse_node, llvm::formatv("Handle {0}", token_kind));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
auto SemanticsHandlePostfixOperator(SemanticsContext& context,
|
|
ParseTree::Node parse_node) -> bool {
|
|
return context.TODO(parse_node, "HandlePostfixOperator");
|
|
}
|
|
|
|
auto SemanticsHandlePrefixOperator(SemanticsContext& context,
|
|
ParseTree::Node parse_node) -> bool {
|
|
auto value_id = context.node_stack().PopExpression();
|
|
|
|
// Figure out the operator for the token.
|
|
auto token = context.parse_tree().node_token(parse_node);
|
|
switch (auto token_kind = context.tokens().GetKind(token)) {
|
|
case TokenKind::Not:
|
|
value_id = context.ImplicitAsBool(parse_node, value_id);
|
|
context.AddNodeAndPush(
|
|
parse_node,
|
|
SemanticsNode::UnaryOperatorNot::Make(
|
|
parse_node, context.semantics_ir().GetNode(value_id).type_id(),
|
|
value_id));
|
|
break;
|
|
|
|
default:
|
|
return context.TODO(parse_node, llvm::formatv("Handle {0}", token_kind));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
auto SemanticsHandleShortCircuitOperand(SemanticsContext& context,
|
|
ParseTree::Node parse_node) -> bool {
|
|
// Convert the condition to `bool`.
|
|
auto cond_value_id = context.node_stack().PopExpression();
|
|
cond_value_id = context.ImplicitAsBool(parse_node, cond_value_id);
|
|
auto bool_type_id = context.semantics_ir().GetNode(cond_value_id).type_id();
|
|
|
|
// Compute the branch value: the condition for `and`, inverted for `or`.
|
|
auto token = context.parse_tree().node_token(parse_node);
|
|
SemanticsNodeId branch_value_id = SemanticsNodeId::Invalid;
|
|
auto short_circuit_result_id = SemanticsNodeId::Invalid;
|
|
switch (auto token_kind = context.tokens().GetKind(token)) {
|
|
case TokenKind::And:
|
|
branch_value_id = cond_value_id;
|
|
short_circuit_result_id =
|
|
context.AddNode(SemanticsNode::BoolLiteral::Make(
|
|
parse_node, bool_type_id, SemanticsBoolValue::False));
|
|
break;
|
|
|
|
case TokenKind::Or:
|
|
branch_value_id = context.AddNode(SemanticsNode::UnaryOperatorNot::Make(
|
|
parse_node, bool_type_id, cond_value_id));
|
|
short_circuit_result_id =
|
|
context.AddNode(SemanticsNode::BoolLiteral::Make(
|
|
parse_node, bool_type_id, SemanticsBoolValue::True));
|
|
break;
|
|
|
|
default:
|
|
CARBON_FATAL() << "Unexpected short-circuiting operator " << parse_node;
|
|
}
|
|
|
|
// Create a block for the right-hand side and for the continuation.
|
|
auto rhs_block_id =
|
|
context.AddDominatedBlockAndBranchIf(parse_node, branch_value_id);
|
|
auto end_block_id = context.AddDominatedBlockAndBranchWithArg(
|
|
parse_node, short_circuit_result_id);
|
|
|
|
// Push the resumption and the right-hand side blocks, and start emitting the
|
|
// right-hand operand.
|
|
context.node_block_stack().Pop();
|
|
context.node_block_stack().Push(end_block_id);
|
|
context.node_block_stack().Push(rhs_block_id);
|
|
context.AddCurrentCodeBlockToFunction();
|
|
|
|
// Put the condition back on the stack for SemanticsHandleInfixOperator.
|
|
context.node_stack().Push(parse_node, cond_value_id);
|
|
return true;
|
|
}
|
|
|
|
} // namespace Carbon
|