Просмотр исходного кода

Switch Declaration to use inheritance+cast (#714)

Jon Meow 4 лет назад
Родитель
Сommit
c1148caf7d

+ 1 - 1
executable_semantics/ast/abstract_syntax_tree.h

@@ -10,7 +10,7 @@
 #include "executable_semantics/ast/declaration.h"
 
 namespace Carbon {
-using AST = std::list<Carbon::Declaration>;
+using AST = std::list<const Carbon::Declaration*>;
 }
 
 #endif  // EXECUTABLE_SEMANTICS_AST_ABSTRACT_SYNTAX_TREE_H_

+ 16 - 67
executable_semantics/ast/declaration.cpp

@@ -4,72 +4,21 @@
 
 #include "executable_semantics/ast/declaration.h"
 
-namespace Carbon {
-
-auto Declaration::MakeFunctionDeclaration(FunctionDefinition definition)
-    -> const Declaration {
-  Declaration d;
-  d.value = FunctionDeclaration({.definition = definition});
-  return d;
-}
-
-auto Declaration::MakeStructDeclaration(int line_num, std::string name,
-                                        std::list<Member*> members)
-    -> const Declaration {
-  Declaration d;
-  d.value = StructDeclaration(
-      {.definition = StructDefinition({.line_num = line_num,
-                                       .name = std::move(name),
-                                       .members = std::move(members)})});
-  return d;
-}
-
-auto Declaration::MakeChoiceDeclaration(
-    int line_num, std::string name,
-    std::list<std::pair<std::string, const Expression*>> alternatives)
-    -> const Declaration {
-  Declaration d;
-  d.value = ChoiceDeclaration({.line_num = line_num,
-                               .name = std::move(name),
-                               .alternatives = std::move(alternatives)});
-  return d;
-}
-
-auto Declaration::MakeVariableDeclaration(int source_location,
-                                          const BindingPattern* binding,
-                                          const Expression* initializer)
-    -> const Declaration {
-  Declaration d;
-  d.value = VariableDeclaration({.source_location = source_location,
-                                 .binding = binding,
-                                 .initializer = initializer});
-  return d;
-}
-
-auto Declaration::GetFunctionDeclaration() const -> const FunctionDeclaration& {
-  return std::get<FunctionDeclaration>(value);
-}
-
-auto Declaration::GetStructDeclaration() const -> const StructDeclaration& {
-  return std::get<StructDeclaration>(value);
-}
+#include "llvm/Support/Casting.h"
 
-auto Declaration::GetChoiceDeclaration() const -> const ChoiceDeclaration& {
-  return std::get<ChoiceDeclaration>(value);
-}
+namespace Carbon {
 
-auto Declaration::GetVariableDeclaration() const -> const VariableDeclaration& {
-  return std::get<VariableDeclaration>(value);
-}
+using llvm::cast;
 
 void Declaration::Print(llvm::raw_ostream& out) const {
-  switch (tag()) {
-    case DeclarationKind::FunctionDeclaration:
-      out << GetFunctionDeclaration().definition;
+  switch (Tag()) {
+    case Kind::FunctionDeclaration:
+      out << cast<FunctionDeclaration>(*this).Definition();
       break;
 
-    case DeclarationKind::StructDeclaration: {
-      const StructDefinition& struct_def = GetStructDeclaration().definition;
+    case Kind::StructDeclaration: {
+      const StructDefinition& struct_def =
+          cast<StructDeclaration>(*this).Definition();
       out << "struct " << struct_def.name << " {\n";
       for (Member* m : struct_def.members) {
         out << *m;
@@ -78,19 +27,19 @@ void Declaration::Print(llvm::raw_ostream& out) const {
       break;
     }
 
-    case DeclarationKind::ChoiceDeclaration: {
-      const auto& choice = GetChoiceDeclaration();
-      out << "choice " << choice.name << " {\n";
-      for (const auto& [name, signature] : choice.alternatives) {
+    case Kind::ChoiceDeclaration: {
+      const auto& choice = cast<ChoiceDeclaration>(*this);
+      out << "choice " << choice.Name() << " {\n";
+      for (const auto& [name, signature] : choice.Alternatives()) {
         out << "alt " << name << " " << *signature << ";\n";
       }
       out << "}\n";
       break;
     }
 
-    case DeclarationKind::VariableDeclaration: {
-      const auto& var = GetVariableDeclaration();
-      out << "var " << *var.binding << " = " << *var.initializer << "\n";
+    case Kind::VariableDeclaration: {
+      const auto& var = cast<VariableDeclaration>(*this);
+      out << "var " << *var.Binding() << " = " << *var.Initializer() << "\n";
       break;
     }
   }

+ 101 - 49
executable_semantics/ast/declaration.h

@@ -31,73 +31,125 @@ struct TypeCheckContext {
   Env values;
 };
 
-enum class DeclarationKind {
-  FunctionDeclaration,
-  StructDeclaration,
-  ChoiceDeclaration,
-  VariableDeclaration,
+// Abstract base class of all AST nodes representing patterns.
+//
+// Declaration and its derived classes support LLVM-style RTTI, including
+// llvm::isa, llvm::cast, and llvm::dyn_cast. To support this, every
+// class derived from Declaration 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 Declaration {
+ public:
+  enum class Kind {
+    FunctionDeclaration,
+    StructDeclaration,
+    ChoiceDeclaration,
+    VariableDeclaration,
+  };
+
+  Declaration(const Member&) = delete;
+  Declaration& operator=(const Member&) = delete;
+
+  // Returns the enumerator corresponding to the most-derived type of this
+  // object.
+  auto Tag() const -> Kind { return tag; }
+
+  auto LineNumber() const -> int { return line_num; }
+
+  void Print(llvm::raw_ostream& out) const;
+
+ protected:
+  // Constructs a Declaration representing syntax at the given line number.
+  // `tag` must be the enumerator corresponding to the most-derived type being
+  // constructed.
+  Declaration(Kind tag, int line_num) : tag(tag), line_num(line_num) {}
+
+ private:
+  const Kind tag;
+  int line_num;
 };
 
-struct FunctionDeclaration {
-  static constexpr DeclarationKind Kind = DeclarationKind::FunctionDeclaration;
+class FunctionDeclaration : public Declaration {
+ public:
+  FunctionDeclaration(FunctionDefinition definition)
+      : Declaration(Kind::FunctionDeclaration, definition.line_num),
+        definition(std::move(definition)) {}
+
+  static auto classof(const Declaration* decl) -> bool {
+    return decl->Tag() == Kind::FunctionDeclaration;
+  }
+
+  auto Definition() const -> const FunctionDefinition& { return definition; }
+
+ private:
   FunctionDefinition definition;
 };
 
-struct StructDeclaration {
-  static constexpr DeclarationKind Kind = DeclarationKind::StructDeclaration;
-  StructDefinition definition;
-};
+class StructDeclaration : public Declaration {
+ public:
+  StructDeclaration(int line_num, std::string name, std::list<Member*> members)
+      : Declaration(Kind::StructDeclaration, line_num),
+        definition({.line_num = line_num,
+                    .name = std::move(name),
+                    .members = std::move(members)}) {}
+
+  static auto classof(const Declaration* decl) -> bool {
+    return decl->Tag() == Kind::StructDeclaration;
+  }
 
-struct ChoiceDeclaration {
-  static constexpr DeclarationKind Kind = DeclarationKind::ChoiceDeclaration;
-  int line_num;
-  std::string name;
-  std::list<std::pair<std::string, const Expression*>> alternatives;
-};
+  auto Definition() const -> const StructDefinition& { return definition; }
 
-// Global variable definition implements the Declaration concept.
-struct VariableDeclaration {
-  static constexpr DeclarationKind Kind = DeclarationKind::VariableDeclaration;
-  int source_location;
-  // 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;
-  const Expression* initializer;
+ private:
+  StructDefinition definition;
 };
 
-class Declaration {
+class ChoiceDeclaration : public Declaration {
  public:
-  static auto MakeFunctionDeclaration(FunctionDefinition definition)
-      -> const Declaration;
-  static auto MakeStructDeclaration(int line_num, std::string name,
-                                    std::list<Member*> members)
-      -> const Declaration;
-  static auto MakeChoiceDeclaration(
+  ChoiceDeclaration(
       int line_num, std::string name,
       std::list<std::pair<std::string, const Expression*>> alternatives)
-      -> const Declaration;
-  static auto MakeVariableDeclaration(int source_location,
-                                      const BindingPattern* binding,
-                                      const Expression* initializer)
-      -> const Declaration;
+      : Declaration(Kind::ChoiceDeclaration, line_num),
+        name(std::move(name)),
+        alternatives(std::move(alternatives)) {}
 
-  auto GetFunctionDeclaration() const -> const FunctionDeclaration&;
-  auto GetStructDeclaration() const -> const StructDeclaration&;
-  auto GetChoiceDeclaration() const -> const ChoiceDeclaration&;
-  auto GetVariableDeclaration() const -> const VariableDeclaration&;
+  static auto classof(const Declaration* decl) -> bool {
+    return decl->Tag() == Kind::ChoiceDeclaration;
+  }
 
-  void Print(llvm::raw_ostream& out) const;
-  LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); }
+  auto Name() const -> const std::string& { return name; }
+  auto Alternatives() const
+      -> const std::list<std::pair<std::string, const Expression*>>& {
+    return alternatives;
+  }
 
-  inline auto tag() const -> DeclarationKind {
-    return std::visit([](const auto& t) { return t.Kind; }, value);
+ private:
+  std::string name;
+  std::list<std::pair<std::string, const Expression*>> alternatives;
+};
+
+// Global variable definition implements the Declaration concept.
+class VariableDeclaration : public Declaration {
+ public:
+  VariableDeclaration(int line_num, const BindingPattern* binding,
+                      const Expression* initializer)
+      : Declaration(Kind::VariableDeclaration, line_num),
+        binding(binding),
+        initializer(initializer) {}
+
+  static auto classof(const Declaration* decl) -> bool {
+    return decl->Tag() == Kind::VariableDeclaration;
   }
 
+  auto Binding() const -> const BindingPattern* { return binding; }
+  auto Initializer() const -> const Expression* { return initializer; }
+
  private:
-  std::variant<FunctionDeclaration, StructDeclaration, ChoiceDeclaration,
-               VariableDeclaration>
-      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;
+  const Expression* initializer;
 };
 
 }  // namespace Carbon

+ 19 - 18
executable_semantics/interpreter/interpreter.cpp

@@ -107,10 +107,10 @@ auto EvalPrim(Operator op, const std::vector<const Value*>& args, int line_num)
 static Env globals;
 
 void InitEnv(const Declaration& d, Env* env) {
-  switch (d.tag()) {
-    case DeclarationKind::FunctionDeclaration: {
+  switch (d.Tag()) {
+    case Declaration::Kind::FunctionDeclaration: {
       const FunctionDefinition& func_def =
-          d.GetFunctionDeclaration().definition;
+          cast<FunctionDeclaration>(d).Definition();
       Env new_env = *env;
       // Bring the deduced parameters into scope.
       for (const auto& deduced : func_def.deduced_parameters) {
@@ -126,8 +126,9 @@ void InitEnv(const Declaration& d, Env* env) {
       break;
     }
 
-    case DeclarationKind::StructDeclaration: {
-      const StructDefinition& struct_def = d.GetStructDeclaration().definition;
+    case Declaration::Kind::StructDeclaration: {
+      const StructDefinition& struct_def =
+          cast<StructDeclaration>(d).Definition();
       VarValues fields;
       VarValues methods;
       for (const Member* m : struct_def.members) {
@@ -149,34 +150,34 @@ void InitEnv(const Declaration& d, Env* env) {
       break;
     }
 
-    case DeclarationKind::ChoiceDeclaration: {
-      const auto& choice = d.GetChoiceDeclaration();
+    case Declaration::Kind::ChoiceDeclaration: {
+      const auto& choice = cast<ChoiceDeclaration>(d);
       VarValues alts;
-      for (const auto& [name, signature] : choice.alternatives) {
+      for (const auto& [name, signature] : choice.Alternatives()) {
         auto t = InterpExp(Env(), signature);
         alts.push_back(make_pair(name, t));
       }
-      auto ct = global_arena->New<ChoiceType>(choice.name, std::move(alts));
+      auto ct = global_arena->New<ChoiceType>(choice.Name(), std::move(alts));
       auto a = state->heap.AllocateValue(ct);
-      env->Set(choice.name, a);
+      env->Set(choice.Name(), a);
       break;
     }
 
-    case DeclarationKind::VariableDeclaration: {
-      const auto& var = d.GetVariableDeclaration();
+    case Declaration::Kind::VariableDeclaration: {
+      const auto& var = cast<VariableDeclaration>(d);
       // Adds an entry in `globals` mapping the variable's name to the
       // result of evaluating the initializer.
-      auto v = InterpExp(*env, var.initializer);
+      auto v = InterpExp(*env, var.Initializer());
       Address a = state->heap.AllocateValue(v);
-      env->Set(*var.binding->Name(), a);
+      env->Set(*var.Binding()->Name(), a);
       break;
     }
   }
 }
 
-static void InitGlobals(std::list<Declaration>* fs) {
-  for (auto const& d : *fs) {
-    InitEnv(d, &globals);
+static void InitGlobals(const std::list<const Declaration*>& fs) {
+  for (const auto* d : fs) {
+    InitEnv(*d, &globals);
   }
 }
 
@@ -1167,7 +1168,7 @@ void Step() {
 }
 
 // Interpret the whole porogram.
-auto InterpProgram(std::list<Declaration>* fs) -> int {
+auto InterpProgram(const std::list<const Declaration*>& fs) -> int {
   state = global_arena->New<State>();  // Runtime state.
   if (tracing_output) {
     llvm::outs() << "********** initializing globals **********\n";

+ 1 - 1
executable_semantics/interpreter/interpreter.h

@@ -35,7 +35,7 @@ void PrintEnv(Env values);
 
 /***** Interpreters *****/
 
-auto InterpProgram(std::list<Declaration>* fs) -> int;
+auto InterpProgram(const std::list<const Declaration*>& fs) -> int;
 auto InterpExp(Env values, const Expression* e) -> const Value*;
 auto InterpPattern(Env values, const Pattern* p) -> const Value*;
 

+ 47 - 45
executable_semantics/interpreter/typecheck.cpp

@@ -905,15 +905,15 @@ auto TypeOfStructDef(const StructDefinition* sd, TypeEnv /*types*/, Env ct_top)
 }
 
 static auto GetName(const Declaration& d) -> const std::string& {
-  switch (d.tag()) {
-    case DeclarationKind::FunctionDeclaration:
-      return d.GetFunctionDeclaration().definition.name;
-    case DeclarationKind::StructDeclaration:
-      return d.GetStructDeclaration().definition.name;
-    case DeclarationKind::ChoiceDeclaration:
-      return d.GetChoiceDeclaration().name;
-    case DeclarationKind::VariableDeclaration: {
-      const BindingPattern* binding = d.GetVariableDeclaration().binding;
+  switch (d.Tag()) {
+    case Declaration::Kind::FunctionDeclaration:
+      return cast<FunctionDeclaration>(d).Definition().name;
+    case Declaration::Kind::StructDeclaration:
+      return cast<StructDeclaration>(d).Definition().name;
+    case Declaration::Kind::ChoiceDeclaration:
+      return cast<ChoiceDeclaration>(d).Name();
+    case Declaration::Kind::VariableDeclaration: {
+      const BindingPattern* binding = cast<VariableDeclaration>(d).Binding();
       if (!binding->Name().has_value()) {
         FATAL_COMPILATION_ERROR(binding->LineNumber())
             << "Top-level variable declarations must have names";
@@ -924,14 +924,15 @@ static auto GetName(const Declaration& d) -> const std::string& {
 }
 
 auto MakeTypeChecked(const Declaration& d, const TypeEnv& types,
-                     const Env& values) -> Declaration {
-  switch (d.tag()) {
-    case DeclarationKind::FunctionDeclaration:
-      return Declaration::MakeFunctionDeclaration(*TypeCheckFunDef(
-          &d.GetFunctionDeclaration().definition, types, values));
+                     const Env& values) -> const Declaration* {
+  switch (d.Tag()) {
+    case Declaration::Kind::FunctionDeclaration:
+      return global_arena->New<FunctionDeclaration>(*TypeCheckFunDef(
+          &cast<FunctionDeclaration>(d).Definition(), types, values));
 
-    case DeclarationKind::StructDeclaration: {
-      const StructDefinition& struct_def = d.GetStructDeclaration().definition;
+    case Declaration::Kind::StructDeclaration: {
+      const StructDefinition& struct_def =
+          cast<StructDeclaration>(d).Definition();
       std::list<Member*> fields;
       for (Member* m : struct_def.members) {
         switch (m->tag()) {
@@ -941,49 +942,50 @@ auto MakeTypeChecked(const Declaration& d, const TypeEnv& types,
             break;
         }
       }
-      return Declaration::MakeStructDeclaration(
+      return global_arena->New<StructDeclaration>(
           struct_def.line_num, struct_def.name, std::move(fields));
     }
 
-    case DeclarationKind::ChoiceDeclaration:
+    case Declaration::Kind::ChoiceDeclaration:
       // TODO
-      return d;
+      return &d;
 
-    case DeclarationKind::VariableDeclaration: {
-      const auto& var = d.GetVariableDeclaration();
+    case Declaration::Kind::VariableDeclaration: {
+      const auto& var = cast<VariableDeclaration>(d);
       // Signals a type error if the initializing expression does not have
       // the declared type of the variable, otherwise returns this
       // declaration with annotated types.
       TCExpression type_checked_initializer =
-          TypeCheckExp(var.initializer, types, values);
+          TypeCheckExp(var.Initializer(), types, values);
       const Expression* type =
-          dyn_cast<ExpressionPattern>(var.binding->Type())->Expression();
+          dyn_cast<ExpressionPattern>(var.Binding()->Type())->Expression();
       if (type == nullptr) {
         // TODO: consider adding support for `auto`
-        FATAL_COMPILATION_ERROR(var.source_location)
+        FATAL_COMPILATION_ERROR(var.LineNumber())
             << "Type of a top-level variable must be an expression.";
       }
       const Value* declared_type = InterpExp(values, type);
-      ExpectType(var.source_location, "initializer of variable", declared_type,
+      ExpectType(var.LineNumber(), "initializer of variable", declared_type,
                  type_checked_initializer.type);
-      return d;
+      return &d;
     }
   }
 }
 
 static void TopLevel(const Declaration& d, TypeCheckContext* tops) {
-  switch (d.tag()) {
-    case DeclarationKind::FunctionDeclaration: {
+  switch (d.Tag()) {
+    case Declaration::Kind::FunctionDeclaration: {
       const FunctionDefinition& func_def =
-          d.GetFunctionDeclaration().definition;
+          cast<FunctionDeclaration>(d).Definition();
       auto t = TypeOfFunDef(tops->types, tops->values, &func_def);
       tops->types.Set(func_def.name, t);
       InitEnv(d, &tops->values);
       break;
     }
 
-    case DeclarationKind::StructDeclaration: {
-      const StructDefinition& struct_def = d.GetStructDeclaration().definition;
+    case Declaration::Kind::StructDeclaration: {
+      const StructDefinition& struct_def =
+          cast<StructDeclaration>(d).Definition();
       auto st = TypeOfStructDef(&struct_def, tops->types, tops->values);
       Address a = state->heap.AllocateValue(st);
       tops->values.Set(struct_def.name, a);  // Is this obsolete?
@@ -999,42 +1001,42 @@ static void TopLevel(const Declaration& d, TypeCheckContext* tops) {
       break;
     }
 
-    case DeclarationKind::ChoiceDeclaration: {
-      const auto& choice = d.GetChoiceDeclaration();
+    case Declaration::Kind::ChoiceDeclaration: {
+      const auto& choice = cast<ChoiceDeclaration>(d);
       VarValues alts;
-      for (const auto& [name, signature] : choice.alternatives) {
+      for (const auto& [name, signature] : choice.Alternatives()) {
         auto t = InterpExp(tops->values, signature);
         alts.push_back(std::make_pair(name, t));
       }
-      auto ct = global_arena->New<ChoiceType>(choice.name, std::move(alts));
+      auto ct = global_arena->New<ChoiceType>(choice.Name(), std::move(alts));
       Address a = state->heap.AllocateValue(ct);
-      tops->values.Set(choice.name, a);  // Is this obsolete?
-      tops->types.Set(choice.name, ct);
+      tops->values.Set(choice.Name(), a);  // Is this obsolete?
+      tops->types.Set(choice.Name(), ct);
       break;
     }
 
-    case DeclarationKind::VariableDeclaration: {
-      const auto& var = d.GetVariableDeclaration();
+    case Declaration::Kind::VariableDeclaration: {
+      const auto& var = cast<VariableDeclaration>(d);
       // Associate the variable name with it's declared type in the
       // compile-time symbol table.
       const Expression* type =
-          cast<ExpressionPattern>(var.binding->Type())->Expression();
+          cast<ExpressionPattern>(var.Binding()->Type())->Expression();
       const Value* declared_type = InterpExp(tops->values, type);
-      tops->types.Set(*var.binding->Name(), declared_type);
+      tops->types.Set(*var.Binding()->Name(), declared_type);
       break;
     }
   }
 }
 
-auto TopLevel(std::list<Declaration>* fs) -> TypeCheckContext {
+auto TopLevel(const std::list<const Declaration*>& fs) -> TypeCheckContext {
   TypeCheckContext tops;
   bool found_main = false;
 
-  for (auto const& d : *fs) {
-    if (GetName(d) == "main") {
+  for (auto const& d : fs) {
+    if (GetName(*d) == "main") {
       found_main = true;
     }
-    TopLevel(d, &tops);
+    TopLevel(*d, &tops);
   }
 
   if (found_main == false) {

+ 2 - 2
executable_semantics/interpreter/typecheck.h

@@ -51,8 +51,8 @@ auto TypeCheckFunDef(struct FunctionDefinition*, TypeEnv)
     -> struct FunctionDefinition*;
 
 auto MakeTypeChecked(const Declaration& decl, const TypeEnv& types,
-                     const Env& values) -> Declaration;
-auto TopLevel(std::list<Declaration>* fs) -> TypeCheckContext;
+                     const Env& values) -> const Declaration*;
+auto TopLevel(const std::list<const Declaration*>& fs) -> TypeCheckContext;
 
 }  // namespace Carbon
 

+ 1 - 1
executable_semantics/main.cpp

@@ -39,5 +39,5 @@ int main(int argc, char* argv[]) {
   }
 
   // Typecheck and run the parsed program.
-  Carbon::ExecProgram(&std::get<Carbon::AST>(ast_or_error));
+  Carbon::ExecProgram(std::get<Carbon::AST>(ast_or_error));
 }

+ 8 - 8
executable_semantics/syntax/parser.ypp

@@ -91,10 +91,10 @@ void Carbon::Parser::error(const location_type&, const std::string& message) {
 %token <std::string> identifier
 %token <std::string> sized_type_literal
 %type <std::string> designator
-%type <Declaration> declaration
+%type <const Declaration*> declaration
 %type <FunctionDefinition> function_declaration
 %type <FunctionDefinition> function_definition
-%type <std::list<Declaration>> declaration_list
+%type <std::list<const Declaration*>> declaration_list
 %type <const Statement*> statement
 %type <const Statement*> if_statement
 %type <const Statement*> optional_else
@@ -558,25 +558,25 @@ alternative_list:
 ;
 declaration:
   function_definition
-    { $$ = Declaration::MakeFunctionDeclaration(std::move($1)); }
+    { $$ = global_arena->New<FunctionDeclaration>(std::move($1)); }
 | function_declaration
-    { $$ = Declaration::MakeFunctionDeclaration(std::move($1)); }
+    { $$ = global_arena->New<FunctionDeclaration>(std::move($1)); }
 | STRUCT identifier "{" member_list "}"
     {
-      $$ = Declaration::MakeStructDeclaration(yylineno, $2, $4);
+      $$ = global_arena->New<StructDeclaration>(yylineno, $2, $4);
     }
 | CHOICE identifier "{" alternative_list "}"
     {
-      $$ = Declaration::MakeChoiceDeclaration(yylineno, $2, $4);
+      $$ = global_arena->New<ChoiceDeclaration>(yylineno, $2, $4);
     }
 | VAR variable_declaration "=" expression ";"
     {
-      $$ = Declaration::MakeVariableDeclaration(yylineno, $2, $4);
+      $$ = global_arena->New<VariableDeclaration>(yylineno, $2, $4);
     }
 ;
 declaration_list:
   // Empty
-    { $$ = std::list<Declaration>(); }
+    { $$ = std::list<const Declaration*>(); }
 | declaration declaration_list
     {
       $$ = $2;

+ 9 - 9
executable_semantics/syntax/syntax_helpers.cpp

@@ -12,11 +12,11 @@
 
 namespace Carbon {
 
-void ExecProgram(std::list<Declaration>* fs) {
+void ExecProgram(const std::list<const Declaration*>& fs) {
   if (tracing_output) {
     llvm::outs() << "********** source program **********\n";
-    for (const auto& decl : *fs) {
-      llvm::outs() << decl;
+    for (const auto* decl : fs) {
+      llvm::outs() << *decl;
     }
     llvm::outs() << "********** type checking **********\n";
   }
@@ -24,19 +24,19 @@ void ExecProgram(std::list<Declaration>* fs) {
   TypeCheckContext p = TopLevel(fs);
   TypeEnv top = p.types;
   Env ct_top = p.values;
-  std::list<Declaration> new_decls;
-  for (const auto& decl : *fs) {
-    new_decls.push_back(MakeTypeChecked(decl, top, ct_top));
+  std::list<const Declaration*> new_decls;
+  for (const auto* decl : fs) {
+    new_decls.push_back(MakeTypeChecked(*decl, top, ct_top));
   }
   if (tracing_output) {
     llvm::outs() << "\n";
     llvm::outs() << "********** type checking complete **********\n";
-    for (const auto& decl : new_decls) {
-      llvm::outs() << decl;
+    for (const auto* decl : new_decls) {
+      llvm::outs() << *decl;
     }
     llvm::outs() << "********** starting execution **********\n";
   }
-  int result = InterpProgram(&new_decls);
+  int result = InterpProgram(new_decls);
   llvm::outs() << "result: " << result << "\n";
 }
 

+ 1 - 1
executable_semantics/syntax/syntax_helpers.h

@@ -16,7 +16,7 @@
 namespace Carbon {
 
 // Runs the top-level declaration list.
-void ExecProgram(std::list<Declaration>* fs);
+void ExecProgram(const std::list<const Declaration*>& fs);
 
 }  // namespace Carbon