diff --git a/executable_semantics/ast/declaration.h b/executable_semantics/ast/declaration.h index cc2940866dfb..91b8f2dc4ca3 100644 --- a/executable_semantics/ast/declaration.h +++ b/executable_semantics/ast/declaration.h @@ -24,42 +24,100 @@ using Env = AssocList; /// TODO:explain this. Also name it if necessary. Consult with jsiek. using ExecutionEnvironment = std::pair; -struct Declaration { - virtual void Print() const = 0; - virtual auto Name() const -> std::string = 0; - virtual auto TypeChecked(TypeEnv* env, Env* ct_env) const - -> const Declaration* = 0; - virtual void InitGlobals(Env*& globals) const = 0; - virtual auto TopLevel(ExecutionEnvironment&) const -> void = 0; +/// An existential AST declaration satisfying the Declaration concept. +class Declaration { + public: // ValueSemantic concept API. + Declaration(const Declaration& other) = default; + Declaration& operator=(const Declaration& other) = default; + + /// Constructs an instance equivalent to `d`, where `Model` satisfies the + /// Declaration concept. + template + Declaration(Model d) : box(std::make_shared>(d)) {} + + public: // Declaration concept API, in addition to ValueSemantic. + void Print() const { box->Print(); } + auto Name() const -> std::string { return box->Name(); } + auto TypeChecked(TypeEnv* env, Env* ct_env) const -> Declaration { + return box->TypeChecked(env, ct_env); + } + void InitGlobals(Env*& globals) const { return box->InitGlobals(globals); } + auto TopLevel(ExecutionEnvironment& e) const -> void { + return box->TopLevel(e); + } + + private: // types + /// A base class that erases the type of a `Boxed`, where `Content` + /// satisfies the Declaration concept. + struct Box { + protected: + Box() {} + + public: + Box(const Box& other) = delete; + Box& operator=(const Box& other) = delete; + + virtual ~Box() {} + virtual auto Print() const -> void = 0; + virtual auto Name() const -> std::string = 0; + virtual auto TypeChecked(TypeEnv* env, Env* ct_env) const + -> Declaration = 0; + virtual auto InitGlobals(Env*& globals) const -> void = 0; + virtual auto TopLevel(ExecutionEnvironment&) const -> void = 0; + }; + + /// The derived class that holds an instance of `Content` satisfying the + /// Declaration concept. + template + struct Boxed final : Box { + const Content content; + explicit Boxed(Content content) : Box(), content(content) {} + + auto Print() const -> void override { return content.Print(); } + auto Name() const -> std::string override { return content.Name(); } + auto TypeChecked(TypeEnv* env, Env* ct_env) const -> Declaration override { + return content.TypeChecked(env, ct_env); + } + auto InitGlobals(Env*& globals) const -> void override { + content.InitGlobals(globals); + } + auto TopLevel(ExecutionEnvironment& e) const -> void override { + content.TopLevel(e); + } + }; + + private: // data members + // Note: the pointee is const as long as we have no mutating methods. When + std::shared_ptr box; }; -struct FunctionDeclaration : Declaration { +struct FunctionDeclaration { const FunctionDefinition* definition; explicit FunctionDeclaration(const FunctionDefinition* definition) : definition(definition) {} - void Print() const; + auto Print() const -> void; auto Name() const -> std::string; - auto TypeChecked(TypeEnv* env, Env* ct_env) const -> const Declaration*; - void InitGlobals(Env*& globals) const; + auto TypeChecked(TypeEnv* env, Env* ct_env) const -> Declaration; + auto InitGlobals(Env*& globals) const -> void; auto TopLevel(ExecutionEnvironment&) const -> void; }; -struct StructDeclaration : Declaration { +struct StructDeclaration { StructDefinition definition; StructDeclaration(int line_num, std::string name, std::list* members) : definition{line_num, new std::string(name), members} {} void Print() const; auto Name() const -> std::string; - auto TypeChecked(TypeEnv* env, Env* ct_env) const -> const Declaration*; + auto TypeChecked(TypeEnv* env, Env* ct_env) const -> Declaration; void InitGlobals(Env*& globals) const; auto TopLevel(ExecutionEnvironment&) const -> void; }; -struct ChoiceDeclaration : Declaration { +struct ChoiceDeclaration { int line_num; - std::string name; + std::string name; std::list> alternatives; ChoiceDeclaration(int line_num, std::string name, @@ -68,7 +126,7 @@ struct ChoiceDeclaration : Declaration { void Print() const; auto Name() const -> std::string; - auto TypeChecked(TypeEnv* env, Env* ct_env) const -> const Declaration*; + auto TypeChecked(TypeEnv* env, Env* ct_env) const -> Declaration; void InitGlobals(Env*& globals) const; auto TopLevel(ExecutionEnvironment&) const -> void; }; diff --git a/executable_semantics/interpreter/interpreter.cpp b/executable_semantics/interpreter/interpreter.cpp index a0334c426dde..5aa6d30b9b55 100644 --- a/executable_semantics/interpreter/interpreter.cpp +++ b/executable_semantics/interpreter/interpreter.cpp @@ -253,10 +253,10 @@ auto EvalPrim(Operator op, const std::vector& args, int line_num) Env* globals; -void InitGlobals(std::list* fs) { +void InitGlobals(std::list* fs) { globals = nullptr; - for (auto d : *fs) { - d->InitGlobals(globals); + for (auto const& d : *fs) { + d.InitGlobals(globals); } } @@ -1321,7 +1321,7 @@ void Step() { } // Interpret the whole porogram. -auto InterpProgram(std::list* fs) -> int { +auto InterpProgram(std::list* fs) -> int { state = new State(); // Runtime state. std::cout << "********** initializing globals **********" << std::endl; InitGlobals(fs); diff --git a/executable_semantics/interpreter/interpreter.h b/executable_semantics/interpreter/interpreter.h index 9c7875a41919..c2bb9a09d6cc 100644 --- a/executable_semantics/interpreter/interpreter.h +++ b/executable_semantics/interpreter/interpreter.h @@ -52,7 +52,7 @@ auto ToInteger(Value* v) -> int; /***** Interpreters *****/ -auto InterpProgram(std::list* fs) -> int; +auto InterpProgram(std::list* fs) -> int; auto InterpExp(Env* env, Expression* e) -> Value*; } // namespace Carbon diff --git a/executable_semantics/interpreter/typecheck.cpp b/executable_semantics/interpreter/typecheck.cpp index 38fd9aba380d..43abcd1aa44a 100644 --- a/executable_semantics/interpreter/typecheck.cpp +++ b/executable_semantics/interpreter/typecheck.cpp @@ -618,7 +618,7 @@ auto StructDeclaration::Name() const -> std::string { return *definition.name; } auto ChoiceDeclaration::Name() const -> std::string { return name; } auto StructDeclaration::TypeChecked(TypeEnv* env, Env* ct_env) const - -> const Declaration* { + -> Declaration { auto fields = new std::list(); for (auto& m : *definition.members) { if (m->tag == MemberKind::FieldMember) { @@ -626,28 +626,28 @@ auto StructDeclaration::TypeChecked(TypeEnv* env, Env* ct_env) const fields->push_back(m); } } - return new StructDeclaration(definition.line_num, *definition.name, fields); + return StructDeclaration(definition.line_num, *definition.name, fields); } auto FunctionDeclaration::TypeChecked(TypeEnv* env, Env* ct_env) const - -> const Declaration* { - return new FunctionDeclaration(TypeCheckFunDef(definition, env, ct_env)); + -> Declaration { + return FunctionDeclaration(TypeCheckFunDef(definition, env, ct_env)); } auto ChoiceDeclaration::TypeChecked(TypeEnv* env, Env* ct_env) const - -> const Declaration* { - return this; // TODO. + -> Declaration { + return *this; // TODO. } -auto TopLevel(std::list* fs) -> std::pair { +auto TopLevel(std::list* fs) -> std::pair { ExecutionEnvironment tops = {nullptr, nullptr}; bool found_main = false; - for (auto d : *fs) { - if (d->Name() == "main") { + for (auto const& d : *fs) { + if (d.Name() == "main") { found_main = true; } - d->TopLevel(tops); + d.TopLevel(tops); } if (found_main == false) { diff --git a/executable_semantics/interpreter/typecheck.h b/executable_semantics/interpreter/typecheck.h index a4494f168f54..c018a1d43bd3 100644 --- a/executable_semantics/interpreter/typecheck.h +++ b/executable_semantics/interpreter/typecheck.h @@ -45,7 +45,7 @@ auto TypeCheckStmt(Statement*, TypeEnv*, Env*, Value*) -> TCStatement; auto TypeCheckFunDef(struct FunctionDefinition*, TypeEnv*) -> struct FunctionDefinition*; -auto TopLevel(std::list* fs) -> std::pair; +auto TopLevel(std::list* fs) -> std::pair; void PrintErrorString(const std::string& s); diff --git a/executable_semantics/syntax.ypp b/executable_semantics/syntax.ypp index 5cb7ea61e6b9..6523a62eb51d 100644 --- a/executable_semantics/syntax.ypp +++ b/executable_semantics/syntax.ypp @@ -38,7 +38,7 @@ void yyerror(char* error) { Carbon::Statement* statement_list; Carbon::FunctionDefinition* function_definition; Carbon::Declaration* declaration; - std::list* declaration_list; + std::list* declaration_list; Carbon::Member* member; std::list* member_list; Carbon::ExpOrFieldList* field_list; @@ -312,21 +312,27 @@ alternative_list: ; declaration: function_definition - { $$ = new Carbon::FunctionDeclaration{$1}; } + { $$ = new Carbon::Declaration(Carbon::FunctionDeclaration{$1}); } | function_declaration - { $$ = new Carbon::FunctionDeclaration{$1}; } + { $$ = new Carbon::Declaration(Carbon::FunctionDeclaration{$1}); } | STRUCT identifier '{' member_list '}' - { $$ = new Carbon::StructDeclaration{yylineno, $2, $4}; } + { + $$ = new Carbon::Declaration( + Carbon::StructDeclaration{yylineno, $2, $4}); + } | CHOICE identifier '{' alternative_list '}' - { $$ = new Carbon::ChoiceDeclaration{yylineno, $2, std::list(*$4)}; } + { + $$ = new Carbon::Declaration( + Carbon::ChoiceDeclaration{yylineno, $2, std::list(*$4)}); + } ; declaration_list: // Empty - { $$ = new std::list(); } + { $$ = new std::list(); } | declaration declaration_list { $$ = $2; - $$->push_front($1); + $$->push_front(*$1); } ; %% diff --git a/executable_semantics/syntax_helpers.cpp b/executable_semantics/syntax_helpers.cpp index b5dcc0cc8c13..4b0b4c5fbc6e 100644 --- a/executable_semantics/syntax_helpers.cpp +++ b/executable_semantics/syntax_helpers.cpp @@ -18,24 +18,24 @@ void PrintSyntaxError(char* error, int line_num) { exit(-1); } -void ExecProgram(std::list* fs) { +void ExecProgram(std::list* fs) { std::cout << "********** source program **********" << std::endl; - for (const auto decl : *fs) { - decl->Print(); + for (const auto& decl : *fs) { + decl.Print(); } std::cout << "********** type checking **********" << std::endl; state = new State(); // Compile-time state. std::pair p = TopLevel(fs); TypeEnv* top = p.first; Env* ct_top = p.second; - std::list new_decls; - for (const auto i : *fs) { - new_decls.push_back(i->TypeChecked(top, ct_top)); + std::list new_decls; + for (const auto& decl : *fs) { + new_decls.push_back(decl.TypeChecked(top, ct_top)); } std::cout << std::endl; std::cout << "********** type checking complete **********" << std::endl; - for (const auto decl : new_decls) { - decl->Print(); + for (const auto& decl : new_decls) { + decl.Print(); } std::cout << "********** starting execution **********" << std::endl; int result = InterpProgram(&new_decls); diff --git a/executable_semantics/syntax_helpers.h b/executable_semantics/syntax_helpers.h index 734c1b2c1d63..0efc77449cd9 100644 --- a/executable_semantics/syntax_helpers.h +++ b/executable_semantics/syntax_helpers.h @@ -22,7 +22,7 @@ extern char* input_filename; void PrintSyntaxError(char* error, int line_num); // Runs the top-level declaration list. -void ExecProgram(std::list* fs); +void ExecProgram(std::list* fs); } // namespace Carbon