From 25dce9fbcf748d3c28a5bbfbd156d28327c3d42c Mon Sep 17 00:00:00 2001 From: Jon Meow <46229924+jonmeow@users.noreply.github.com> Date: Wed, 29 Sep 2021 13:36:54 -0700 Subject: [PATCH] Change Match clauses from pairs to classes (#858) Updates style of the Match class at the same time. --- executable_semantics/ast/statement.cpp | 8 ++-- executable_semantics/ast/statement.h | 37 +++++++++++++------ .../interpreter/interpreter.cpp | 12 +++--- .../interpreter/type_checker.cpp | 27 +++++++------- .../interpreter/type_checker.h | 2 +- executable_semantics/syntax/parser.ypp | 14 +++---- 6 files changed, 57 insertions(+), 43 deletions(-) diff --git a/executable_semantics/ast/statement.cpp b/executable_semantics/ast/statement.cpp index 3ecc280d3b4e..4d13ce4d990b 100644 --- a/executable_semantics/ast/statement.cpp +++ b/executable_semantics/ast/statement.cpp @@ -20,12 +20,12 @@ void Statement::PrintDepth(int depth, llvm::raw_ostream& out) const { switch (Tag()) { case Kind::Match: { const auto& match = cast(*this); - out << "match (" << *match.Exp() << ") {"; + out << "match (" << match.expression() << ") {"; if (depth < 0 || depth > 1) { out << "\n"; - for (auto& clause : match.Clauses()) { - out << "case " << *clause.first << " =>\n"; - clause.second->PrintDepth(depth - 1, out); + for (auto& clause : match.clauses()) { + out << "case " << clause.pattern() << " =>\n"; + clause.statement().PrintDepth(depth - 1, out); out << "\n"; } } else { diff --git a/executable_semantics/ast/statement.h b/executable_semantics/ast/statement.h index 2544d7a3ce2f..44ee96720ef8 100644 --- a/executable_semantics/ast/statement.h +++ b/executable_semantics/ast/statement.h @@ -238,24 +238,39 @@ class Continue : public Statement { class Match : public Statement { public: - Match(SourceLocation loc, Nonnull exp, - std::vector, Nonnull>> clauses) - : Statement(Kind::Match, loc), exp(exp), clauses(std::move(clauses)) {} + class Clause { + public: + Clause(Nonnull pattern, Nonnull statement) + : pattern_(pattern), statement_(statement) {} + + auto pattern() const -> const Pattern& { return *pattern_; } + auto pattern() -> Pattern& { return *pattern_; } + auto statement() const -> const Statement& { return *statement_; } + auto statement() -> Statement& { return *statement_; } + + private: + Nonnull pattern_; + Nonnull statement_; + }; + + Match(SourceLocation loc, Nonnull expression, + std::vector clauses) + : Statement(Kind::Match, loc), + expression_(expression), + clauses_(std::move(clauses)) {} static auto classof(const Statement* stmt) -> bool { return stmt->Tag() == Kind::Match; } - auto Exp() const -> Nonnull { return exp; } - auto Exp() -> Nonnull { return exp; } - auto Clauses() const - -> llvm::ArrayRef, Nonnull>> { - return clauses; - } + auto expression() const -> const Expression& { return *expression_; } + auto expression() -> Expression& { return *expression_; } + auto clauses() const -> llvm::ArrayRef { return clauses_; } + auto clauses() -> llvm::MutableArrayRef { return clauses_; } private: - Nonnull exp; - std::vector, Nonnull>> clauses; + Nonnull expression_; + std::vector clauses_; }; // A continuation statement. diff --git a/executable_semantics/interpreter/interpreter.cpp b/executable_semantics/interpreter/interpreter.cpp index 188eae4d6b8d..d23abcc9e445 100644 --- a/executable_semantics/interpreter/interpreter.cpp +++ b/executable_semantics/interpreter/interpreter.cpp @@ -737,7 +737,7 @@ auto Interpreter::StepStmt() -> Transition { // { { (match (e) ...) :: C, E, F} :: S, H} // -> { { e :: (match ([]) ...) :: C, E, F} :: S, H} frame->scopes.Push(arena->New(CurrentEnv())); - return Spawn{arena->New(match_stmt.Exp())}; + return Spawn{arena->New(&match_stmt.expression())}; } else { // Regarding act->Pos(): // * odd: start interpreting the pattern of a clause @@ -749,31 +749,31 @@ auto Interpreter::StepStmt() -> Transition { // * 2: the pattern for clause 1 // * ... auto clause_num = (act->Pos() - 1) / 2; - if (clause_num >= static_cast(match_stmt.Clauses().size())) { + if (clause_num >= static_cast(match_stmt.clauses().size())) { DeallocateScope(frame->scopes.Top()); frame->scopes.Pop(); return Done{}; } - auto c = match_stmt.Clauses()[clause_num]; + auto c = match_stmt.clauses()[clause_num]; if (act->Pos() % 2 == 1) { // start interpreting the pattern of the clause // { {v :: (match ([]) ...) :: C, E, F} :: S, H} // -> { {pi :: (match ([]) ...) :: C, E, F} :: S, H} - return Spawn{arena->New(c.first)}; + return Spawn{arena->New(&c.pattern())}; } else { // try to match auto v = act->Results()[0]; auto pat = act->Results()[clause_num + 1]; std::optional matches = PatternMatch(pat, v, stmt->SourceLoc()); if (matches) { // we have a match, start the body // Ensure we don't process any more clauses. - act->SetPos(2 * match_stmt.Clauses().size() + 1); + act->SetPos(2 * match_stmt.clauses().size() + 1); for (const auto& [name, value] : *matches) { frame->scopes.Top()->values.Set(name, value); frame->scopes.Top()->locals.push_back(name); } - return Spawn{arena->New(c.second)}; + return Spawn{arena->New(&c.statement())}; } else { return RunAgain{}; } diff --git a/executable_semantics/interpreter/type_checker.cpp b/executable_semantics/interpreter/type_checker.cpp index 1390575467f1..0a906378ce87 100644 --- a/executable_semantics/interpreter/type_checker.cpp +++ b/executable_semantics/interpreter/type_checker.cpp @@ -631,10 +631,10 @@ auto TypeChecker::TypeCheckCase(Nonnull expected, Nonnull pat, Nonnull body, TypeEnv types, Env values, Nonnull return_type_context) - -> std::pair, Nonnull> { + -> Match::Clause { auto pat_res = TypeCheckPattern(pat, types, values, expected); auto res = TypeCheckStmt(body, pat_res.types, values, return_type_context); - return std::make_pair(pat, res.stmt); + return Match::Clause(pat, res.stmt); } auto TypeChecker::TypeCheckStmt(Nonnull s, TypeEnv types, @@ -644,13 +644,12 @@ auto TypeChecker::TypeCheckStmt(Nonnull s, TypeEnv types, switch (s->Tag()) { case Statement::Kind::Match: { auto& match = cast(*s); - auto res = TypeCheckExp(match.Exp(), types, values); + auto res = TypeCheckExp(&match.expression(), types, values); auto res_type = res.type; - std::vector, Nonnull>> - new_clauses; - for (auto& clause : match.Clauses()) { - new_clauses.push_back(TypeCheckCase(res_type, clause.first, - clause.second, types, values, + std::vector new_clauses; + for (auto& clause : match.clauses()) { + new_clauses.push_back(TypeCheckCase(res_type, &clause.pattern(), + &clause.statement(), types, values, return_type_context)); } auto new_s = arena->New(s->SourceLoc(), res.exp, new_clauses); @@ -806,14 +805,14 @@ auto TypeChecker::CheckOrEnsureReturn( switch (stmt->Tag()) { case Statement::Kind::Match: { auto& match = cast(*stmt); - std::vector, Nonnull>> - new_clauses; - for (const auto& clause : match.Clauses()) { - auto s = CheckOrEnsureReturn(clause.second, omitted_ret_type, + std::vector new_clauses; + for (auto& clause : match.clauses()) { + auto s = CheckOrEnsureReturn(&clause.statement(), omitted_ret_type, stmt->SourceLoc()); - new_clauses.push_back(std::make_pair(clause.first, s)); + new_clauses.push_back(Match::Clause(&clause.pattern(), s)); } - return arena->New(stmt->SourceLoc(), match.Exp(), new_clauses); + return arena->New(stmt->SourceLoc(), &match.expression(), + new_clauses); } case Statement::Kind::Block: return arena->New( diff --git a/executable_semantics/interpreter/type_checker.h b/executable_semantics/interpreter/type_checker.h index 10a7b0f43557..65104561403a 100644 --- a/executable_semantics/interpreter/type_checker.h +++ b/executable_semantics/interpreter/type_checker.h @@ -130,7 +130,7 @@ class TypeChecker { auto TypeCheckCase(Nonnull expected, Nonnull pat, Nonnull body, TypeEnv types, Env values, Nonnull return_type_context) - -> std::pair, Nonnull>; + -> Match::Clause; auto TypeOfFunDef(TypeEnv types, Env values, FunctionDefinition* fun_def) -> Nonnull; diff --git a/executable_semantics/syntax/parser.ypp b/executable_semantics/syntax/parser.ypp index 99d964a8f756..9ad33617daf3 100644 --- a/executable_semantics/syntax/parser.ypp +++ b/executable_semantics/syntax/parser.ypp @@ -133,8 +133,8 @@ %type > alternative %type > alternative_list %type > alternative_list_contents -%type , Nonnull>> clause -%type , Nonnull>>> clause_list +%type > clause +%type > clause_list %token // Most tokens have their spelling defined in lexer.lpp. @@ -501,13 +501,13 @@ maybe_empty_tuple_pattern: ; clause: CASE pattern DOUBLE_ARROW statement - { $$ = std::pair, Nonnull>($2, $4); } + { $$ = Match::Clause($2, $4); } | DEFAULT DOUBLE_ARROW statement { - auto vp = arena -> New( - context.SourceLoc(), std::nullopt, - arena->New(context.SourceLoc())); - $$ = std::pair, Nonnull>(vp, $3); + $$ = Match::Clause(arena->New( + context.SourceLoc(), std::nullopt, + arena->New(context.SourceLoc())), + $3); } ; clause_list: