diff --git a/executable_semantics/ast/declaration.h b/executable_semantics/ast/declaration.h index e0403c51deed..38d49fe29543 100644 --- a/executable_semantics/ast/declaration.h +++ b/executable_semantics/ast/declaration.h @@ -90,7 +90,7 @@ class FunctionDeclaration : public Declaration { Nonnull param_pattern, Nonnull return_type, bool is_omitted_return_type, - std::optional> body) + std::optional> body) : Declaration(Kind::FunctionDeclaration, source_loc), name_(std::move(name)), deduced_parameters_(std::move(deduced_params)), @@ -116,10 +116,8 @@ class FunctionDeclaration : public Declaration { auto is_omitted_return_type() const -> bool { return is_omitted_return_type_; } - auto body() const -> std::optional> { - return body_; - } - auto body() -> std::optional> { return body_; } + auto body() const -> std::optional> { return body_; } + auto body() -> std::optional> { return body_; } private: std::string name_; @@ -127,7 +125,7 @@ class FunctionDeclaration : public Declaration { Nonnull param_pattern_; Nonnull return_type_; bool is_omitted_return_type_; - std::optional> body_; + std::optional> body_; }; class ClassDeclaration : public Declaration { diff --git a/executable_semantics/ast/expression.cpp b/executable_semantics/ast/expression.cpp index 768de7788a13..26233bd19972 100644 --- a/executable_semantics/ast/expression.cpp +++ b/executable_semantics/ast/expression.cpp @@ -30,7 +30,7 @@ auto ExpressionFromParenContents( auto TupleExpressionFromParenContents( Nonnull arena, SourceLocation source_loc, - const ParenContents& paren_contents) -> Nonnull { + const ParenContents& paren_contents) -> Nonnull { return arena->New(source_loc, paren_contents.elements); } diff --git a/executable_semantics/ast/expression.h b/executable_semantics/ast/expression.h index bd7e9e2a755a..19ab1b7d450a 100644 --- a/executable_semantics/ast/expression.h +++ b/executable_semantics/ast/expression.h @@ -79,19 +79,6 @@ class Expression { std::optional> static_type_; }; -// Converts paren_contents to an Expression, interpreting the parentheses as -// grouping if their contents permit that interpretation, or as forming a -// tuple otherwise. -auto ExpressionFromParenContents( - Nonnull arena, SourceLocation source_loc, - const ParenContents& paren_contents) -> Nonnull; - -// Converts paren_contents to an Expression, interpreting the parentheses as -// forming a tuple. -auto TupleExpressionFromParenContents( - Nonnull arena, SourceLocation source_loc, - const ParenContents& paren_contents) -> Nonnull; - // A FieldInitializer represents the initialization of a single struct field. class FieldInitializer { public: @@ -450,6 +437,19 @@ class IntrinsicExpression : public Expression { Intrinsic intrinsic_; }; +// Converts paren_contents to an Expression, interpreting the parentheses as +// grouping if their contents permit that interpretation, or as forming a +// tuple otherwise. +auto ExpressionFromParenContents( + Nonnull arena, SourceLocation source_loc, + const ParenContents& paren_contents) -> Nonnull; + +// Converts paren_contents to an Expression, interpreting the parentheses as +// forming a tuple. +auto TupleExpressionFromParenContents( + Nonnull arena, SourceLocation source_loc, + const ParenContents& paren_contents) -> Nonnull; + } // namespace Carbon #endif // EXECUTABLE_SEMANTICS_AST_EXPRESSION_H_ diff --git a/executable_semantics/ast/statement.cpp b/executable_semantics/ast/statement.cpp index a2e71deded33..2ad275d4f2b1 100644 --- a/executable_semantics/ast/statement.cpp +++ b/executable_semantics/ast/statement.cpp @@ -62,10 +62,10 @@ void Statement::PrintDepth(int depth, llvm::raw_ostream& out) const { case Kind::If: { const auto& if_stmt = cast(*this); out << "if (" << if_stmt.condition() << ")\n"; - if_stmt.then_statement().PrintDepth(depth - 1, out); - if (if_stmt.else_statement()) { + if_stmt.then_block().PrintDepth(depth - 1, out); + if (if_stmt.else_block()) { out << "\nelse\n"; - (*if_stmt.else_statement())->PrintDepth(depth - 1, out); + (*if_stmt.else_block())->PrintDepth(depth - 1, out); } break; } @@ -97,8 +97,8 @@ void Statement::PrintDepth(int depth, llvm::raw_ostream& out) const { if (depth < 0 || depth > 1) { out << "\n"; } - if (block.statement()) { - (*block.statement())->PrintDepth(depth, out); + if (block.sequence()) { + (*block.sequence())->PrintDepth(depth, out); if (depth < 0 || depth > 1) { out << "\n"; } diff --git a/executable_semantics/ast/statement.h b/executable_semantics/ast/statement.h index 3c7d924df54b..4bbf992f1fef 100644 --- a/executable_semantics/ast/statement.h +++ b/executable_semantics/ast/statement.h @@ -60,6 +60,48 @@ class Statement { SourceLocation source_loc_; }; +class Sequence : public Statement { + public: + Sequence(SourceLocation source_loc, Nonnull statement, + std::optional> next) + : Statement(Kind::Sequence, source_loc), + statement_(statement), + next_(next) {} + + static auto classof(const Statement* stmt) -> bool { + return stmt->kind() == Kind::Sequence; + } + + auto statement() const -> const Statement& { return *statement_; } + auto statement() -> Statement& { return *statement_; } + auto next() const -> std::optional> { + return next_; + } + auto next() -> std::optional> { return next_; } + + private: + Nonnull statement_; + std::optional> next_; +}; + +class Block : public Statement { + public: + Block(SourceLocation source_loc, std::optional> sequence) + : Statement(Kind::Block, source_loc), sequence_(sequence) {} + + static auto classof(const Statement* stmt) -> bool { + return stmt->kind() == Kind::Block; + } + + auto sequence() const -> std::optional> { + return sequence_; + } + auto sequence() -> std::optional> { return sequence_; } + + private: + std::optional> sequence_; +}; + class ExpressionStatement : public Statement { public: ExpressionStatement(SourceLocation source_loc, @@ -123,12 +165,11 @@ class VariableDefinition : public Statement { class If : public Statement { public: If(SourceLocation source_loc, Nonnull condition, - Nonnull then_statement, - std::optional> else_statement) + Nonnull then_block, std::optional> else_block) : Statement(Kind::If, source_loc), condition_(condition), - then_statement_(then_statement), - else_statement_(else_statement) {} + then_block_(then_block), + else_block_(else_block) {} static auto classof(const Statement* stmt) -> bool { return stmt->kind() == Kind::If; @@ -136,19 +177,17 @@ class If : public Statement { auto condition() const -> const Expression& { return *condition_; } auto condition() -> Expression& { return *condition_; } - auto then_statement() const -> const Statement& { return *then_statement_; } - auto then_statement() -> Statement& { return *then_statement_; } - auto else_statement() const -> std::optional> { - return else_statement_; - } - auto else_statement() -> std::optional> { - return else_statement_; + auto then_block() const -> const Block& { return *then_block_; } + auto then_block() -> Block& { return *then_block_; } + auto else_block() const -> std::optional> { + return else_block_; } + auto else_block() -> std::optional> { return else_block_; } private: Nonnull condition_; - Nonnull then_statement_; - std::optional> else_statement_; + Nonnull then_block_; + std::optional> else_block_; }; class Return : public Statement { @@ -189,52 +228,10 @@ class Return : public Statement { std::optional> function_; }; -class Sequence : public Statement { - public: - Sequence(SourceLocation source_loc, Nonnull statement, - std::optional> next) - : Statement(Kind::Sequence, source_loc), - statement_(statement), - next_(next) {} - - static auto classof(const Statement* stmt) -> bool { - return stmt->kind() == Kind::Sequence; - } - - auto statement() const -> const Statement& { return *statement_; } - auto statement() -> Statement& { return *statement_; } - auto next() const -> std::optional> { - return next_; - } - auto next() -> std::optional> { return next_; } - - private: - Nonnull statement_; - std::optional> next_; -}; - -class Block : public Statement { - public: - Block(SourceLocation source_loc, std::optional> statement) - : Statement(Kind::Block, source_loc), statement_(statement) {} - - static auto classof(const Statement* stmt) -> bool { - return stmt->kind() == Kind::Block; - } - - auto statement() const -> std::optional> { - return statement_; - } - auto statement() -> std::optional> { return statement_; } - - private: - std::optional> statement_; -}; - class While : public Statement { public: While(SourceLocation source_loc, Nonnull condition, - Nonnull body) + Nonnull body) : Statement(Kind::While, source_loc), condition_(condition), body_(body) {} @@ -245,12 +242,12 @@ class While : public Statement { auto condition() const -> const Expression& { return *condition_; } auto condition() -> Expression& { return *condition_; } - auto body() const -> const Statement& { return *body_; } - auto body() -> Statement& { return *body_; } + auto body() const -> const Block& { return *body_; } + auto body() -> Block& { return *body_; } private: Nonnull condition_; - Nonnull body_; + Nonnull body_; }; class Break : public Statement { @@ -352,7 +349,7 @@ class Match : public Statement { class Continuation : public Statement { public: Continuation(SourceLocation source_loc, std::string continuation_variable, - Nonnull body) + Nonnull body) : Statement(Kind::Continuation, source_loc), continuation_variable_(std::move(continuation_variable)), body_(body) {} @@ -364,12 +361,12 @@ class Continuation : public Statement { auto continuation_variable() const -> const std::string& { return continuation_variable_; } - auto body() const -> const Statement& { return *body_; } - auto body() -> Statement& { return *body_; } + auto body() const -> const Block& { return *body_; } + auto body() -> Block& { return *body_; } private: std::string continuation_variable_; - Nonnull body_; + Nonnull body_; }; // A run statement. diff --git a/executable_semantics/interpreter/exec_program.cpp b/executable_semantics/interpreter/exec_program.cpp index 3a425bb0bb13..f74036155db8 100644 --- a/executable_semantics/interpreter/exec_program.cpp +++ b/executable_semantics/interpreter/exec_program.cpp @@ -22,10 +22,15 @@ static void AddIntrinsics(Nonnull arena, source_loc, "format_str", arena->New( arena->New(source_loc)))}; - auto print_return = arena->New( + auto print_return = arena->New( source_loc, - arena->New(IntrinsicExpression::Intrinsic::Print), - false); + arena->New( + source_loc, + arena->New(source_loc, + arena->New( + IntrinsicExpression::Intrinsic::Print), + false), + std::nullopt)); auto print = arena->New( source_loc, "Print", std::vector(), arena->New(source_loc, print_params), diff --git a/executable_semantics/interpreter/interpreter.cpp b/executable_semantics/interpreter/interpreter.cpp index 923a29136f3a..b4033d6bef88 100644 --- a/executable_semantics/interpreter/interpreter.cpp +++ b/executable_semantics/interpreter/interpreter.cpp @@ -859,9 +859,9 @@ auto Interpreter::StepStmt() -> Transition { case Statement::Kind::Block: { if (act->pos() == 0) { const Block& block = cast(stmt); - if (block.statement()) { + if (block.sequence()) { act->StartScope(Scope(CurrentEnv())); - return Spawn{arena_->New(*block.statement())}; + return Spawn{arena_->New(*block.sequence())}; } else { return Done{}; } @@ -937,13 +937,13 @@ auto Interpreter::StepStmt() -> Transition { // S, H} // -> { { then_stmt :: C, E, F } :: S, H} return Delegate{ - arena_->New(&cast(stmt).then_statement())}; - } else if (cast(stmt).else_statement()) { + arena_->New(&cast(stmt).then_block())}; + } else if (cast(stmt).else_block()) { // { {false :: if ([]) then_stmt else else_stmt :: C, E, F} :: // S, H} // -> { { else_stmt :: C, E, F } :: S, H} return Delegate{ - arena_->New(*cast(stmt).else_statement())}; + arena_->New(*cast(stmt).else_block())}; } else { return Done{}; } diff --git a/executable_semantics/interpreter/resolve_control_flow.cpp b/executable_semantics/interpreter/resolve_control_flow.cpp index 2ace13c31f83..f9cddf28be50 100644 --- a/executable_semantics/interpreter/resolve_control_flow.cpp +++ b/executable_semantics/interpreter/resolve_control_flow.cpp @@ -45,9 +45,9 @@ static void ResolveControlFlow( return; case Statement::Kind::If: { auto& if_stmt = cast(*statement); - ResolveControlFlow(&if_stmt.then_statement(), function, loop); - if (if_stmt.else_statement().has_value()) { - ResolveControlFlow(*if_stmt.else_statement(), function, loop); + ResolveControlFlow(&if_stmt.then_block(), function, loop); + if (if_stmt.else_block().has_value()) { + ResolveControlFlow(*if_stmt.else_block(), function, loop); } return; } @@ -61,8 +61,8 @@ static void ResolveControlFlow( } case Statement::Kind::Block: { auto& block = cast(*statement); - if (block.statement().has_value()) { - ResolveControlFlow(*block.statement(), function, loop); + if (block.sequence().has_value()) { + ResolveControlFlow(*block.sequence(), function, loop); } return; } diff --git a/executable_semantics/interpreter/type_checker.cpp b/executable_semantics/interpreter/type_checker.cpp index 801c0ca4909e..295be2503d96 100644 --- a/executable_semantics/interpreter/type_checker.cpp +++ b/executable_semantics/interpreter/type_checker.cpp @@ -868,8 +868,8 @@ auto TypeChecker::TypeCheckStmt(Nonnull s, TypeEnv types, return TCResult(types); case Statement::Kind::Block: { auto& block = cast(*s); - if (block.statement()) { - TypeCheckStmt(*block.statement(), types, values, return_type_context); + if (block.sequence()) { + TypeCheckStmt(*block.sequence(), types, values, return_type_context); return TCResult(types); } else { return TCResult(types); @@ -911,10 +911,9 @@ auto TypeChecker::TypeCheckStmt(Nonnull s, TypeEnv types, TypeCheckExp(&if_stmt.condition(), types, values); ExpectType(s->source_loc(), "condition of `if`", arena_->New(), &if_stmt.condition().static_type()); - TypeCheckStmt(&if_stmt.then_statement(), types, values, - return_type_context); - if (if_stmt.else_statement()) { - TypeCheckStmt(*if_stmt.else_statement(), types, values, + TypeCheckStmt(&if_stmt.then_block(), types, values, return_type_context); + if (if_stmt.else_block()) { + TypeCheckStmt(*if_stmt.else_block(), types, values, return_type_context); } return TCResult(types); @@ -1005,13 +1004,12 @@ void TypeChecker::ExpectReturnOnAllPaths( return; } case Statement::Kind::Block: - ExpectReturnOnAllPaths(cast(*stmt).statement(), - stmt->source_loc()); + ExpectReturnOnAllPaths(cast(*stmt).sequence(), stmt->source_loc()); return; case Statement::Kind::If: { auto& if_stmt = cast(*stmt); - ExpectReturnOnAllPaths(&if_stmt.then_statement(), stmt->source_loc()); - ExpectReturnOnAllPaths(if_stmt.else_statement(), stmt->source_loc()); + ExpectReturnOnAllPaths(&if_stmt.then_block(), stmt->source_loc()); + ExpectReturnOnAllPaths(if_stmt.else_block(), stmt->source_loc()); return; } case Statement::Kind::Return: diff --git a/executable_semantics/syntax/parser.ypp b/executable_semantics/syntax/parser.ypp index b89cbbafdff3..3aa0725134ce 100644 --- a/executable_semantics/syntax/parser.ypp +++ b/executable_semantics/syntax/parser.ypp @@ -101,13 +101,13 @@ %type > function_declaration %type >> declaration_list %type > statement -%type > if_statement -%type >> optional_else +%type > if_statement +%type >> optional_else %type , bool>> return_expression -%type > nonempty_block -%type > block -%type > nonempty_statement_list -%type >> statement_list +%type > nonempty_block +%type > block +%type > nonempty_statement_list +%type >> statement_list %type > expression %type generic_binding %type > deduced_params @@ -116,11 +116,11 @@ %type > non_expression_pattern %type , bool>> return_type %type > paren_expression -%type > struct_literal +%type > struct_literal %type > struct_literal_contents -%type > struct_type_literal +%type > struct_type_literal %type > struct_type_literal_contents -%type > tuple +%type > tuple %type > binding_lhs %type > variable_declaration %type > member @@ -577,7 +577,7 @@ statement: | MATCH LEFT_PARENTHESIS expression RIGHT_PARENTHESIS LEFT_CURLY_BRACE clause_list RIGHT_CURLY_BRACE { $$ = arena->New(context.source_loc(), $3, $6); } -| CONTINUATION identifier statement +| CONTINUATION identifier block { $$ = arena->New(context.source_loc(), $2, $3); } | RUN expression SEMICOLON { $$ = arena->New(context.source_loc(), $2); } @@ -592,7 +592,11 @@ optional_else: // Empty { $$ = std::nullopt; } | ELSE if_statement - { $$ = $2; } + { + $$ = arena->New( + context.source_loc(), + arena->New(context.source_loc(), $2, std::nullopt)); + } | ELSE block { $$ = $2; } ; diff --git a/executable_semantics/testdata/experimental_continuation/fail_continuation_syntax.carbon b/executable_semantics/testdata/experimental_continuation/fail_continuation_syntax.carbon new file mode 100644 index 000000000000..eb5ad48df164 --- /dev/null +++ b/executable_semantics/testdata/experimental_continuation/fail_continuation_syntax.carbon @@ -0,0 +1,19 @@ +// 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: not executable_semantics %s 2>&1 | \ +// RUN: FileCheck --match-full-lines --allow-unused-prefixes=false %s +// RUN: not executable_semantics --trace %s 2>&1 | \ +// RUN: FileCheck --match-full-lines --allow-unused-prefixes %s +// AUTOUPDATE: executable_semantics %s +// CHECK: COMPILATION ERROR: {{.*}}/executable_semantics/testdata/experimental_continuation/fail_continuation_syntax.carbon:16: syntax error, unexpected identifier, expecting LEFT_CURLY_BRACE + +package ExecutableSemanticsTest api; + +fn main() -> i32 { + var x: i32 = 0; + __continuation k x = 3; + __run k; + return x; +}