mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 22:02:23 +01:00
replace uses of AssocList with Dictionary (#344)
Co-authored-by: Geoff Romer <gromer@google.com> Co-authored-by: Dave Abrahams <dabrahams@google.com>
This commit is contained in:
committed by
GitHub
co-authored by
Geoff Romer
Dave Abrahams
parent
5d6593ee39
commit
05db2012ab
@@ -14,6 +14,7 @@ cc_library(
|
||||
":function_definition",
|
||||
":member",
|
||||
":struct_definition",
|
||||
"//executable_semantics/interpreter:containers",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -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 <class K, class V>
|
||||
struct AssocList;
|
||||
|
||||
using Address = unsigned int;
|
||||
using TypeEnv = AssocList<std::string, Value*>;
|
||||
using Env = AssocList<std::string, Address>;
|
||||
using TypeEnv = Dictionary<std::string, Value*>;
|
||||
using Env = Dictionary<std::string, Address>;
|
||||
|
||||
/// TODO:explain this. Also name it if necessary. Consult with jsiek.
|
||||
using ExecutionEnvironment = std::pair<TypeEnv*, Env*>;
|
||||
using ExecutionEnvironment = std::pair<TypeEnv, Env>;
|
||||
|
||||
/// 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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -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 <iostream>
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
template <class K, class V>
|
||||
struct AssocList {
|
||||
AssocList(K k, V v, AssocList* n) : key(k), value(v), next(n) {}
|
||||
|
||||
K key;
|
||||
V value;
|
||||
AssocList* next;
|
||||
};
|
||||
|
||||
template <class K, class V>
|
||||
auto Lookup(int line_num, AssocList<K, V>* 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_
|
||||
@@ -22,8 +22,8 @@ namespace Carbon {
|
||||
|
||||
State* state = nullptr;
|
||||
|
||||
auto PatternMatch(Value* pat, Value* val, Env*, std::list<std::string>*, int)
|
||||
-> Env*;
|
||||
auto PatternMatch(Value* pat, Value* val, Env, std::list<std::string>*, int)
|
||||
-> std::optional<Env>;
|
||||
void HandleValue();
|
||||
|
||||
template <class T>
|
||||
@@ -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<Value*>& 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<Value*>& args, int line_num)
|
||||
}
|
||||
}
|
||||
|
||||
Env* globals;
|
||||
// Globally-defined entities, such as functions, structs, choices.
|
||||
Env globals;
|
||||
|
||||
void InitGlobals(std::list<Declaration>* 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<Value*> operas, State* state) {
|
||||
case ValKind::FunV: {
|
||||
// Bind arguments to parameters
|
||||
std::list<std::string> params;
|
||||
Env* env = PatternMatch(operas[0]->u.fun.param, operas[1], globals,
|
||||
¶ms, line_num);
|
||||
if (!env) {
|
||||
std::optional<Env> 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<Value*> 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<Address> 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<std::string>* 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<std::string>* vars,
|
||||
int line_num) -> std::optional<Env> {
|
||||
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<std::string>* 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<std::string>* vars,
|
||||
std::cerr << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
env = PatternMatch(state->heap[elt.second], state->heap[*a], env,
|
||||
vars, line_num);
|
||||
}
|
||||
std::optional<Env> 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<std::string>* 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<Env> 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<std::string>* 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<Env> 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<Address> 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<Address> 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<Action*>& 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<Env> 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<std::string> 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<Env> 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<int>(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<Declaration>* 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<std::string>());
|
||||
auto* frame = new Frame("InterpExp", Stack(scope), todo);
|
||||
|
||||
@@ -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<std::string, Address>;
|
||||
using Env = Dictionary<std::string, Address>;
|
||||
|
||||
/***** Scopes *****/
|
||||
|
||||
struct Scope {
|
||||
Scope(Env* e, std::list<std::string> l) : env(e), locals(std::move(l)) {}
|
||||
Env* env;
|
||||
Scope(Env e, std::list<std::string> l) : env(e), locals(std::move(l)) {}
|
||||
Env env;
|
||||
std::list<std::string> 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<Declaration>* fs) -> int;
|
||||
auto InterpExp(Env* env, Expression* e) -> Value*;
|
||||
auto InterpExp(Env env, Expression* e) -> Value*;
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
|
||||
@@ -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<Value*> 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<Expression*, Statement*> {
|
||||
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<Member*>();
|
||||
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<Declaration>* fs) -> std::pair<TypeEnv*, Env*> {
|
||||
ExecutionEnvironment tops = {nullptr, nullptr};
|
||||
auto TopLevel(std::list<Declaration>* fs) -> std::pair<TypeEnv, Env> {
|
||||
ExecutionEnvironment tops;
|
||||
bool found_main = false;
|
||||
|
||||
for (auto const& d : *fs) {
|
||||
@@ -659,16 +663,16 @@ auto TopLevel(std::list<Declaration>* fs) -> std::pair<TypeEnv*, Env*> {
|
||||
|
||||
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
|
||||
|
||||
@@ -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<std::string, Value*>;
|
||||
using TypeEnv = Dictionary<std::string, Value*>;
|
||||
|
||||
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<Declaration>* fs) -> std::pair<TypeEnv*, Env*>;
|
||||
auto TopLevel(std::list<Declaration>* fs) -> std::pair<TypeEnv, Env>;
|
||||
|
||||
void PrintErrorString(const std::string& s);
|
||||
|
||||
|
||||
@@ -28,9 +28,9 @@ void ExecProgram(std::list<Declaration>* fs) {
|
||||
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::pair<TypeEnv, Env> p = TopLevel(fs);
|
||||
TypeEnv top = p.first;
|
||||
Env ct_top = p.second;
|
||||
std::list<Declaration> new_decls;
|
||||
for (const auto& decl : *fs) {
|
||||
new_decls.push_back(decl.TypeChecked(top, ct_top));
|
||||
|
||||
Reference in New Issue
Block a user