mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
@@ -52,4 +52,5 @@ abstract class Expression : AstNode;
|
||||
class TypeTypeLiteral : Expression;
|
||||
class IdentifierExpression : Expression;
|
||||
class IntrinsicExpression : Expression;
|
||||
class IfExpression : Expression;
|
||||
class UnimplementedExpression : Expression;
|
||||
|
||||
@@ -187,6 +187,13 @@ void Expression::Print(llvm::raw_ostream& out) const {
|
||||
}
|
||||
out << ")";
|
||||
break;
|
||||
case ExpressionKind::IfExpression: {
|
||||
const auto& if_expr = cast<IfExpression>(*this);
|
||||
out << "if " << *if_expr.condition() << " then "
|
||||
<< *if_expr.then_expression() << " else "
|
||||
<< *if_expr.else_expression();
|
||||
break;
|
||||
}
|
||||
case ExpressionKind::UnimplementedExpression: {
|
||||
const auto& unimplemented = cast<UnimplementedExpression>(*this);
|
||||
out << "UnimplementedExpression<" << unimplemented.label() << ">(";
|
||||
|
||||
@@ -490,6 +490,35 @@ class IntrinsicExpression : public Expression {
|
||||
Nonnull<TupleLiteral*> args_;
|
||||
};
|
||||
|
||||
class IfExpression : public Expression {
|
||||
public:
|
||||
explicit IfExpression(SourceLocation source_loc,
|
||||
Nonnull<Expression*> condition,
|
||||
Nonnull<Expression*> then_expression,
|
||||
Nonnull<Expression*> else_expression)
|
||||
: Expression(AstNodeKind::IfExpression, source_loc),
|
||||
condition_(condition),
|
||||
then_expression_(then_expression),
|
||||
else_expression_(else_expression) {}
|
||||
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromIfExpression(node->kind());
|
||||
}
|
||||
|
||||
auto condition() const -> Nonnull<Expression*> { return condition_; }
|
||||
auto then_expression() const -> Nonnull<Expression*> {
|
||||
return then_expression_;
|
||||
}
|
||||
auto else_expression() const -> Nonnull<Expression*> {
|
||||
return else_expression_;
|
||||
}
|
||||
|
||||
private:
|
||||
Nonnull<Expression*> condition_;
|
||||
Nonnull<Expression*> then_expression_;
|
||||
Nonnull<Expression*> else_expression_;
|
||||
};
|
||||
|
||||
// An expression whose semantics have not been implemented. This can be used
|
||||
// as a placeholder during development, in order to implement and test parsing
|
||||
// of a new expression syntax without having to implement its semantics.
|
||||
|
||||
@@ -346,6 +346,7 @@ void Interpreter::StepLvalue() {
|
||||
case ExpressionKind::StringLiteral:
|
||||
case ExpressionKind::StringTypeLiteral:
|
||||
case ExpressionKind::IntrinsicExpression:
|
||||
case ExpressionKind::IfExpression:
|
||||
FATAL() << "Can't treat expression as lvalue: " << exp;
|
||||
case ExpressionKind::UnimplementedExpression:
|
||||
FATAL() << "Unimplemented: " << exp;
|
||||
@@ -690,6 +691,21 @@ void Interpreter::StepExp() {
|
||||
CHECK(act.pos() == 0);
|
||||
return todo_.FinishAction(arena_->New<StringType>());
|
||||
}
|
||||
case ExpressionKind::IfExpression: {
|
||||
const auto& if_expr = cast<IfExpression>(exp);
|
||||
if (act.pos() == 0) {
|
||||
return todo_.Spawn(
|
||||
std::make_unique<ExpressionAction>(if_expr.condition()));
|
||||
} else if (act.pos() == 1) {
|
||||
const BoolValue& condition = cast<BoolValue>(*act.results()[0]);
|
||||
return todo_.Spawn(std::make_unique<ExpressionAction>(
|
||||
condition.value() ? if_expr.then_expression()
|
||||
: if_expr.else_expression()));
|
||||
} else {
|
||||
return todo_.FinishAction(act.results()[1]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ExpressionKind::UnimplementedExpression:
|
||||
FATAL() << "Unimplemented: " << exp;
|
||||
} // switch (exp->kind)
|
||||
|
||||
@@ -132,6 +132,13 @@ static void ResolveNames(Expression& expression,
|
||||
ResolveNames(cast<IntrinsicExpression>(expression).args(),
|
||||
enclosing_scope);
|
||||
break;
|
||||
case ExpressionKind::IfExpression: {
|
||||
auto& if_expr = cast<IfExpression>(expression);
|
||||
ResolveNames(*if_expr.condition(), enclosing_scope);
|
||||
ResolveNames(*if_expr.then_expression(), enclosing_scope);
|
||||
ResolveNames(*if_expr.else_expression(), enclosing_scope);
|
||||
break;
|
||||
}
|
||||
case ExpressionKind::BoolTypeLiteral:
|
||||
case ExpressionKind::BoolLiteral:
|
||||
case ExpressionKind::IntTypeLiteral:
|
||||
|
||||
@@ -800,6 +800,22 @@ void TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
e->set_value_category(ValueCategory::Let);
|
||||
e->set_static_type(arena_->New<TypeType>());
|
||||
return;
|
||||
case ExpressionKind::IfExpression: {
|
||||
auto& if_expr = cast<IfExpression>(*e);
|
||||
TypeCheckExp(if_expr.condition(), impl_scope);
|
||||
ExpectType(if_expr.source_loc(), "condition of `if`",
|
||||
arena_->New<BoolType>(), &if_expr.condition()->static_type());
|
||||
|
||||
// TODO: Compute the common type and convert both operands to it.
|
||||
TypeCheckExp(if_expr.then_expression(), impl_scope);
|
||||
TypeCheckExp(if_expr.else_expression(), impl_scope);
|
||||
ExpectExactType(e->source_loc(), "expression of `if` expression",
|
||||
&if_expr.then_expression()->static_type(),
|
||||
&if_expr.else_expression()->static_type());
|
||||
e->set_static_type(&if_expr.then_expression()->static_type());
|
||||
e->set_value_category(ValueCategory::Let);
|
||||
return;
|
||||
}
|
||||
case ExpressionKind::UnimplementedExpression:
|
||||
FATAL() << "Unimplemented: " << *e;
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ RUN "__run"
|
||||
SEMICOLON ";"
|
||||
SLASH "/"
|
||||
STRING "String"
|
||||
THEN "then"
|
||||
TRUE "true"
|
||||
TYPE "Type"
|
||||
UNDERSCORE "_"
|
||||
@@ -185,6 +186,7 @@ string_literal \"([^\\\"\n\v\f\r]|\\.)*\"
|
||||
{SEMICOLON} { return SIMPLE_TOKEN(SEMICOLON); }
|
||||
{SLASH} { return SIMPLE_TOKEN(SLASH); }
|
||||
{STRING} { return SIMPLE_TOKEN(STRING); }
|
||||
{THEN} { return SIMPLE_TOKEN(THEN); }
|
||||
{TRUE} { return SIMPLE_TOKEN(TRUE); }
|
||||
{TYPE} { return SIMPLE_TOKEN(TYPE); }
|
||||
{UNDERSCORE} { return SIMPLE_TOKEN(UNDERSCORE); }
|
||||
|
||||
@@ -134,6 +134,8 @@
|
||||
%type <Nonnull<Expression*>> and_expression
|
||||
%type <Nonnull<Expression*>> or_lhs
|
||||
%type <Nonnull<Expression*>> or_expression
|
||||
%type <Nonnull<Expression*>> statement_expression
|
||||
%type <Nonnull<Expression*>> if_expression
|
||||
%type <Nonnull<Expression*>> expression
|
||||
%type <Nonnull<GenericBinding*>> generic_binding
|
||||
%type <std::vector<Nonnull<AstNode*>>> deduced_params
|
||||
@@ -216,6 +218,7 @@
|
||||
SEMICOLON
|
||||
SLASH
|
||||
STRING
|
||||
THEN
|
||||
TRUE
|
||||
TYPE
|
||||
UNDERSCORE
|
||||
@@ -477,12 +480,20 @@ or_expression:
|
||||
std::vector<Nonnull<Expression*>>({$1, $3}));
|
||||
}
|
||||
;
|
||||
expression:
|
||||
statement_expression:
|
||||
ref_deref_expression
|
||||
| predicate_expression
|
||||
| and_expression
|
||||
| or_expression
|
||||
;
|
||||
if_expression:
|
||||
statement_expression
|
||||
| IF expression THEN if_expression ELSE if_expression
|
||||
{ $$ = arena->New<IfExpression>(context.source_loc(), $2, $4, $6); }
|
||||
;
|
||||
expression:
|
||||
if_expression
|
||||
;
|
||||
designator: PERIOD identifier { $$ = $2; }
|
||||
;
|
||||
paren_expression: paren_expression_base
|
||||
@@ -645,11 +656,11 @@ clause_list:
|
||||
}
|
||||
;
|
||||
statement:
|
||||
expression EQUAL expression SEMICOLON
|
||||
statement_expression EQUAL expression SEMICOLON
|
||||
{ $$ = arena->New<Assign>(context.source_loc(), $1, $3); }
|
||||
| VAR pattern EQUAL expression SEMICOLON
|
||||
{ $$ = arena->New<VariableDefinition>(context.source_loc(), $2, $4); }
|
||||
| expression SEMICOLON
|
||||
| statement_expression SEMICOLON
|
||||
{ $$ = arena->New<ExpressionStatement>(context.source_loc(), $1); }
|
||||
| if_statement
|
||||
{ $$ = $1; }
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// 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
|
||||
//
|
||||
// RUN: %{executable_semantics} %s 2>&1 | \
|
||||
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes=false %s
|
||||
// RUN: %{executable_semantics} --trace %s 2>&1 | \
|
||||
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes %s
|
||||
// AUTOUPDATE: %{executable_semantics} %s
|
||||
// CHECK: result: 12
|
||||
|
||||
package ExecutableSemanticsTest api;
|
||||
|
||||
fn Main() -> i32 {
|
||||
var cond: if true then Bool else i32 = true;
|
||||
if (if cond then true else false) {}
|
||||
while (if cond then false else true) {}
|
||||
return if if cond then true or false else false and true
|
||||
then if not cond then 1 + 2 else 3 * 4
|
||||
else if not cond then 5 + 6 else 7 * 8;
|
||||
}
|
||||
Reference in New Issue
Block a user