diff --git a/executable_semantics/ast/BUILD b/executable_semantics/ast/BUILD index 99e88447dda8..0e3d0644e964 100644 --- a/executable_semantics/ast/BUILD +++ b/executable_semantics/ast/BUILD @@ -14,6 +14,7 @@ cc_library( ":function_definition", ":member", ":struct_definition", + "//executable_semantics/interpreter:containers", ], ) diff --git a/executable_semantics/ast/declaration.h b/executable_semantics/ast/declaration.h index 91b8f2dc4ca3..0f9b2814d741 100644 --- a/executable_semantics/ast/declaration.h +++ b/executable_semantics/ast/declaration.h @@ -11,18 +11,18 @@ #include "executable_semantics/ast/function_definition.h" #include "executable_semantics/ast/member.h" #include "executable_semantics/ast/struct_definition.h" +#include "executable_semantics/interpreter/dictionary.h" namespace Carbon { struct Value; -template -struct AssocList; + using Address = unsigned int; -using TypeEnv = AssocList; -using Env = AssocList; +using TypeEnv = Dictionary; +using Env = Dictionary; /// TODO:explain this. Also name it if necessary. Consult with jsiek. -using ExecutionEnvironment = std::pair; +using ExecutionEnvironment = std::pair; /// An existential AST declaration satisfying the Declaration concept. class Declaration { @@ -38,10 +38,10 @@ class Declaration { 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 { + auto TypeChecked(TypeEnv env, Env ct_env) const -> Declaration { return box->TypeChecked(env, ct_env); } - void InitGlobals(Env*& globals) const { return box->InitGlobals(globals); } + void InitGlobals(Env& globals) const { return box->InitGlobals(globals); } auto TopLevel(ExecutionEnvironment& e) const -> void { return box->TopLevel(e); } @@ -60,9 +60,8 @@ class Declaration { 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 TypeChecked(TypeEnv env, Env ct_env) const -> Declaration = 0; + virtual auto InitGlobals(Env& globals) const -> void = 0; virtual auto TopLevel(ExecutionEnvironment&) const -> void = 0; }; @@ -75,10 +74,10 @@ class Declaration { 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 { + auto TypeChecked(TypeEnv env, Env ct_env) const -> Declaration override { return content.TypeChecked(env, ct_env); } - auto InitGlobals(Env*& globals) const -> void override { + auto InitGlobals(Env& globals) const -> void override { content.InitGlobals(globals); } auto TopLevel(ExecutionEnvironment& e) const -> void override { @@ -98,8 +97,8 @@ struct FunctionDeclaration { auto Print() const -> void; auto Name() const -> std::string; - auto TypeChecked(TypeEnv* env, Env* ct_env) const -> Declaration; - auto InitGlobals(Env*& globals) const -> void; + auto TypeChecked(TypeEnv env, Env ct_env) const -> Declaration; + auto InitGlobals(Env& globals) const -> void; auto TopLevel(ExecutionEnvironment&) const -> void; }; @@ -110,8 +109,8 @@ struct StructDeclaration { void Print() const; auto Name() const -> std::string; - auto TypeChecked(TypeEnv* env, Env* ct_env) const -> Declaration; - void InitGlobals(Env*& globals) const; + auto TypeChecked(TypeEnv env, Env ct_env) const -> Declaration; + void InitGlobals(Env& globals) const; auto TopLevel(ExecutionEnvironment&) const -> void; }; @@ -126,8 +125,8 @@ struct ChoiceDeclaration { void Print() const; auto Name() const -> std::string; - auto TypeChecked(TypeEnv* env, Env* ct_env) const -> Declaration; - void InitGlobals(Env*& globals) const; + 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/BUILD b/executable_semantics/interpreter/BUILD index 70a31f80db68..0ee87130202c 100644 --- a/executable_semantics/interpreter/BUILD +++ b/executable_semantics/interpreter/BUILD @@ -17,14 +17,12 @@ cc_library( ], hdrs = [ "action.h", - "assoc_list.h", "interpreter.h", - "list_node.h", - "stack.h", "typecheck.h", "value.h", ], deps = [ + ":containers", "//executable_semantics:tracing_flag", "//executable_semantics/ast:declaration", "//executable_semantics/ast:expression", @@ -33,3 +31,14 @@ cc_library( "//executable_semantics/ast:statement", ], ) + +cc_library( + name = "containers", + srcs = [ + "list_node.h", + ], + hdrs = [ + "dictionary.h", + "stack.h", + ], +) diff --git a/executable_semantics/interpreter/assoc_list.h b/executable_semantics/interpreter/assoc_list.h deleted file mode 100644 index c5f9f0014468..000000000000 --- a/executable_semantics/interpreter/assoc_list.h +++ /dev/null @@ -1,38 +0,0 @@ -// Part of the Carbon Language project, under the Apache License v2.0 with LLVM -// Exceptions. See /LICENSE for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#ifndef EXECUTABLE_SEMANTICS_INTERPRETER_ASSOC_LIST_H_ -#define EXECUTABLE_SEMANTICS_INTERPRETER_ASSOC_LIST_H_ - -#include -#include -#include - -namespace Carbon { - -template -struct AssocList { - AssocList(K k, V v, AssocList* n) : key(k), value(v), next(n) {} - - K key; - V value; - AssocList* next; -}; - -template -auto Lookup(int line_num, AssocList* alist, const K& key, - void (*print_key)(const K&)) -> V { - if (alist == NULL) { - std::cerr << line_num << ": could not find `" << key << "`" << std::endl; - exit(-1); - } else if (alist->key == key) { - return alist->value; - } else { - return Lookup(line_num, alist->next, key, print_key); - } -} - -} // namespace Carbon - -#endif // EXECUTABLE_SEMANTICS_INTERPRETER_ASSOC_LIST_H_ diff --git a/executable_semantics/interpreter/interpreter.cpp b/executable_semantics/interpreter/interpreter.cpp index b071d5c41fa8..d378566e1d28 100644 --- a/executable_semantics/interpreter/interpreter.cpp +++ b/executable_semantics/interpreter/interpreter.cpp @@ -22,8 +22,8 @@ namespace Carbon { State* state = nullptr; -auto PatternMatch(Value* pat, Value* val, Env*, std::list*, int) - -> Env*; +auto PatternMatch(Value* pat, Value* val, Env, std::list*, int) + -> std::optional; void HandleValue(); template @@ -38,7 +38,9 @@ static auto FindField(const std::string& field, return std::nullopt; } -/**** Auxiliary Functions ****/ +// +// Auxiliary Functions +// auto AllocateValue(Value* v) -> Address { // Putting the following two side effects together in this function @@ -135,16 +137,17 @@ void KillValue(Value* val) { } } -void PrintEnv(Env* env, std::ostream& out) { - if (env) { - std::cout << env->key << ": "; - PrintValue(state->heap[env->value], out); - std::cout << ", "; - PrintEnv(env->next, out); +void PrintEnv(Env env, std::ostream& out) { + for (const auto& [name, value] : env) { + out << name << ": "; + PrintValue(state->heap[value], out); + out << ", "; } } -/***** Frame and State Operations *****/ +// +// Frame and State Operations +// void PrintFrame(Frame* frame, std::ostream& out) { out << frame->name; @@ -174,7 +177,7 @@ void PrintHeap(const std::vector& heap, std::ostream& out) { } } -auto CurrentEnv(State* state) -> Env* { +auto CurrentEnv(State* state) -> Env { Frame* frame = state->stack.Top(); return frame->scopes.Top()->env; } @@ -190,7 +193,9 @@ void PrintState(std::ostream& out) { out << std::endl << "}" << std::endl; } -/***** Auxiliary Functions *****/ +// +// More Auxiliary Functions +// auto ValToInt(Value* v, int line_num) -> int { CheckAlive(v, line_num); @@ -252,27 +257,27 @@ auto EvalPrim(Operator op, const std::vector& args, int line_num) } } -Env* globals; +// Globally-defined entities, such as functions, structs, choices. +Env globals; void InitGlobals(std::list* fs) { - globals = nullptr; for (auto const& d : *fs) { d.InitGlobals(globals); } } -auto ChoiceDeclaration::InitGlobals(Env*& globals) const -> void { +auto ChoiceDeclaration::InitGlobals(Env& globals) const -> void { auto alts = new VarValues(); for (auto kv : alternatives) { - auto t = ToType(line_num, InterpExp(nullptr, kv.second)); + auto t = ToType(line_num, InterpExp(Env(), 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); + globals.Set(name, a); } -auto StructDeclaration::InitGlobals(Env*& globals) const -> void { +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(); @@ -280,7 +285,7 @@ auto StructDeclaration::InitGlobals(Env*& globals) const -> void { switch ((*i)->tag) { case MemberKind::FieldMember: { auto t = - ToType(definition.line_num, InterpExp(nullptr, (*i)->u.field.type)); + ToType(definition.line_num, InterpExp(Env(), (*i)->u.field.type)); fields->push_back(make_pair(*(*i)->u.field.name, t)); break; } @@ -288,15 +293,15 @@ auto StructDeclaration::InitGlobals(Env*& globals) const -> void { } auto st = MakeStructTypeVal(*definition.name, fields, methods); auto a = AllocateValue(st); - globals = new Env(*definition.name, a, globals); + globals.Set(*definition.name, a); } -auto FunctionDeclaration::InitGlobals(Env*& globals) const -> void { - Env* env = nullptr; +auto FunctionDeclaration::InitGlobals(Env& globals) const -> void { + Env env; 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); + globals.Set(definition->name, a); } // { S, H} -> { { C, E, F} :: S, H} @@ -309,15 +314,15 @@ void CallFunction(int line_num, std::vector operas, State* state) { case ValKind::FunV: { // Bind arguments to parameters std::list params; - Env* env = PatternMatch(operas[0]->u.fun.param, operas[1], globals, - ¶ms, line_num); - if (!env) { + std::optional envWithMatches = PatternMatch( + operas[0]->u.fun.param, operas[1], globals, ¶ms, line_num); + if (!envWithMatches) { std::cerr << "internal error in call_function, pattern match failed" << std::endl; exit(-1); } // Create the new frame and push it on the stack - auto* scope = new Scope(env, params); + auto* scope = new Scope(*envWithMatches, params); auto* frame = new Frame(*operas[0]->u.fun.name, Stack(scope), Stack(MakeStmtAct(operas[0]->u.fun.body))); state->stack.Push(frame); @@ -348,8 +353,12 @@ void CallFunction(int line_num, std::vector operas, State* state) { void KillScope(int line_num, Scope* scope) { for (const auto& l : scope->locals) { - Address a = Lookup(line_num, scope->env, l, PrintErrorString); - KillValue(state->heap[a]); + std::optional
a = scope->env.Get(l); + if (!a) { + std::cerr << "internal error in KillScope" << std::endl; + exit(-1); + } + KillValue(state->heap[*a]); } } @@ -395,9 +404,13 @@ auto ToValue(Expression* value) -> Value* { } } -// Returns 0 if the value doesn't match the pattern. -auto PatternMatch(Value* p, Value* v, Env* env, std::list* vars, - int line_num) -> Env* { +// Returns an updated environment that includes the bindings of +// pattern variables to their matched values, if matching succeeds. +// +// The names of the pattern variables are added to the vars parameter. +// Returns nullopt if the value doesn't match the pattern. +auto PatternMatch(Value* p, Value* v, Env env, std::list* vars, + int line_num) -> std::optional { if (tracing_output) { std::cout << "pattern_match("; PrintValue(p, std::cout); @@ -409,7 +422,8 @@ auto PatternMatch(Value* p, Value* v, Env* env, std::list* vars, case ValKind::VarPatV: { Address a = AllocateValue(CopyVal(v, line_num)); vars->push_back(*p->u.var_pat.name); - return new Env(*p->u.var_pat.name, a, env); + env.Set(*p->u.var_pat.name, a); + return env; } case ValKind::TupleV: switch (v->tag) { @@ -427,9 +441,13 @@ auto PatternMatch(Value* p, Value* v, Env* env, std::list* vars, std::cerr << std::endl; exit(-1); } - env = PatternMatch(state->heap[elt.second], state->heap[*a], env, - vars, line_num); - } + std::optional envWithMatches = PatternMatch( + state->heap[elt.second], state->heap[*a], env, vars, line_num); + if (!envWithMatches) { + return std::nullopt; + } + env = *envWithMatches; + } // for return env; } default: @@ -444,10 +462,14 @@ auto PatternMatch(Value* p, Value* v, Env* env, std::list* vars, case ValKind::AltV: { if (*p->u.alt.choice_name != *v->u.alt.choice_name || *p->u.alt.alt_name != *v->u.alt.alt_name) { - return nullptr; + return std::nullopt; } - env = PatternMatch(p->u.alt.arg, v->u.alt.arg, env, vars, line_num); - return env; + std::optional envWithMatches = + PatternMatch(p->u.alt.arg, v->u.alt.arg, env, vars, line_num); + if (!envWithMatches) { + return std::nullopt; + } + return *envWithMatches; } default: std::cerr @@ -459,20 +481,23 @@ auto PatternMatch(Value* p, Value* v, Env* env, std::list* vars, } case ValKind::FunctionTV: switch (v->tag) { - case ValKind::FunctionTV: - env = PatternMatch(p->u.fun_type.param, v->u.fun_type.param, env, - vars, line_num); - env = PatternMatch(p->u.fun_type.ret, v->u.fun_type.ret, env, vars, - line_num); - return env; + case ValKind::FunctionTV: { + std::optional envWithMatches = PatternMatch( + p->u.fun_type.param, v->u.fun_type.param, env, vars, line_num); + if (!envWithMatches) { + return std::nullopt; + } + return PatternMatch(p->u.fun_type.ret, v->u.fun_type.ret, + *envWithMatches, vars, line_num); + } default: - return nullptr; + return std::nullopt; } default: if (ValueEqual(p, v, line_num)) { return env; } else { - return nullptr; + return std::nullopt; } } } @@ -542,7 +567,7 @@ void PatternAssignment(Value* pat, Value* val, int line_num) { } } -/***** state transitions for lvalues *****/ +// State transitions for lvalues. void StepLvalue() { Frame* frame = state->stack.Top(); @@ -557,9 +582,14 @@ void StepLvalue() { case ExpressionKind::Variable: { // { {x :: C, E, F} :: S, H} // -> { {E(x) :: C, E, F} :: S, H} - Address a = Lookup(exp->line_num, CurrentEnv(state), - *(exp->u.variable.name), PrintErrorString); - Value* v = MakePtrVal(a); + std::optional
pointer = + CurrentEnv(state).Get(*(exp->u.variable.name)); + if (!pointer) { + std::cerr << exp->line_num << ": could not find `" + << *(exp->u.variable.name) << "`" << std::endl; + exit(-1); + } + Value* v = MakePtrVal(*pointer); CheckAlive(v, exp->line_num); frame->todo.Pop(); frame->todo.Push(MakeValAct(v)); @@ -604,7 +634,7 @@ void StepLvalue() { } } -/***** state transitions for expressions *****/ +// State transitions for expressions. void StepExp() { Frame* frame = state->stack.Top(); @@ -649,11 +679,16 @@ void StepExp() { } case ExpressionKind::Variable: { // { {x :: C, E, F} :: S, H} -> { {H(E(x)) :: C, E, F} :: S, H} - Address a = Lookup(exp->line_num, CurrentEnv(state), - *(exp->u.variable.name), PrintErrorString); - Value* v = state->heap[a]; + std::optional
pointer = + CurrentEnv(state).Get(*(exp->u.variable.name)); + if (!pointer) { + std::cerr << exp->line_num << ": could not find `" + << *(exp->u.variable.name) << "`" << std::endl; + exit(-1); + } + Value* pointee = state->heap[*pointer]; frame->todo.Pop(1); - frame->todo.Push(MakeValAct(v)); + frame->todo.Push(MakeValAct(pointee)); break; } case ExpressionKind::Integer: @@ -719,8 +754,6 @@ void StepExp() { } // switch (exp->tag) } -/***** state transitions for statements *****/ - auto IsWhileAct(Action* act) -> bool { switch (act->tag) { case ActionKind::StatementAction: @@ -749,6 +782,8 @@ auto IsBlockAct(Action* act) -> bool { } } +// State transitions for statements. + void StepStmt() { Frame* frame = state->stack.Top(); Action* act = frame->todo.Top(); @@ -918,7 +953,7 @@ void InsertDelete(Action* del, Stack& todo) { } } -/***** State transition for handling a value *****/ +// State transition for handling a value. void HandleValue() { Frame* frame = state->stack.Top(); @@ -1150,17 +1185,18 @@ void HandleValue() { // -> { { C, E(x := a), F} :: S, H(a := copy(v))} Value* v = act->results[0]; Value* p = act->results[1]; - // Address a = AllocateValue(CopyVal(v)); - frame->scopes.Top()->env = + + std::optional envWithMatches = PatternMatch(p, v, frame->scopes.Top()->env, &frame->scopes.Top()->locals, stmt->line_num); - if (!frame->scopes.Top()->env) { + if (!envWithMatches) { std::cerr << stmt->line_num << ": internal error in variable definition, match failed" << std::endl; exit(-1); } + frame->scopes.Top()->env = *envWithMatches; frame->todo.Pop(2); } break; @@ -1244,9 +1280,10 @@ void HandleValue() { auto pat = act->results[clause_num + 1]; auto env = CurrentEnv(state); std::list vars; - Env* new_env = PatternMatch(pat, v, env, &vars, stmt->line_num); - if (new_env) { // we have a match, start the body - auto* new_scope = new Scope(new_env, vars); + std::optional envWithMatches = + PatternMatch(pat, v, env, &vars, stmt->line_num); + if (envWithMatches) { // we have a match, start the body + auto* new_scope = new Scope(*envWithMatches, vars); frame->scopes.Push(new_scope); Statement* body_block = MakeBlock(stmt->line_num, c->second); Action* body_act = MakeStmtAct(body_block); @@ -1255,11 +1292,12 @@ void HandleValue() { frame->todo.Push(body_act); frame->todo.Push(MakeStmtAct(c->second)); } else { + // this case did not match, moving on act->pos++; clause_num = (act->pos - 1) / 2; if (clause_num < static_cast(stmt->u.match_stmt.clauses->size())) { - // move on to the next clause + // interpret the next clause c = stmt->u.match_stmt.clauses->begin(); std::advance(c, clause_num); frame->todo.Pop(1); @@ -1366,7 +1404,7 @@ auto InterpProgram(std::list* fs) -> int { } // Interpret an expression at compile-time. -auto InterpExp(Env* env, Expression* e) -> Value* { +auto InterpExp(Env env, Expression* e) -> Value* { auto todo = Stack(MakeExpAct(e)); auto* scope = new Scope(env, std::list()); auto* frame = new Frame("InterpExp", Stack(scope), todo); diff --git a/executable_semantics/interpreter/interpreter.h b/executable_semantics/interpreter/interpreter.h index c2bb9a09d6cc..803b35de5a35 100644 --- a/executable_semantics/interpreter/interpreter.h +++ b/executable_semantics/interpreter/interpreter.h @@ -11,19 +11,19 @@ #include "executable_semantics/ast/declaration.h" #include "executable_semantics/interpreter/action.h" -#include "executable_semantics/interpreter/assoc_list.h" +#include "executable_semantics/interpreter/dictionary.h" #include "executable_semantics/interpreter/stack.h" #include "executable_semantics/interpreter/value.h" namespace Carbon { -using Env = AssocList; +using Env = Dictionary; /***** Scopes *****/ struct Scope { - Scope(Env* e, std::list l) : env(e), locals(std::move(l)) {} - Env* env; + Scope(Env e, std::list l) : env(e), locals(std::move(l)) {} + Env env; std::list locals; }; @@ -45,7 +45,7 @@ struct State { extern State* state; -void PrintEnv(Env* env); +void PrintEnv(Env env); auto AllocateValue(Value* v) -> Address; auto CopyVal(Value* val, int line_num) -> Value*; auto ToInteger(Value* v) -> int; @@ -53,7 +53,7 @@ auto ToInteger(Value* v) -> int; /***** Interpreters *****/ auto InterpProgram(std::list* fs) -> int; -auto InterpExp(Env* env, Expression* e) -> Value*; +auto InterpExp(Env env, Expression* e) -> Value*; } // namespace Carbon diff --git a/executable_semantics/interpreter/typecheck.cpp b/executable_semantics/interpreter/typecheck.cpp index 0e361f77dce0..85df48232b4f 100644 --- a/executable_semantics/interpreter/typecheck.cpp +++ b/executable_semantics/interpreter/typecheck.cpp @@ -31,12 +31,11 @@ void ExpectType(int line_num, const std::string& context, Value* expected, void PrintErrorString(const std::string& s) { std::cerr << s; } -void PrintTypeEnv(TypeEnv* env, std::ostream& out) { - if (env) { - out << env->key << ": "; - PrintValue(env->value, out); +void PrintTypeEnv(TypeEnv env, std::ostream& out) { + for (const auto& [name, value] : env) { + out << name << ": "; + PrintValue(value, out); out << ", "; - PrintTypeEnv(env->next, out); } } @@ -138,7 +137,7 @@ auto ReifyType(Value* t, int line_num) -> Expression* { // and it is used to implement `auto`, otherwise it is null. // context says what kind of position this expression is nested in, // whether it's a position that expects a value, a pattern, or a type. -auto TypeCheckExp(Expression* e, TypeEnv* env, Env* ct_env, Value* expected, +auto TypeCheckExp(Expression* e, TypeEnv env, Env ct_env, Value* expected, TCContext context) -> TCResult { switch (e->tag) { case ExpressionKind::PatternVariable: { @@ -164,8 +163,8 @@ auto TypeCheckExp(Expression* e, TypeEnv* env, Env* ct_env, Value* expected, } auto new_e = MakeVarPat(e->line_num, *e->u.pattern_variable.name, ReifyType(t, e->line_num)); - return TCResult(new_e, t, - new TypeEnv(*e->u.pattern_variable.name, t, env)); + env.Set(*e->u.pattern_variable.name, t); + return TCResult(new_e, t, env); } case ExpressionKind::Index: { auto res = TypeCheckExp(e->u.get_field.aggregate, env, ct_env, nullptr, @@ -282,9 +281,14 @@ auto TypeCheckExp(Expression* e, TypeEnv* env, Env* ct_env, Value* expected, } } case ExpressionKind::Variable: { - auto t = - Lookup(e->line_num, env, *(e->u.variable.name), PrintErrorString); - return TCResult(e, t, env); + std::optional type = env.Get(*(e->u.variable.name)); + if (type) { + return TCResult(e, *type, env); + } else { + std::cerr << e->line_num << ": could not find `" + << *(e->u.variable.name) << "`" << std::endl; + exit(-1); + } } case ExpressionKind::Integer: return TCResult(e, MakeIntTypeVal(), env); @@ -386,7 +390,7 @@ auto TypeCheckExp(Expression* e, TypeEnv* env, Env* ct_env, Value* expected, } auto TypecheckCase(Value* expected, Expression* pat, Statement* body, - TypeEnv* env, Env* ct_env, Value* ret_type) + TypeEnv env, Env ct_env, Value* ret_type) -> std::pair { auto pat_res = TypeCheckExp(pat, env, ct_env, expected, TCContext::PatternContext); @@ -401,7 +405,7 @@ auto TypecheckCase(Value* expected, Expression* pat, Statement* body, // It is the declared return type of the enclosing function definition. // If the return type is "auto", then the return type is inferred from // the first return statement. -auto TypeCheckStmt(Statement* s, TypeEnv* env, Env* ct_env, Value* ret_type) +auto TypeCheckStmt(Statement* s, TypeEnv env, Env ct_env, Value* ret_type) -> TCStatement { if (!s) { return TCStatement(s, env); @@ -565,7 +569,7 @@ auto CheckOrEnsureReturn(Statement* stmt, bool void_return, int line_num) } } -auto TypeCheckFunDef(const FunctionDefinition* f, TypeEnv* env, Env* ct_env) +auto TypeCheckFunDef(const FunctionDefinition* f, TypeEnv env, Env ct_env) -> struct FunctionDefinition* { auto param_res = TypeCheckExp(f->param_pattern, env, ct_env, nullptr, TCContext::PatternContext); @@ -582,7 +586,7 @@ auto TypeCheckFunDef(const FunctionDefinition* f, TypeEnv* env, Env* ct_env) f->param_pattern, body); } -auto TypeOfFunDef(TypeEnv* env, Env* ct_env, const FunctionDefinition* fun_def) +auto TypeOfFunDef(TypeEnv env, Env ct_env, const FunctionDefinition* fun_def) -> Value* { auto param_res = TypeCheckExp(fun_def->param_pattern, env, ct_env, nullptr, TCContext::PatternContext); @@ -595,7 +599,7 @@ auto TypeOfFunDef(TypeEnv* env, Env* ct_env, const FunctionDefinition* fun_def) return MakeFunTypeVal(param_type, ret); } -auto TypeOfStructDef(const StructDefinition* sd, TypeEnv* /*env*/, Env* ct_top) +auto TypeOfStructDef(const StructDefinition* sd, TypeEnv /*env*/, Env ct_top) -> Value* { auto fields = new VarValues(); auto methods = new VarValues(); @@ -616,7 +620,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 +auto StructDeclaration::TypeChecked(TypeEnv env, Env ct_env) const -> Declaration { auto fields = new std::list(); for (auto& m : *definition.members) { @@ -628,18 +632,18 @@ auto StructDeclaration::TypeChecked(TypeEnv* env, Env* ct_env) const return StructDeclaration(definition.line_num, *definition.name, fields); } -auto FunctionDeclaration::TypeChecked(TypeEnv* env, Env* ct_env) const +auto FunctionDeclaration::TypeChecked(TypeEnv env, Env ct_env) const -> Declaration { return FunctionDeclaration(TypeCheckFunDef(definition, env, ct_env)); } -auto ChoiceDeclaration::TypeChecked(TypeEnv* env, Env* ct_env) const +auto ChoiceDeclaration::TypeChecked(TypeEnv env, Env ct_env) const -> Declaration { return *this; // TODO. } -auto TopLevel(std::list* fs) -> std::pair { - ExecutionEnvironment tops = {nullptr, nullptr}; +auto TopLevel(std::list* fs) -> std::pair { + ExecutionEnvironment tops; bool found_main = false; for (auto const& d : *fs) { @@ -659,16 +663,16 @@ auto TopLevel(std::list* fs) -> std::pair { auto FunctionDeclaration::TopLevel(ExecutionEnvironment& tops) const -> void { auto t = TypeOfFunDef(tops.first, tops.second, definition); - tops.first = new TypeEnv(Name(), t, tops.first); + tops.first.Set(Name(), t); } auto StructDeclaration::TopLevel(ExecutionEnvironment& tops) const -> void { auto st = TypeOfStructDef(&definition, tops.first, tops.second); Address a = AllocateValue(st); - tops.second = new Env(Name(), a, tops.second); // Is this obsolete? + tops.second.Set(Name(), a); // Is this obsolete? auto params = MakeTupleTypeVal(st->u.struct_type.fields); auto fun_ty = MakeFunTypeVal(params, st); - tops.first = new TypeEnv(Name(), fun_ty, tops.first); + tops.first.Set(Name(), fun_ty); } auto ChoiceDeclaration::TopLevel(ExecutionEnvironment& tops) const -> void { @@ -679,8 +683,8 @@ auto ChoiceDeclaration::TopLevel(ExecutionEnvironment& tops) const -> void { } auto ct = MakeChoiceTypeVal(name, alts); Address a = AllocateValue(ct); - tops.second = new Env(Name(), a, tops.second); // Is this obsolete? - tops.first = new TypeEnv(Name(), ct, tops.first); + tops.second.Set(Name(), a); // Is this obsolete? + tops.first.Set(Name(), ct); } } // namespace Carbon diff --git a/executable_semantics/interpreter/typecheck.h b/executable_semantics/interpreter/typecheck.h index c018a1d43bd3..7aed729fcfdb 100644 --- a/executable_semantics/interpreter/typecheck.h +++ b/executable_semantics/interpreter/typecheck.h @@ -9,43 +9,43 @@ #include "executable_semantics/ast/expression.h" #include "executable_semantics/ast/statement.h" -#include "executable_semantics/interpreter/assoc_list.h" +#include "executable_semantics/interpreter/dictionary.h" #include "executable_semantics/interpreter/interpreter.h" namespace Carbon { -using TypeEnv = AssocList; +using TypeEnv = Dictionary; -void PrintTypeEnv(TypeEnv* env); +void PrintTypeEnv(TypeEnv env); enum class TCContext { ValueContext, PatternContext, TypeContext }; struct TCResult { - TCResult(Expression* e, Value* t, TypeEnv* env) : exp(e), type(t), env(env) {} + TCResult(Expression* e, Value* t, TypeEnv env) : exp(e), type(t), env(env) {} Expression* exp; Value* type; - TypeEnv* env; + TypeEnv env; }; struct TCStatement { - TCStatement(Statement* s, TypeEnv* e) : stmt(s), env(e) {} + TCStatement(Statement* s, TypeEnv e) : stmt(s), env(e) {} Statement* stmt; - TypeEnv* env; + TypeEnv env; }; auto ToType(int line_num, Value* val) -> Value*; -auto TypeCheckExp(Expression* e, TypeEnv* env, Env* ct_env, Value* expected, +auto TypeCheckExp(Expression* e, TypeEnv env, Env ct_env, Value* expected, TCContext context) -> TCResult; -auto TypeCheckStmt(Statement*, TypeEnv*, Env*, Value*) -> TCStatement; +auto TypeCheckStmt(Statement*, TypeEnv, Env, Value*) -> TCStatement; -auto TypeCheckFunDef(struct FunctionDefinition*, TypeEnv*) +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/syntax_helpers.cpp b/executable_semantics/syntax/syntax_helpers.cpp index fc8a9c129e0b..3279f6ab56b6 100644 --- a/executable_semantics/syntax/syntax_helpers.cpp +++ b/executable_semantics/syntax/syntax_helpers.cpp @@ -28,9 +28,9 @@ void ExecProgram(std::list* fs) { 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::pair p = TopLevel(fs); + TypeEnv top = p.first; + Env ct_top = p.second; std::list new_decls; for (const auto& decl : *fs) { new_decls.push_back(decl.TypeChecked(top, ct_top));