diff --git a/executable_semantics/ast/statement.cpp b/executable_semantics/ast/statement.cpp index 2ad275d4f2b1..5d4e4d69cf47 100644 --- a/executable_semantics/ast/statement.cpp +++ b/executable_semantics/ast/statement.cpp @@ -78,27 +78,14 @@ void Statement::PrintDepth(int depth, llvm::raw_ostream& out) const { } break; } - case Kind::Sequence: { - const auto& seq = cast(*this); - seq.statement().PrintDepth(depth, out); - if (depth < 0 || depth > 1) { - out << "\n"; - } else { - out << " "; - } - if (seq.next()) { - (*seq.next())->PrintDepth(depth - 1, out); - } - break; - } case Kind::Block: { const auto& block = cast(*this); out << "{"; if (depth < 0 || depth > 1) { out << "\n"; } - if (block.sequence()) { - (*block.sequence())->PrintDepth(depth, out); + for (const auto* statement : block.statements()) { + statement->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 4bbf992f1fef..bf6e391e2e6d 100644 --- a/executable_semantics/ast/statement.h +++ b/executable_semantics/ast/statement.h @@ -27,7 +27,6 @@ class Statement { VariableDefinition, If, Return, - Sequence, Block, While, Break, @@ -60,46 +59,24 @@ 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) {} + Block(SourceLocation source_loc, std::vector> statements) + : Statement(Kind::Block, source_loc), statements_(statements) {} static auto classof(const Statement* stmt) -> bool { return stmt->kind() == Kind::Block; } - auto sequence() const -> std::optional> { - return sequence_; + auto statements() const -> llvm::ArrayRef> { + return statements_; + } + auto statements() -> llvm::MutableArrayRef> { + return statements_; } - auto sequence() -> std::optional> { return sequence_; } private: - std::optional> sequence_; + std::vector> statements_; }; class ExpressionStatement : public Statement { diff --git a/executable_semantics/interpreter/exec_program.cpp b/executable_semantics/interpreter/exec_program.cpp index f74036155db8..9402a7a89b85 100644 --- a/executable_semantics/interpreter/exec_program.cpp +++ b/executable_semantics/interpreter/exec_program.cpp @@ -23,14 +23,11 @@ static void AddIntrinsics(Nonnull arena, arena->New( arena->New(source_loc)))}; auto print_return = arena->New( - source_loc, - arena->New( - source_loc, - arena->New(source_loc, - arena->New( - IntrinsicExpression::Intrinsic::Print), - false), - std::nullopt)); + source_loc, std::vector>({arena->New( + source_loc, + arena->New( + IntrinsicExpression::Intrinsic::Print), + false)})); 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 b4033d6bef88..6a58eb7ddde3 100644 --- a/executable_semantics/interpreter/interpreter.cpp +++ b/executable_semantics/interpreter/interpreter.cpp @@ -857,17 +857,20 @@ auto Interpreter::StepStmt() -> Transition { return UnwindTo{&cast(stmt).loop()}; } case Statement::Kind::Block: { - if (act->pos() == 0) { - const Block& block = cast(stmt); - if (block.sequence()) { - act->StartScope(Scope(CurrentEnv())); - return Spawn{arena_->New(*block.sequence())}; - } else { - return Done{}; - } - } else { + const auto& block = cast(stmt); + if (act->pos() >= static_cast(block.statements().size())) { + // If the position is past the end of the block, end processing. Note + // that empty blocks immediately end. return Done{}; } + // Initialize a scope when starting a block. + if (act->pos() == 0) { + act->StartScope(Scope(CurrentEnv())); + } + // Process the next statement in the block. The position will be + // incremented as part of Spawn. + return Spawn{ + arena_->New(block.statements()[act->pos()])}; } case Statement::Kind::VariableDefinition: { const auto& definition = cast(stmt); @@ -962,21 +965,6 @@ auto Interpreter::StepStmt() -> Transition { const FunctionDeclaration& function = cast(stmt).function(); return UnwindPast{*function.body(), act->results()[0]}; } - case Statement::Kind::Sequence: { - // { { (s1,s2) :: C, E, F} :: S, H} - // -> { { s1 :: s2 :: C, E, F} :: S, H} - const auto& seq = cast(stmt); - if (act->pos() == 0) { - return Spawn{arena_->New(&seq.statement())}; - } else { - if (seq.next()) { - return Delegate{ - arena_->New(*cast(stmt).next())}; - } else { - return Done{}; - } - } - } case Statement::Kind::Continuation: { CHECK(act->pos() == 0); // Create a continuation object by creating a frame similar the diff --git a/executable_semantics/interpreter/resolve_control_flow.cpp b/executable_semantics/interpreter/resolve_control_flow.cpp index f9cddf28be50..4d8c8286ece5 100644 --- a/executable_semantics/interpreter/resolve_control_flow.cpp +++ b/executable_semantics/interpreter/resolve_control_flow.cpp @@ -51,18 +51,10 @@ static void ResolveControlFlow( } return; } - case Statement::Kind::Sequence: { - auto& seq = cast(*statement); - ResolveControlFlow(&seq.statement(), function, loop); - if (seq.next().has_value()) { - ResolveControlFlow(*seq.next(), function, loop); - } - return; - } case Statement::Kind::Block: { auto& block = cast(*statement); - if (block.sequence().has_value()) { - ResolveControlFlow(*block.sequence(), function, loop); + for (auto* block_statement : block.statements()) { + ResolveControlFlow(block_statement, function, loop); } return; } diff --git a/executable_semantics/interpreter/type_checker.cpp b/executable_semantics/interpreter/type_checker.cpp index 295be2503d96..16b5240337fe 100644 --- a/executable_semantics/interpreter/type_checker.cpp +++ b/executable_semantics/interpreter/type_checker.cpp @@ -868,12 +868,12 @@ auto TypeChecker::TypeCheckStmt(Nonnull s, TypeEnv types, return TCResult(types); case Statement::Kind::Block: { auto& block = cast(*s); - if (block.sequence()) { - TypeCheckStmt(*block.sequence(), types, values, return_type_context); - return TCResult(types); - } else { - return TCResult(types); + for (auto* block_statement : block.statements()) { + auto result = + TypeCheckStmt(block_statement, types, values, return_type_context); + types = result.types; } + return TCResult(types); } case Statement::Kind::VariableDefinition: { auto& var = cast(*s); @@ -882,18 +882,6 @@ auto TypeChecker::TypeCheckStmt(Nonnull s, TypeEnv types, auto lhs_res = TypeCheckPattern(&var.pattern(), types, values, &rhs_ty); return TCResult(lhs_res.types); } - case Statement::Kind::Sequence: { - auto& seq = cast(*s); - auto stmt_res = - TypeCheckStmt(&seq.statement(), types, values, return_type_context); - auto checked_types = stmt_res.types; - if (seq.next()) { - auto next_res = TypeCheckStmt(*seq.next(), checked_types, values, - return_type_context); - checked_types = next_res.types; - } - return TCResult(checked_types); - } case Statement::Kind::Assign: { auto& assign = cast(*s); TypeCheckExp(&assign.rhs(), types, values); @@ -1003,9 +991,17 @@ void TypeChecker::ExpectReturnOnAllPaths( } return; } - case Statement::Kind::Block: - ExpectReturnOnAllPaths(cast(*stmt).sequence(), stmt->source_loc()); + case Statement::Kind::Block: { + auto& block = cast(*stmt); + if (block.statements().empty()) { + FATAL_COMPILATION_ERROR(stmt->source_loc()) + << "control-flow reaches end of function that provides a `->` " + "return type without reaching a return statement"; + } + ExpectReturnOnAllPaths(block.statements()[block.statements().size() - 1], + block.source_loc()); return; + } case Statement::Kind::If: { auto& if_stmt = cast(*stmt); ExpectReturnOnAllPaths(&if_stmt.then_block(), stmt->source_loc()); @@ -1014,15 +1010,6 @@ void TypeChecker::ExpectReturnOnAllPaths( } case Statement::Kind::Return: return; - case Statement::Kind::Sequence: { - auto& seq = cast(*stmt); - if (seq.next()) { - ExpectReturnOnAllPaths(seq.next(), stmt->source_loc()); - } else { - ExpectReturnOnAllPaths(&seq.statement(), stmt->source_loc()); - } - return; - } case Statement::Kind::Continuation: case Statement::Kind::Run: case Statement::Kind::Await: diff --git a/executable_semantics/syntax/parser.ypp b/executable_semantics/syntax/parser.ypp index ce0aead63426..4bb7e6254228 100644 --- a/executable_semantics/syntax/parser.ypp +++ b/executable_semantics/syntax/parser.ypp @@ -106,8 +106,7 @@ %type , bool>> return_expression %type > nonempty_block %type > block -%type > nonempty_statement_list -%type >> statement_list +%type >> statement_list %type > expression %type generic_binding %type > deduced_params @@ -593,9 +592,8 @@ optional_else: { $$ = std::nullopt; } | ELSE if_statement { - $$ = arena->New( - context.source_loc(), - arena->New(context.source_loc(), $2, std::nullopt)); + $$ = arena->New(context.source_loc(), + std::vector>({$2})); } | ELSE block { $$ = $2; } @@ -608,21 +606,24 @@ return_expression: ; statement_list: // Empty - { $$ = std::nullopt; } -| nonempty_statement_list - { $$ = $1; } -; -nonempty_statement_list: - statement statement_list - { $$ = arena->New(context.source_loc(), $1, $2); } + { $$ = {}; } +| statement_list statement + { + $$ = std::move($1); + $$.push_back($2); + } ; block: LEFT_CURLY_BRACE statement_list RIGHT_CURLY_BRACE - { $$ = arena->New(context.source_loc(), $2); } + { $$ = arena->New(context.source_loc(), std::move($2)); } ; nonempty_block: - LEFT_CURLY_BRACE nonempty_statement_list RIGHT_CURLY_BRACE - { $$ = arena->New(context.source_loc(), $2); } + LEFT_CURLY_BRACE statement_list statement RIGHT_CURLY_BRACE + { + $2.push_back($3); + $$ = arena->New(context.source_loc(), std::move($2)); + } +; return_type: // Empty { $$ = {arena->New(context.source_loc()), true}; }