浏览代码

Switch Member to use inheritance+cast (#713)

Jon Meow 4 年之前
父节点
当前提交
4e0307efbc

+ 6 - 15
executable_semantics/ast/member.cpp

@@ -5,26 +5,17 @@
 #include "executable_semantics/ast/member.h"
 #include "executable_semantics/ast/member.h"
 
 
 #include "executable_semantics/common/arena.h"
 #include "executable_semantics/common/arena.h"
+#include "llvm/Support/Casting.h"
 
 
 namespace Carbon {
 namespace Carbon {
 
 
-auto Member::MakeFieldMember(int line_num, const BindingPattern* binding)
-    -> Member* {
-  auto m = global_arena->New<Member>();
-  m->line_num = line_num;
-  m->value = FieldMember({.binding = binding});
-  return m;
-}
-
-auto Member::GetFieldMember() const -> const FieldMember& {
-  return std::get<FieldMember>(value);
-}
+using llvm::cast;
 
 
 void Member::Print(llvm::raw_ostream& out) const {
 void Member::Print(llvm::raw_ostream& out) const {
-  switch (tag()) {
-    case MemberKind::FieldMember:
-      const auto& field = GetFieldMember();
-      out << "var " << field.binding << ";\n";
+  switch (Tag()) {
+    case Kind::FieldMember:
+      const auto& field = cast<FieldMember>(*this);
+      out << "var " << field.Binding() << ";\n";
       break;
       break;
   }
   }
 }
 }

+ 40 - 17
executable_semantics/ast/member.h

@@ -14,33 +14,56 @@
 
 
 namespace Carbon {
 namespace Carbon {
 
 
-enum class MemberKind { FieldMember };
+// Abstract base class of all AST nodes representing patterns.
+//
+// Member and its derived classes support LLVM-style RTTI, including
+// llvm::isa, llvm::cast, and llvm::dyn_cast. To support this, every
+// class derived from Member must provide a `classof` operation, and
+// every concrete derived class must have a corresponding enumerator
+// in `Kind`; see https://llvm.org/docs/HowToSetUpLLVMStyleRTTI.html for
+// details.
+class Member {
+ public:
+  enum class Kind { FieldMember };
 
 
-struct FieldMember {
-  static constexpr MemberKind Kind = MemberKind::FieldMember;
-  // TODO: split this into a non-optional name and a type, initialized by
-  // a constructor that takes a BindingPattern and handles errors like a
-  // missing name.
-  const BindingPattern* binding;
-};
+  Member(const Member&) = delete;
+  Member& operator=(const Member&) = delete;
 
 
-struct Member {
-  static auto MakeFieldMember(int line_num, const BindingPattern* binding)
-      -> Member*;
+  // Returns the enumerator corresponding to the most-derived type of this
+  // object.
+  auto Tag() const -> Kind { return tag; }
 
 
-  auto GetFieldMember() const -> const FieldMember&;
+  auto LineNumber() const -> int { return line_num; }
 
 
   void Print(llvm::raw_ostream& out) const;
   void Print(llvm::raw_ostream& out) const;
-  LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); }
 
 
-  inline auto tag() const -> MemberKind {
-    return std::visit([](const auto& t) { return t.Kind; }, value);
-  }
+ protected:
+  // Constructs a Member representing syntax at the given line number.
+  // `tag` must be the enumerator corresponding to the most-derived type being
+  // constructed.
+  Member(Kind tag, int line_num) : tag(tag), line_num(line_num) {}
 
 
+ private:
+  const Kind tag;
   int line_num;
   int line_num;
+};
+
+class FieldMember : public Member {
+ public:
+  FieldMember(int line_num, const BindingPattern* binding)
+      : Member(Kind::FieldMember, line_num), binding(binding) {}
+
+  static auto classof(const Member* member) -> bool {
+    return member->Tag() == Kind::FieldMember;
+  }
+
+  auto Binding() const -> const BindingPattern* { return binding; }
 
 
  private:
  private:
-  std::variant<FieldMember> value;
+  // TODO: split this into a non-optional name and a type, initialized by
+  // a constructor that takes a BindingPattern and handles errors like a
+  // missing name.
+  const BindingPattern* binding;
 };
 };
 
 
 }  // namespace Carbon
 }  // namespace Carbon

+ 3 - 3
executable_semantics/interpreter/interpreter.cpp

@@ -132,9 +132,9 @@ void InitEnv(const Declaration& d, Env* env) {
       VarValues fields;
       VarValues fields;
       VarValues methods;
       VarValues methods;
       for (const Member* m : struct_def.members) {
       for (const Member* m : struct_def.members) {
-        switch (m->tag()) {
-          case MemberKind::FieldMember: {
-            const BindingPattern* binding = m->GetFieldMember().binding;
+        switch (m->Tag()) {
+          case Member::Kind::FieldMember: {
+            const BindingPattern* binding = cast<FieldMember>(*m).Binding();
             const Expression* type_expression =
             const Expression* type_expression =
                 cast<ExpressionPattern>(binding->Type())->Expression();
                 cast<ExpressionPattern>(binding->Type())->Expression();
             auto type = InterpExp(Env(), type_expression);
             auto type = InterpExp(Env(), type_expression);

+ 5 - 5
executable_semantics/interpreter/typecheck.cpp

@@ -896,9 +896,9 @@ static auto TypeOfStructDef(const StructDefinition* sd, TypeEnv /*types*/,
   VarValues fields;
   VarValues fields;
   VarValues methods;
   VarValues methods;
   for (const Member* m : sd->members) {
   for (const Member* m : sd->members) {
-    switch (m->tag()) {
-      case MemberKind::FieldMember: {
-        const BindingPattern* binding = m->GetFieldMember().binding;
+    switch (m->Tag()) {
+      case Member::Kind::FieldMember: {
+        const BindingPattern* binding = cast<FieldMember>(*m).Binding();
         if (!binding->Name().has_value()) {
         if (!binding->Name().has_value()) {
           FATAL_COMPILATION_ERROR(binding->LineNumber())
           FATAL_COMPILATION_ERROR(binding->LineNumber())
               << "Struct members must have names";
               << "Struct members must have names";
@@ -950,8 +950,8 @@ auto MakeTypeChecked(const Declaration& d, const TypeEnv& types,
           cast<StructDeclaration>(d).Definition();
           cast<StructDeclaration>(d).Definition();
       std::list<Member*> fields;
       std::list<Member*> fields;
       for (Member* m : struct_def.members) {
       for (Member* m : struct_def.members) {
-        switch (m->tag()) {
-          case MemberKind::FieldMember:
+        switch (m->Tag()) {
+          case Member::Kind::FieldMember:
             // TODO: Interpret the type expression and store the result.
             // TODO: Interpret the type expression and store the result.
             fields.push_back(m);
             fields.push_back(m);
             break;
             break;

+ 1 - 1
executable_semantics/syntax/parser.ypp

@@ -530,7 +530,7 @@ variable_declaration: identifier ":" pattern
     { $$ = global_arena->New<BindingPattern>(yylineno, $1, $3); }
     { $$ = global_arena->New<BindingPattern>(yylineno, $1, $3); }
 ;
 ;
 member: VAR variable_declaration ";"
 member: VAR variable_declaration ";"
-    { $$ = Member::MakeFieldMember(yylineno, $2); }
+    { $$ = global_arena->New<FieldMember>(yylineno, $2); }
 ;
 ;
 member_list:
 member_list:
   // Empty
   // Empty