[executable semantics] class-ify Declaration (#307)

* [executable semantics] class-ify Declaration

NFC (no functional change).

Proof of concept that we can simplify code by replacing unions with safer, more
regular types.  Hand-rolled existentials (type-erasing CoW wrappers) are a follow-on
step that will further simplify usage.

Began adding `const` where possible, and replacing `std::string*` with
`std::string`.  Most `const`s can disappear as we replace reference semantics
with value semantics, but in the meantime it's an important step in the right
direction.
This commit is contained in:
Dave Abrahams
2021-02-27 13:32:03 -08:00
committed by GitHub
parent cd57024042
commit 2205fd52ce
14 changed files with 191 additions and 210 deletions
@@ -252,55 +252,49 @@ auto EvalPrim(Operator op, const std::vector<Value*>& args, int line_num)
Env* globals;
void InitGlobals(std::list<Declaration*>* fs) {
void InitGlobals(std::list<const Declaration*>* fs) {
globals = nullptr;
for (auto& iter : *fs) {
switch (iter->tag) {
case DeclarationKind::ChoiceDeclaration: {
auto d = iter;
auto alts = new VarValues();
for (auto i = d->u.choice_def.alternatives->begin();
i != d->u.choice_def.alternatives->end(); ++i) {
auto t =
ToType(d->u.choice_def.line_num, InterpExp(nullptr, i->second));
alts->push_back(make_pair(i->first, t));
}
auto ct = MakeChoiceTypeVal(d->u.choice_def.name, alts);
auto a = AllocateValue(ct);
globals = new Env(*d->u.choice_def.name, a, globals);
break;
}
case DeclarationKind::StructDeclaration: {
auto d = iter;
auto fields = new VarValues();
auto methods = new VarValues();
for (auto i = d->u.struct_def->members->begin();
i != d->u.struct_def->members->end(); ++i) {
switch ((*i)->tag) {
case MemberKind::FieldMember: {
auto t = ToType(d->u.struct_def->line_num,
InterpExp(nullptr, (*i)->u.field.type));
fields->push_back(make_pair(*(*i)->u.field.name, t));
break;
}
}
}
auto st = MakeStructTypeVal(*d->u.struct_def->name, fields, methods);
auto a = AllocateValue(st);
globals = new Env(*d->u.struct_def->name, a, globals);
break;
}
case DeclarationKind::FunctionDeclaration: {
struct FunctionDefinition* fun = iter->u.fun_def;
Env* env = nullptr;
auto pt = InterpExp(env, fun->param_pattern);
auto f = MakeFunVal(fun->name, pt, fun->body);
Address a = AllocateValue(f);
globals = new Env(fun->name, a, globals);
for (auto d : *fs) {
d->InitGlobals(globals);
}
}
auto ChoiceDeclaration::InitGlobals(Env*& globals) const -> void {
auto alts = new VarValues();
for (auto kv : alternatives) {
auto t = ToType(line_num, InterpExp(nullptr, kv.second));
alts->push_back(make_pair(kv.first, t));
}
auto ct = MakeChoiceTypeVal(name, alts);
auto a = AllocateValue(ct);
globals = new Env(name, a, globals);
}
auto StructDeclaration::InitGlobals(Env*& globals) const -> void {
auto fields = new VarValues();
auto methods = new VarValues();
for (auto i = definition.members->begin(); i != definition.members->end();
++i) {
switch ((*i)->tag) {
case MemberKind::FieldMember: {
auto t =
ToType(definition.line_num, InterpExp(nullptr, (*i)->u.field.type));
fields->push_back(make_pair(*(*i)->u.field.name, t));
break;
}
}
}
auto st = MakeStructTypeVal(*definition.name, fields, methods);
auto a = AllocateValue(st);
globals = new Env(*definition.name, a, globals);
}
auto FunctionDeclaration::InitGlobals(Env*& globals) const -> void {
Env* env = nullptr;
auto pt = InterpExp(env, definition->param_pattern);
auto f = MakeFunVal(definition->name, pt, definition->body);
Address a = AllocateValue(f);
globals = new Env(definition->name, a, globals);
}
// { S, H} -> { { C, E, F} :: S, H}
@@ -1325,7 +1319,7 @@ void Step() {
}
// Interpret the whole porogram.
auto InterpProgram(std::list<Declaration*>* fs) -> int {
auto InterpProgram(std::list<const Declaration*>* fs) -> int {
state = new State(); // Runtime state.
std::cout << "********** initializing globals **********" << std::endl;
InitGlobals(fs);