Jelajahi Sumber

Change Match clauses from pairs to classes (#858)

Updates style of the Match class at the same time.
Jon Meow 4 tahun lalu
induk
melakukan
25dce9fbcf

+ 4 - 4
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<Match>(*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 {

+ 26 - 11
executable_semantics/ast/statement.h

@@ -238,24 +238,39 @@ class Continue : public Statement {
 
 class Match : public Statement {
  public:
-  Match(SourceLocation loc, Nonnull<Expression*> exp,
-        std::vector<std::pair<Nonnull<Pattern*>, Nonnull<Statement*>>> clauses)
-      : Statement(Kind::Match, loc), exp(exp), clauses(std::move(clauses)) {}
+  class Clause {
+   public:
+    Clause(Nonnull<Pattern*> pattern, Nonnull<Statement*> 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*> pattern_;
+    Nonnull<Statement*> statement_;
+  };
+
+  Match(SourceLocation loc, Nonnull<Expression*> expression,
+        std::vector<Clause> 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<const Expression*> { return exp; }
-  auto Exp() -> Nonnull<Expression*> { return exp; }
-  auto Clauses() const
-      -> llvm::ArrayRef<std::pair<Nonnull<Pattern*>, Nonnull<Statement*>>> {
-    return clauses;
-  }
+  auto expression() const -> const Expression& { return *expression_; }
+  auto expression() -> Expression& { return *expression_; }
+  auto clauses() const -> llvm::ArrayRef<Clause> { return clauses_; }
+  auto clauses() -> llvm::MutableArrayRef<Clause> { return clauses_; }
 
  private:
-  Nonnull<Expression*> exp;
-  std::vector<std::pair<Nonnull<Pattern*>, Nonnull<Statement*>>> clauses;
+  Nonnull<Expression*> expression_;
+  std::vector<Clause> clauses_;
 };
 
 // A continuation statement.

+ 6 - 6
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<Scope>(CurrentEnv()));
-        return Spawn{arena->New<ExpressionAction>(match_stmt.Exp())};
+        return Spawn{arena->New<ExpressionAction>(&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<int>(match_stmt.Clauses().size())) {
+        if (clause_num >= static_cast<int>(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<PatternAction>(c.first)};
+          return Spawn{arena->New<PatternAction>(&c.pattern())};
         } else {  // try to match
           auto v = act->Results()[0];
           auto pat = act->Results()[clause_num + 1];
           std::optional<Env> 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<StatementAction>(c.second)};
+            return Spawn{arena->New<StatementAction>(&c.statement())};
           } else {
             return RunAgain{};
           }

+ 13 - 14
executable_semantics/interpreter/type_checker.cpp

@@ -631,10 +631,10 @@ auto TypeChecker::TypeCheckCase(Nonnull<const Value*> expected,
                                 Nonnull<Pattern*> pat, Nonnull<Statement*> body,
                                 TypeEnv types, Env values,
                                 Nonnull<ReturnTypeContext*> return_type_context)
-    -> std::pair<Nonnull<Pattern*>, Nonnull<Statement*>> {
+    -> 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<Statement*> s, TypeEnv types,
@@ -644,13 +644,12 @@ auto TypeChecker::TypeCheckStmt(Nonnull<Statement*> s, TypeEnv types,
   switch (s->Tag()) {
     case Statement::Kind::Match: {
       auto& match = cast<Match>(*s);
-      auto res = TypeCheckExp(match.Exp(), types, values);
+      auto res = TypeCheckExp(&match.expression(), types, values);
       auto res_type = res.type;
-      std::vector<std::pair<Nonnull<Pattern*>, Nonnull<Statement*>>>
-          new_clauses;
-      for (auto& clause : match.Clauses()) {
-        new_clauses.push_back(TypeCheckCase(res_type, clause.first,
-                                            clause.second, types, values,
+      std::vector<Match::Clause> 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<Match>(s->SourceLoc(), res.exp, new_clauses);
@@ -806,14 +805,14 @@ auto TypeChecker::CheckOrEnsureReturn(
   switch (stmt->Tag()) {
     case Statement::Kind::Match: {
       auto& match = cast<Match>(*stmt);
-      std::vector<std::pair<Nonnull<Pattern*>, Nonnull<Statement*>>>
-          new_clauses;
-      for (const auto& clause : match.Clauses()) {
-        auto s = CheckOrEnsureReturn(clause.second, omitted_ret_type,
+      std::vector<Match::Clause> 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<Match>(stmt->SourceLoc(), match.Exp(), new_clauses);
+      return arena->New<Match>(stmt->SourceLoc(), &match.expression(),
+                               new_clauses);
     }
     case Statement::Kind::Block:
       return arena->New<Block>(

+ 1 - 1
executable_semantics/interpreter/type_checker.h

@@ -130,7 +130,7 @@ class TypeChecker {
   auto TypeCheckCase(Nonnull<const Value*> expected, Nonnull<Pattern*> pat,
                      Nonnull<Statement*> body, TypeEnv types, Env values,
                      Nonnull<ReturnTypeContext*> return_type_context)
-      -> std::pair<Nonnull<Pattern*>, Nonnull<Statement*>>;
+      -> Match::Clause;
 
   auto TypeOfFunDef(TypeEnv types, Env values, FunctionDefinition* fun_def)
       -> Nonnull<const Value*>;

+ 7 - 7
executable_semantics/syntax/parser.ypp

@@ -133,8 +133,8 @@
 %type <BisonWrap<ChoiceDeclaration::Alternative>> alternative
 %type <std::vector<ChoiceDeclaration::Alternative>> alternative_list
 %type <std::vector<ChoiceDeclaration::Alternative>> alternative_list_contents
-%type <std::pair<Nonnull<Pattern*>, Nonnull<Statement*>>> clause
-%type <std::vector<std::pair<Nonnull<Pattern*>, Nonnull<Statement*>>>> clause_list
+%type <BisonWrap<Match::Clause>> clause
+%type <std::vector<Match::Clause>> 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<Pattern*>, Nonnull<Statement*>>($2, $4); }
+    { $$ = Match::Clause($2, $4); }
 | DEFAULT DOUBLE_ARROW statement
     {
-      auto vp = arena -> New<BindingPattern>(
-                    context.SourceLoc(), std::nullopt,
-                    arena->New<AutoPattern>(context.SourceLoc()));
-      $$ = std::pair<Nonnull<Pattern*>, Nonnull<Statement*>>(vp, $3);
+      $$ = Match::Clause(arena->New<BindingPattern>(
+                             context.SourceLoc(), std::nullopt,
+                             arena->New<AutoPattern>(context.SourceLoc())),
+                         $3);
     }
 ;
 clause_list: