mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-30 22:02:41 +01:00
Semantic analysis for if expressions (#2893)
Add semantic analysis and semantics IR building for `if` expressions, and add the first parts of control flow handling to semantics IR. After discussion with @chandlerc, use [block arguments](https://en.wikipedia.org/wiki/Static_single-assignment_form#Block_arguments) to convey values from the two arms of the `if` to the result. For now, only a single block argument is supported, but we should revisit this as we explore more of the requirements of the Semantics IR form. Functions can now contain multiple code blocks, so grab the entry block up-front instead of assuming the entry block will be at the top of the block stack when we reach the end of function emission. Add trivial support for `bool` type literal, because without it we can't write testcases.
This commit is contained in:
@@ -28,8 +28,8 @@ auto ParserHandleExpression(ParserContext& context) -> void {
|
||||
}
|
||||
|
||||
if (context.PositionIs(TokenKind::If)) {
|
||||
context.PushState(ParserState::ExpressionIfFinish);
|
||||
context.PushState(ParserState::ExpressionThen);
|
||||
context.PushState(ParserState::IfExpressionFinish);
|
||||
context.PushState(ParserState::IfExpressionFinishCondition);
|
||||
} else {
|
||||
context.PushStateForExpressionLoop(ParserState::ExpressionLoopForPrefix,
|
||||
state.ambient_precedence,
|
||||
@@ -64,6 +64,7 @@ auto ParserHandleExpressionInPostfix(ParserContext& context) -> void {
|
||||
case TokenKind::IntegerLiteral:
|
||||
case TokenKind::RealLiteral:
|
||||
case TokenKind::StringLiteral:
|
||||
case TokenKind::Bool:
|
||||
case TokenKind::IntegerTypeLiteral:
|
||||
case TokenKind::UnsignedIntegerTypeLiteral:
|
||||
case TokenKind::FloatingPointTypeLiteral:
|
||||
@@ -209,12 +210,15 @@ auto ParserHandleExpressionLoopForPrefix(ParserContext& context) -> void {
|
||||
context.PushState(state);
|
||||
}
|
||||
|
||||
auto ParserHandleExpressionThen(ParserContext& context) -> void {
|
||||
auto ParserHandleIfExpressionFinishCondition(ParserContext& context) -> void {
|
||||
auto state = context.PopState();
|
||||
|
||||
if (context.ConsumeAndAddLeafNodeIf(TokenKind::Then,
|
||||
ParseNodeKind::IfExpressionThen)) {
|
||||
context.PushState(ParserState::ExpressionElse);
|
||||
context.AddNode(ParseNodeKind::IfExpressionIf, state.token,
|
||||
state.subtree_start, state.has_error);
|
||||
|
||||
if (context.PositionIs(TokenKind::Then)) {
|
||||
context.PushState(ParserState::IfExpressionFinishThen);
|
||||
context.ConsumeChecked(TokenKind::Then);
|
||||
context.PushStateForExpression(*PrecedenceGroup::ForLeading(TokenKind::If));
|
||||
} else {
|
||||
// TODO: Include the location of the `if` token.
|
||||
@@ -223,20 +227,24 @@ auto ParserHandleExpressionThen(ParserContext& context) -> void {
|
||||
if (!state.has_error) {
|
||||
context.emitter().Emit(*context.position(), ExpectedThenAfterIf);
|
||||
}
|
||||
// Add placeholders for `then expression else expression`.
|
||||
for (int i = 0; i != 4; ++i) {
|
||||
context.AddLeafNode(ParseNodeKind::InvalidParse, *context.position(),
|
||||
/*has_error=*/true);
|
||||
}
|
||||
// Add placeholders for `IfExpressionThen` and final `Expression`.
|
||||
context.AddLeafNode(ParseNodeKind::InvalidParse, *context.position(),
|
||||
/*has_error=*/true);
|
||||
context.AddLeafNode(ParseNodeKind::InvalidParse, *context.position(),
|
||||
/*has_error=*/true);
|
||||
context.ReturnErrorOnState();
|
||||
}
|
||||
}
|
||||
|
||||
auto ParserHandleExpressionElse(ParserContext& context) -> void {
|
||||
auto ParserHandleIfExpressionFinishThen(ParserContext& context) -> void {
|
||||
auto state = context.PopState();
|
||||
|
||||
if (context.ConsumeAndAddLeafNodeIf(TokenKind::Else,
|
||||
ParseNodeKind::IfExpressionElse)) {
|
||||
context.AddNode(ParseNodeKind::IfExpressionThen, state.token,
|
||||
state.subtree_start, state.has_error);
|
||||
|
||||
if (context.PositionIs(TokenKind::Else)) {
|
||||
context.PushState(ParserState::IfExpressionFinishElse);
|
||||
context.ConsumeChecked(TokenKind::Else);
|
||||
context.PushStateForExpression(*PrecedenceGroup::ForLeading(TokenKind::If));
|
||||
} else {
|
||||
// TODO: Include the location of the `if` token.
|
||||
@@ -245,20 +253,28 @@ auto ParserHandleExpressionElse(ParserContext& context) -> void {
|
||||
if (!state.has_error) {
|
||||
context.emitter().Emit(*context.position(), ExpectedElseAfterIf);
|
||||
}
|
||||
// Add placeholders for `else expression`.
|
||||
for (int i = 0; i != 2; ++i) {
|
||||
context.AddLeafNode(ParseNodeKind::InvalidParse, *context.position(),
|
||||
/*has_error=*/true);
|
||||
}
|
||||
// Add placeholder for the final `Expression`.
|
||||
context.AddLeafNode(ParseNodeKind::InvalidParse, *context.position(),
|
||||
/*has_error=*/true);
|
||||
context.ReturnErrorOnState();
|
||||
}
|
||||
}
|
||||
|
||||
auto ParserHandleExpressionIfFinish(ParserContext& context) -> void {
|
||||
auto ParserHandleIfExpressionFinishElse(ParserContext& context) -> void {
|
||||
auto else_state = context.PopState();
|
||||
|
||||
// Propagate the location of `else`.
|
||||
auto if_state = context.PopState();
|
||||
if_state.token = else_state.token;
|
||||
if_state.has_error |= else_state.has_error;
|
||||
context.PushState(if_state);
|
||||
}
|
||||
|
||||
auto ParserHandleIfExpressionFinish(ParserContext& context) -> void {
|
||||
auto state = context.PopState();
|
||||
|
||||
context.AddNode(ParseNodeKind::IfExpression, state.token, state.subtree_start,
|
||||
state.has_error);
|
||||
context.AddNode(ParseNodeKind::IfExpressionElse, state.token,
|
||||
state.subtree_start, state.has_error);
|
||||
}
|
||||
|
||||
auto ParserHandleExpressionStatementFinish(ParserContext& context) -> void {
|
||||
|
||||
Reference in New Issue
Block a user