mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Value semantics for Declaration. (#313)
This change creates an unpleasant amount of boilerplate where `Declaration` is declared, in exchange for being able to—very pleasantly—treat it as a simple value that composes with other values everywhere it is used. Applying this technique broadly will pay off in code comprehensibility; once it has been done for all things being new'd, pointers disappear and references are only needed as an idiomatic approximation of inout. The unpleasant code grows only when new polymorphic operations are added, and then only a bit, and is an idiom whose details can readily be ignored once in place. The pleasant code pervades the codebase. Too bad we don't have existential types in C++ ;-)
This commit is contained in:
@@ -24,42 +24,100 @@ using Env = AssocList<std::string, Address>;
|
||||
/// TODO:explain this. Also name it if necessary. Consult with jsiek.
|
||||
using ExecutionEnvironment = std::pair<TypeEnv*, Env*>;
|
||||
|
||||
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 <class Model>
|
||||
Declaration(Model d) : box(std::make_shared<Boxed<Model>>(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<Content>`, 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 <class Content>
|
||||
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<const Box> 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<Member*>* 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<std::pair<std::string, Expression*>> 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;
|
||||
};
|
||||
|
||||
@@ -253,10 +253,10 @@ auto EvalPrim(Operator op, const std::vector<Value*>& args, int line_num)
|
||||
|
||||
Env* globals;
|
||||
|
||||
void InitGlobals(std::list<const Declaration*>* fs) {
|
||||
void InitGlobals(std::list<Declaration>* 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<const Declaration*>* fs) -> int {
|
||||
auto InterpProgram(std::list<Declaration>* fs) -> int {
|
||||
state = new State(); // Runtime state.
|
||||
std::cout << "********** initializing globals **********" << std::endl;
|
||||
InitGlobals(fs);
|
||||
|
||||
@@ -52,7 +52,7 @@ auto ToInteger(Value* v) -> int;
|
||||
|
||||
/***** Interpreters *****/
|
||||
|
||||
auto InterpProgram(std::list<const Declaration*>* fs) -> int;
|
||||
auto InterpProgram(std::list<Declaration>* fs) -> int;
|
||||
auto InterpExp(Env* env, Expression* e) -> Value*;
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
@@ -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<Member*>();
|
||||
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<Declaration*>* fs) -> std::pair<TypeEnv*, Env*> {
|
||||
auto TopLevel(std::list<Declaration>* fs) -> std::pair<TypeEnv*, Env*> {
|
||||
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) {
|
||||
|
||||
@@ -45,7 +45,7 @@ auto TypeCheckStmt(Statement*, TypeEnv*, Env*, Value*) -> TCStatement;
|
||||
auto TypeCheckFunDef(struct FunctionDefinition*, TypeEnv*)
|
||||
-> struct FunctionDefinition*;
|
||||
|
||||
auto TopLevel(std::list<Declaration*>* fs) -> std::pair<TypeEnv*, Env*>;
|
||||
auto TopLevel(std::list<Declaration>* fs) -> std::pair<TypeEnv*, Env*>;
|
||||
|
||||
void PrintErrorString(const std::string& s);
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ void yyerror(char* error) {
|
||||
Carbon::Statement* statement_list;
|
||||
Carbon::FunctionDefinition* function_definition;
|
||||
Carbon::Declaration* declaration;
|
||||
std::list<Carbon::Declaration*>* declaration_list;
|
||||
std::list<Carbon::Declaration>* declaration_list;
|
||||
Carbon::Member* member;
|
||||
std::list<Carbon::Member*>* 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<Carbon::Declaration*>(); }
|
||||
{ $$ = new std::list<Carbon::Declaration>(); }
|
||||
| declaration declaration_list
|
||||
{
|
||||
$$ = $2;
|
||||
$$->push_front($1);
|
||||
$$->push_front(*$1);
|
||||
}
|
||||
;
|
||||
%%
|
||||
|
||||
@@ -18,24 +18,24 @@ void PrintSyntaxError(char* error, int line_num) {
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
void ExecProgram(std::list<Declaration*>* fs) {
|
||||
void ExecProgram(std::list<Declaration>* 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<TypeEnv*, Env*> p = TopLevel(fs);
|
||||
TypeEnv* top = p.first;
|
||||
Env* ct_top = p.second;
|
||||
std::list<const Declaration*> new_decls;
|
||||
for (const auto i : *fs) {
|
||||
new_decls.push_back(i->TypeChecked(top, ct_top));
|
||||
std::list<Declaration> 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);
|
||||
|
||||
@@ -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<Declaration*>* fs);
|
||||
void ExecProgram(std::list<Declaration>* fs);
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
|
||||
Reference in New Issue
Block a user