mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
const-ify Value*s in preparation for value semantic transformation (#409)
Making Values const allows us to separate the actual mutations (search for "*&" in this change) from places where the Value is effectively passed by-value.
This commit is contained in:
@@ -83,7 +83,7 @@ auto MakeStmtAct(Statement* s) -> Action* {
|
||||
return act;
|
||||
}
|
||||
|
||||
auto MakeValAct(Value* v) -> Action* {
|
||||
auto MakeValAct(const Value* v) -> Action* {
|
||||
auto* act = new Action();
|
||||
act->tag = ActionKind::ValAction;
|
||||
act->u.val = v;
|
||||
|
||||
@@ -29,11 +29,11 @@ struct Action {
|
||||
union {
|
||||
Expression* exp; // for LValAction and ExpressionAction
|
||||
Statement* stmt;
|
||||
Value* val; // for finished actions with a value (ValAction)
|
||||
const Value* val; // for finished actions with a value (ValAction)
|
||||
Address delete_tmp;
|
||||
} u;
|
||||
int pos; // position or state of the action
|
||||
std::vector<Value*> results; // results from subexpression
|
||||
int pos; // position or state of the action
|
||||
std::vector<const Value*> results; // results from subexpression
|
||||
};
|
||||
|
||||
void PrintAct(Action* act, std::ostream& out);
|
||||
@@ -41,7 +41,7 @@ void PrintActList(Stack<Action*> ls, std::ostream& out);
|
||||
auto MakeExpAct(Expression* e) -> Action*;
|
||||
auto MakeLvalAct(Expression* e) -> Action*;
|
||||
auto MakeStmtAct(Statement* s) -> Action*;
|
||||
auto MakeValAct(Value* v) -> Action*;
|
||||
auto MakeValAct(const Value* v) -> Action*;
|
||||
auto MakeExpToLvalAct() -> Action*;
|
||||
auto MakeDeleteAct(Address a) -> Action*;
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ namespace Carbon {
|
||||
|
||||
State* state = nullptr;
|
||||
|
||||
auto PatternMatch(Value* pat, Value* val, Env, std::list<std::string>*, int)
|
||||
-> std::optional<Env>;
|
||||
auto PatternMatch(const Value* pat, const Value* val, Env,
|
||||
std::list<std::string>*, int) -> std::optional<Env>;
|
||||
void HandleValue();
|
||||
|
||||
template <class T>
|
||||
@@ -42,37 +42,37 @@ static auto FindField(const std::string& field,
|
||||
// Auxiliary Functions
|
||||
//
|
||||
|
||||
auto AllocateValue(Value* v) -> Address {
|
||||
auto AllocateValue(const Value* v) -> Address {
|
||||
// Putting the following two side effects together in this function
|
||||
// ensures that we don't do anything else in between, which is really bad!
|
||||
// Consider whether to include a copy of the input v in this function
|
||||
// or to leave it up to the caller.
|
||||
Address a = state->heap.size();
|
||||
state->heap.push_back(v);
|
||||
state->heap.push_back(new Value(*v));
|
||||
state->alive.push_back(true);
|
||||
return a;
|
||||
}
|
||||
|
||||
auto CopyVal(Value* val, int line_num) -> Value* {
|
||||
auto CopyVal(const Value* val, int line_num) -> const Value* {
|
||||
switch (val->tag) {
|
||||
case ValKind::TupleV: {
|
||||
auto elts = new std::vector<std::pair<std::string, Address>>();
|
||||
for (auto& i : *val->u.tuple.elts) {
|
||||
CheckAlive(i.second, line_num);
|
||||
Value* elt = CopyVal(state->heap[i.second], line_num);
|
||||
const Value* elt = CopyVal(state->heap[i.second], line_num);
|
||||
Address new_address = AllocateValue(elt);
|
||||
elts->push_back(make_pair(i.first, new_address));
|
||||
}
|
||||
return MakeTupleVal(elts);
|
||||
}
|
||||
case ValKind::AltV: {
|
||||
Value* arg = CopyVal(state->heap[val->u.alt.argument], line_num);
|
||||
const Value* arg = CopyVal(state->heap[val->u.alt.argument], line_num);
|
||||
Address argument_address = AllocateValue(arg);
|
||||
return MakeAltVal(*val->u.alt.alt_name, *val->u.alt.choice_name,
|
||||
argument_address);
|
||||
}
|
||||
case ValKind::StructV: {
|
||||
Value* inits = CopyVal(val->u.struct_val.inits, line_num);
|
||||
const Value* inits = CopyVal(val->u.struct_val.inits, line_num);
|
||||
return MakeStructVal(val->u.struct_val.type, inits);
|
||||
}
|
||||
case ValKind::IntV:
|
||||
@@ -119,7 +119,7 @@ auto CopyVal(Value* val, int line_num) -> Value* {
|
||||
void KillObject(Address address);
|
||||
|
||||
// Marks all of the sub-objects of this value as dead.
|
||||
void KillSubObjects(Value* val) {
|
||||
void KillSubObjects(const Value* val) {
|
||||
switch (val->tag) {
|
||||
case ValKind::AltV:
|
||||
KillObject(val->u.alt.argument);
|
||||
@@ -177,7 +177,7 @@ void PrintStack(Stack<Frame*> ls, std::ostream& out) {
|
||||
}
|
||||
}
|
||||
|
||||
void PrintHeap(const std::vector<Value*>& heap, std::ostream& out) {
|
||||
void PrintHeap(const std::vector<const Value*>& heap, std::ostream& out) {
|
||||
for (auto& iter : heap) {
|
||||
if (iter) {
|
||||
PrintValue(iter, out);
|
||||
@@ -208,7 +208,7 @@ void PrintState(std::ostream& out) {
|
||||
// More Auxiliary Functions
|
||||
//
|
||||
|
||||
auto ValToInt(Value* v, int line_num) -> int {
|
||||
auto ValToInt(const Value* v, int line_num) -> int {
|
||||
switch (v->tag) {
|
||||
case ValKind::IntV:
|
||||
return v->u.integer;
|
||||
@@ -219,7 +219,7 @@ auto ValToInt(Value* v, int line_num) -> int {
|
||||
}
|
||||
}
|
||||
|
||||
auto ValToBool(Value* v, int line_num) -> int {
|
||||
auto ValToBool(const Value* v, int line_num) -> int {
|
||||
switch (v->tag) {
|
||||
case ValKind::BoolV:
|
||||
return v->u.boolean;
|
||||
@@ -229,7 +229,7 @@ auto ValToBool(Value* v, int line_num) -> int {
|
||||
}
|
||||
}
|
||||
|
||||
auto ValToPtr(Value* v, int line_num) -> Address {
|
||||
auto ValToPtr(const Value* v, int line_num) -> Address {
|
||||
CheckAlive(v->u.ptr, line_num);
|
||||
switch (v->tag) {
|
||||
case ValKind::PtrV:
|
||||
@@ -242,8 +242,8 @@ auto ValToPtr(Value* v, int line_num) -> Address {
|
||||
}
|
||||
}
|
||||
|
||||
auto EvalPrim(Operator op, const std::vector<Value*>& args, int line_num)
|
||||
-> Value* {
|
||||
auto EvalPrim(Operator op, const std::vector<const Value*>& args, int line_num)
|
||||
-> const Value* {
|
||||
switch (op) {
|
||||
case Operator::Neg:
|
||||
return MakeIntVal(-ValToInt(args[0], line_num));
|
||||
@@ -325,7 +325,8 @@ auto VariableDeclaration::InitGlobals(Env& globals) const -> void {
|
||||
// where C is the body of the function,
|
||||
// E is the environment (functions + parameters + locals)
|
||||
// F is the function
|
||||
void CallFunction(int line_num, std::vector<Value*> operas, State* state) {
|
||||
void CallFunction(int line_num, std::vector<const Value*> operas,
|
||||
State* state) {
|
||||
switch (operas[0]->tag) {
|
||||
case ValKind::FunV: {
|
||||
// Bind arguments to parameters
|
||||
@@ -345,15 +346,15 @@ void CallFunction(int line_num, std::vector<Value*> operas, State* state) {
|
||||
break;
|
||||
}
|
||||
case ValKind::StructTV: {
|
||||
Value* arg = CopyVal(operas[1], line_num);
|
||||
Value* sv = MakeStructVal(operas[0], arg);
|
||||
const Value* arg = CopyVal(operas[1], line_num);
|
||||
const Value* sv = MakeStructVal(operas[0], arg);
|
||||
Frame* frame = state->stack.Top();
|
||||
frame->todo.Push(MakeValAct(sv));
|
||||
break;
|
||||
}
|
||||
case ValKind::AltConsV: {
|
||||
Value* arg = CopyVal(operas[1], line_num);
|
||||
Value* av =
|
||||
const Value* arg = CopyVal(operas[1], line_num);
|
||||
const Value* av =
|
||||
MakeAltVal(*operas[0]->u.alt_cons.alt_name,
|
||||
*operas[0]->u.alt_cons.choice_name, AllocateValue(arg));
|
||||
Frame* frame = state->stack.Top();
|
||||
@@ -394,7 +395,7 @@ void CreateTuple(Frame* frame, Action* act, Expression* /*exp*/) {
|
||||
Address a = AllocateValue(*i); // copy?
|
||||
elts->push_back(make_pair(f->first, a));
|
||||
}
|
||||
Value* tv = MakeTupleVal(elts);
|
||||
const Value* tv = MakeTupleVal(elts);
|
||||
frame->todo.Pop(1);
|
||||
frame->todo.Push(MakeValAct(tv));
|
||||
}
|
||||
@@ -404,8 +405,9 @@ void CreateTuple(Frame* frame, Action* act, Expression* /*exp*/) {
|
||||
//
|
||||
// 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> {
|
||||
auto PatternMatch(const Value* p, const Value* v, Env env,
|
||||
std::list<std::string>* vars, int line_num)
|
||||
-> std::optional<Env> {
|
||||
switch (p->tag) {
|
||||
case ValKind::VarPatV: {
|
||||
Address a = AllocateValue(CopyVal(v, line_num));
|
||||
@@ -491,7 +493,7 @@ auto PatternMatch(Value* p, Value* v, Env env, std::list<std::string>* vars,
|
||||
}
|
||||
}
|
||||
|
||||
void PatternAssignment(Value* pat, Value* val, int line_num) {
|
||||
void PatternAssignment(const Value* pat, const Value* val, int line_num) {
|
||||
switch (pat->tag) {
|
||||
case ValKind::PtrV:
|
||||
state->heap[ValToPtr(pat, line_num)] = val;
|
||||
@@ -579,7 +581,7 @@ void StepLvalue() {
|
||||
<< *(exp->u.variable.name) << "`" << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
Value* v = MakePtrVal(*pointer);
|
||||
const Value* v = MakePtrVal(*pointer);
|
||||
CheckAlive(*pointer, exp->line_num);
|
||||
frame->todo.Pop();
|
||||
frame->todo.Push(MakeValAct(v));
|
||||
@@ -676,7 +678,7 @@ void StepExp() {
|
||||
<< *(exp->u.variable.name) << "`" << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
Value* pointee = state->heap[*pointer];
|
||||
const Value* pointee = state->heap[*pointer];
|
||||
frame->todo.Pop(1);
|
||||
frame->todo.Push(MakeValAct(pointee));
|
||||
break;
|
||||
@@ -700,7 +702,7 @@ void StepExp() {
|
||||
} else {
|
||||
// { {v :: op(]) :: C, E, F} :: S, H}
|
||||
// -> { {eval_prim(op, ()) :: C, E, F} :: S, H}
|
||||
Value* v =
|
||||
const Value* v =
|
||||
EvalPrim(exp->u.primitive_op.op, act->results, exp->line_num);
|
||||
frame->todo.Pop(2);
|
||||
frame->todo.Push(MakeValAct(v));
|
||||
@@ -713,25 +715,25 @@ void StepExp() {
|
||||
act->pos++;
|
||||
break;
|
||||
case ExpressionKind::IntT: {
|
||||
Value* v = MakeIntTypeVal();
|
||||
const Value* v = MakeIntTypeVal();
|
||||
frame->todo.Pop(1);
|
||||
frame->todo.Push(MakeValAct(v));
|
||||
break;
|
||||
}
|
||||
case ExpressionKind::BoolT: {
|
||||
Value* v = MakeBoolTypeVal();
|
||||
const Value* v = MakeBoolTypeVal();
|
||||
frame->todo.Pop(1);
|
||||
frame->todo.Push(MakeValAct(v));
|
||||
break;
|
||||
}
|
||||
case ExpressionKind::AutoT: {
|
||||
Value* v = MakeAutoTypeVal();
|
||||
const Value* v = MakeAutoTypeVal();
|
||||
frame->todo.Pop(1);
|
||||
frame->todo.Push(MakeValAct(v));
|
||||
break;
|
||||
}
|
||||
case ExpressionKind::TypeT: {
|
||||
Value* v = MakeTypeTypeVal();
|
||||
const Value* v = MakeTypeTypeVal();
|
||||
frame->todo.Pop(1);
|
||||
frame->todo.Push(MakeValAct(v));
|
||||
break;
|
||||
@@ -878,7 +880,7 @@ void StepStmt() {
|
||||
}
|
||||
|
||||
auto GetMember(Address a, const std::string& f) -> Address {
|
||||
Value* v = state->heap[a];
|
||||
const Value* v = state->heap[a];
|
||||
switch (v->tag) {
|
||||
case ValKind::StructV: {
|
||||
auto a = FindField(f, *v->u.struct_val.inits->u.tuple.elts);
|
||||
@@ -980,7 +982,7 @@ void HandleValue() {
|
||||
case ExpressionKind::GetField: {
|
||||
// { v :: [].f :: C, E, F} :: S, H}
|
||||
// -> { { &v.f :: C, E, F} :: S, H }
|
||||
Value* str = act->results[0];
|
||||
const Value* str = act->results[0];
|
||||
Address a =
|
||||
GetMember(ValToPtr(str, exp->line_num), *exp->u.get_field.field);
|
||||
frame->todo.Pop(2);
|
||||
@@ -994,7 +996,7 @@ void HandleValue() {
|
||||
} else if (act->pos == 2) {
|
||||
// { v :: [][i] :: C, E, F} :: S, H}
|
||||
// -> { { &v[i] :: C, E, F} :: S, H }
|
||||
Value* tuple = act->results[0];
|
||||
const Value* tuple = act->results[0];
|
||||
std::string f = std::to_string(ToInteger(act->results[1]));
|
||||
auto a = FindField(f, *tuple->u.tuple.elts);
|
||||
if (a == std::nullopt) {
|
||||
@@ -1107,7 +1109,7 @@ void HandleValue() {
|
||||
} else {
|
||||
// { {v :: op(vs,[]) :: C, E, F} :: S, H}
|
||||
// -> { {eval_prim(op, (vs,v)) :: C, E, F} :: S, H}
|
||||
Value* v =
|
||||
const Value* v =
|
||||
EvalPrim(exp->u.primitive_op.op, act->results, exp->line_num);
|
||||
frame->todo.Pop(2);
|
||||
frame->todo.Push(MakeValAct(v));
|
||||
@@ -1136,7 +1138,7 @@ void HandleValue() {
|
||||
if (act->pos == 2) {
|
||||
// { { rt :: fn pt -> [] :: C, E, F} :: S, H}
|
||||
// -> { fn pt -> rt :: {C, E, F} :: S, H}
|
||||
Value* v = MakeFunTypeVal(act->results[0], act->results[1]);
|
||||
const Value* v = MakeFunTypeVal(act->results[0], act->results[1]);
|
||||
frame->todo.Pop(2);
|
||||
frame->todo.Push(MakeValAct(v));
|
||||
} else {
|
||||
@@ -1173,8 +1175,8 @@ void HandleValue() {
|
||||
} else if (act->pos == 2) {
|
||||
// { { v :: (x = []) :: C, E, F} :: S, H}
|
||||
// -> { { C, E(x := a), F} :: S, H(a := copy(v))}
|
||||
Value* v = act->results[0];
|
||||
Value* p = act->results[1];
|
||||
const Value* v = act->results[0];
|
||||
const Value* p = act->results[1];
|
||||
|
||||
std::optional<Env> env_with_matches =
|
||||
PatternMatch(p, v, frame->scopes.Top()->env,
|
||||
@@ -1302,7 +1304,7 @@ void HandleValue() {
|
||||
case StatementKind::Return: {
|
||||
// { {v :: return [] :: C, E, F} :: {C', E', F'} :: S, H}
|
||||
// -> { {v :: C', E', F'} :: S, H}
|
||||
Value* ret_val = CopyVal(val_act->u.val, stmt->line_num);
|
||||
const Value* ret_val = CopyVal(val_act->u.val, stmt->line_num);
|
||||
KillLocals(stmt->line_num, frame);
|
||||
state->stack.Pop(1);
|
||||
frame = state->stack.Top();
|
||||
@@ -1389,12 +1391,12 @@ auto InterpProgram(std::list<Declaration>* fs) -> int {
|
||||
PrintState(std::cout);
|
||||
}
|
||||
}
|
||||
Value* v = state->stack.Top()->todo.Top()->u.val;
|
||||
const Value* v = state->stack.Top()->todo.Top()->u.val;
|
||||
return ValToInt(v, 0);
|
||||
}
|
||||
|
||||
// Interpret an expression at compile-time.
|
||||
auto InterpExp(Env env, Expression* e) -> Value* {
|
||||
auto InterpExp(Env env, Expression* e) -> const Value* {
|
||||
auto todo = Stack(MakeExpAct(e));
|
||||
auto* scope = new Scope(env, std::list<std::string>());
|
||||
auto* frame = new Frame("InterpExp", Stack(scope), todo);
|
||||
@@ -1405,7 +1407,7 @@ auto InterpExp(Env env, Expression* e) -> Value* {
|
||||
state->stack.Top()->todo.Top()->tag != ActionKind::ValAction) {
|
||||
Step();
|
||||
}
|
||||
Value* v = state->stack.Top()->todo.Top()->u.val;
|
||||
const Value* v = state->stack.Top()->todo.Top()->u.val;
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,21 +40,21 @@ struct Frame {
|
||||
|
||||
struct State {
|
||||
Stack<Frame*> stack;
|
||||
std::vector<Value*> heap;
|
||||
std::vector<const Value*> heap;
|
||||
std::vector<bool> alive;
|
||||
};
|
||||
|
||||
extern State* state;
|
||||
|
||||
void PrintEnv(Env env);
|
||||
auto AllocateValue(Value* v) -> Address;
|
||||
auto CopyVal(Value* val, int line_num) -> Value*;
|
||||
auto ToInteger(Value* v) -> int;
|
||||
auto AllocateValue(const Value* v) -> Address;
|
||||
auto CopyVal(const Value* val, int line_num) -> const Value*;
|
||||
auto ToInteger(const Value* v) -> int;
|
||||
|
||||
/***** Interpreters *****/
|
||||
|
||||
auto InterpProgram(std::list<Declaration>* fs) -> int;
|
||||
auto InterpExp(Env env, Expression* e) -> Value*;
|
||||
auto InterpExp(Env env, Expression* e) -> const Value*;
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
void ExpectType(int line_num, const std::string& context, Value* expected,
|
||||
Value* actual) {
|
||||
void ExpectType(int line_num, const std::string& context, const Value* expected,
|
||||
const Value* actual) {
|
||||
if (!TypeEqual(expected, actual)) {
|
||||
std::cerr << line_num << ": type error in " << context << std::endl;
|
||||
std::cerr << "expected: ";
|
||||
@@ -40,12 +40,12 @@ void PrintTypeEnv(TypeEnv env, std::ostream& out) {
|
||||
}
|
||||
|
||||
// Convert tuples to tuple types.
|
||||
auto ToType(int line_num, Value* val) -> Value* {
|
||||
auto ToType(int line_num, const Value* val) -> const Value* {
|
||||
switch (val->tag) {
|
||||
case ValKind::TupleV: {
|
||||
auto fields = new VarValues();
|
||||
for (auto& elt : *val->u.tuple.elts) {
|
||||
Value* ty = ToType(line_num, state->heap[elt.second]);
|
||||
const Value* ty = ToType(line_num, state->heap[elt.second]);
|
||||
fields->push_back(std::make_pair(elt.first, ty));
|
||||
}
|
||||
return MakeTupleTypeVal(fields);
|
||||
@@ -53,7 +53,7 @@ auto ToType(int line_num, Value* val) -> Value* {
|
||||
case ValKind::TupleTV: {
|
||||
auto fields = new VarValues();
|
||||
for (auto& field : *val->u.tuple_type.fields) {
|
||||
Value* ty = ToType(line_num, field.second);
|
||||
const Value* ty = ToType(line_num, field.second);
|
||||
fields->push_back(std::make_pair(field.first, ty));
|
||||
}
|
||||
return MakeTupleTypeVal(fields);
|
||||
@@ -86,7 +86,7 @@ auto ToType(int line_num, Value* val) -> Value* {
|
||||
}
|
||||
|
||||
// Reify type to type expression.
|
||||
auto ReifyType(Value* t, int line_num) -> Expression* {
|
||||
auto ReifyType(const Value* t, int line_num) -> Expression* {
|
||||
switch (t->tag) {
|
||||
case ValKind::VarTV:
|
||||
return MakeVar(0, *t->u.var_type);
|
||||
@@ -137,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, const Value* expected,
|
||||
TCContext context) -> TCResult {
|
||||
switch (e->tag) {
|
||||
case ExpressionKind::PatternVariable: {
|
||||
@@ -198,7 +198,7 @@ auto TypeCheckExp(Expression* e, TypeEnv env, Env ct_env, Value* expected,
|
||||
int i = 0;
|
||||
for (auto arg = e->u.tuple.fields->begin();
|
||||
arg != e->u.tuple.fields->end(); ++arg, ++i) {
|
||||
Value* arg_expected = nullptr;
|
||||
const Value* arg_expected = nullptr;
|
||||
if (expected && expected->tag == ValKind::TupleTV) {
|
||||
arg_expected =
|
||||
FindInVarValues(arg->first, expected->u.tuple_type.fields);
|
||||
@@ -281,7 +281,7 @@ auto TypeCheckExp(Expression* e, TypeEnv env, Env ct_env, Value* expected,
|
||||
}
|
||||
}
|
||||
case ExpressionKind::Variable: {
|
||||
std::optional<Value*> type = env.Get(*(e->u.variable.name));
|
||||
std::optional<const Value*> type = env.Get(*(e->u.variable.name));
|
||||
if (type) {
|
||||
return TCResult(e, *type, env);
|
||||
} else {
|
||||
@@ -296,7 +296,7 @@ auto TypeCheckExp(Expression* e, TypeEnv env, Env ct_env, Value* expected,
|
||||
return TCResult(e, MakeBoolTypeVal(), env);
|
||||
case ExpressionKind::PrimitiveOp: {
|
||||
auto es = new std::vector<Expression*>();
|
||||
std::vector<Value*> ts;
|
||||
std::vector<const Value*> ts;
|
||||
auto new_env = env;
|
||||
for (auto& argument : *e->u.primitive_op.arguments) {
|
||||
auto res = TypeCheckExp(argument, env, ct_env, nullptr,
|
||||
@@ -389,8 +389,8 @@ 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)
|
||||
auto TypecheckCase(const Value* expected, Expression* pat, Statement* body,
|
||||
TypeEnv env, Env ct_env, const Value*& ret_type)
|
||||
-> std::pair<Expression*, Statement*> {
|
||||
auto pat_res =
|
||||
TypeCheckExp(pat, env, ct_env, expected, TCContext::PatternContext);
|
||||
@@ -405,8 +405,8 @@ 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)
|
||||
-> TCStatement {
|
||||
auto TypeCheckStmt(Statement* s, TypeEnv env, Env ct_env,
|
||||
const Value*& ret_type) -> TCStatement {
|
||||
if (!s) {
|
||||
return TCStatement(s, env);
|
||||
}
|
||||
@@ -443,7 +443,7 @@ auto TypeCheckStmt(Statement* s, TypeEnv env, Env ct_env, Value* ret_type)
|
||||
case StatementKind::VariableDefinition: {
|
||||
auto res = TypeCheckExp(s->u.variable_definition.init, env, ct_env,
|
||||
nullptr, TCContext::ValueContext);
|
||||
Value* rhs_ty = res.type;
|
||||
const Value* rhs_ty = res.type;
|
||||
auto lhs_res = TypeCheckExp(s->u.variable_definition.pat, env, ct_env,
|
||||
rhs_ty, TCContext::PatternContext);
|
||||
Statement* new_s =
|
||||
@@ -494,7 +494,7 @@ auto TypeCheckStmt(Statement* s, TypeEnv env, Env ct_env, Value* ret_type)
|
||||
// The following infers the return type from the first 'return'
|
||||
// statement. This will get more difficult with subtyping, when we
|
||||
// should infer the least-upper bound of all the 'return' statements.
|
||||
*ret_type = *res.type;
|
||||
ret_type = res.type;
|
||||
} else {
|
||||
ExpectType(s->line_num, "return", ret_type, res.type);
|
||||
}
|
||||
@@ -587,7 +587,7 @@ auto TypeCheckFunDef(const FunctionDefinition* f, TypeEnv env, Env ct_env)
|
||||
}
|
||||
|
||||
auto TypeOfFunDef(TypeEnv env, Env ct_env, const FunctionDefinition* fun_def)
|
||||
-> Value* {
|
||||
-> const Value* {
|
||||
auto param_res = TypeCheckExp(fun_def->param_pattern, env, ct_env, nullptr,
|
||||
TCContext::PatternContext);
|
||||
auto param_type = ToType(fun_def->line_num, param_res.type);
|
||||
@@ -600,7 +600,7 @@ auto TypeOfFunDef(TypeEnv env, Env ct_env, const FunctionDefinition* fun_def)
|
||||
}
|
||||
|
||||
auto TypeOfStructDef(const StructDefinition* sd, TypeEnv /*env*/, Env ct_top)
|
||||
-> Value* {
|
||||
-> const Value* {
|
||||
auto fields = new VarValues();
|
||||
auto methods = new VarValues();
|
||||
for (auto m = sd->members->begin(); m != sd->members->end(); ++m) {
|
||||
@@ -652,7 +652,7 @@ auto VariableDeclaration::TypeChecked(TypeEnv env, Env ct_env) const
|
||||
-> Declaration {
|
||||
TCResult type_checked_initializer =
|
||||
TypeCheckExp(initializer, env, ct_env, nullptr, TCContext::ValueContext);
|
||||
Value* declared_type = ToType(source_location, InterpExp(ct_env, type));
|
||||
const Value* declared_type = ToType(source_location, InterpExp(ct_env, type));
|
||||
ExpectType(source_location, "initializer of variable", declared_type,
|
||||
type_checked_initializer.type);
|
||||
return *this;
|
||||
@@ -706,7 +706,8 @@ auto ChoiceDeclaration::TopLevel(TypeCheckContext& tops) const -> void {
|
||||
// Associate the variable name with it's declared type in the
|
||||
// compile-time symbol table.
|
||||
auto VariableDeclaration::TopLevel(TypeCheckContext& tops) const -> void {
|
||||
Value* declared_type = ToType(source_location, InterpExp(tops.values, type));
|
||||
const Value* declared_type =
|
||||
ToType(source_location, InterpExp(tops.values, type));
|
||||
tops.types.Set(Name(), declared_type);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,17 +14,18 @@
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
using TypeEnv = Dictionary<std::string, Value*>;
|
||||
using TypeEnv = Dictionary<std::string, const Value*>;
|
||||
|
||||
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, const Value* t, TypeEnv env)
|
||||
: exp(e), type(t), env(env) {}
|
||||
|
||||
Expression* exp;
|
||||
Value* type;
|
||||
const Value* type;
|
||||
TypeEnv env;
|
||||
};
|
||||
|
||||
@@ -35,12 +36,12 @@ struct TCStatement {
|
||||
TypeEnv env;
|
||||
};
|
||||
|
||||
auto ToType(int line_num, Value* val) -> Value*;
|
||||
auto ToType(int line_num, const Value* val) -> const Value*;
|
||||
|
||||
auto TypeCheckExp(Expression* e, TypeEnv env, Env ct_env, Value* expected,
|
||||
auto TypeCheckExp(Expression* e, TypeEnv env, Env ct_env, const Value* expected,
|
||||
TCContext context) -> TCResult;
|
||||
|
||||
auto TypeCheckStmt(Statement*, TypeEnv, Env, Value*) -> TCStatement;
|
||||
auto TypeCheckStmt(Statement*, TypeEnv, Env, Value const*&) -> TCStatement;
|
||||
|
||||
auto TypeCheckFunDef(struct FunctionDefinition*, TypeEnv)
|
||||
-> struct FunctionDefinition*;
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
auto FindInVarValues(const std::string& field, VarValues* inits) -> Value* {
|
||||
auto FindInVarValues(const std::string& field, VarValues* inits)
|
||||
-> const Value* {
|
||||
for (auto& i : *inits) {
|
||||
if (i.first == field) {
|
||||
return i.second;
|
||||
@@ -36,21 +37,22 @@ auto FieldsEqual(VarValues* ts1, VarValues* ts2) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
auto MakeIntVal(int i) -> Value* {
|
||||
auto MakeIntVal(int i) -> const Value* {
|
||||
auto* v = new Value();
|
||||
v->tag = ValKind::IntV;
|
||||
v->u.integer = i;
|
||||
return v;
|
||||
}
|
||||
|
||||
auto MakeBoolVal(bool b) -> Value* {
|
||||
auto MakeBoolVal(bool b) -> const Value* {
|
||||
auto* v = new Value();
|
||||
v->tag = ValKind::BoolV;
|
||||
v->u.boolean = b;
|
||||
return v;
|
||||
}
|
||||
|
||||
auto MakeFunVal(std::string name, Value* param, Statement* body) -> Value* {
|
||||
auto MakeFunVal(std::string name, const Value* param, Statement* body)
|
||||
-> const Value* {
|
||||
auto* v = new Value();
|
||||
v->tag = ValKind::FunV;
|
||||
v->u.fun.name = new std::string(std::move(name));
|
||||
@@ -59,14 +61,14 @@ auto MakeFunVal(std::string name, Value* param, Statement* body) -> Value* {
|
||||
return v;
|
||||
}
|
||||
|
||||
auto MakePtrVal(Address addr) -> Value* {
|
||||
auto MakePtrVal(Address addr) -> const Value* {
|
||||
auto* v = new Value();
|
||||
v->tag = ValKind::PtrV;
|
||||
v->u.ptr = addr;
|
||||
return v;
|
||||
}
|
||||
|
||||
auto MakeStructVal(Value* type, Value* inits) -> Value* {
|
||||
auto MakeStructVal(const Value* type, const Value* inits) -> const Value* {
|
||||
auto* v = new Value();
|
||||
v->tag = ValKind::StructV;
|
||||
v->u.struct_val.type = type;
|
||||
@@ -75,7 +77,7 @@ auto MakeStructVal(Value* type, Value* inits) -> Value* {
|
||||
}
|
||||
|
||||
auto MakeTupleVal(std::vector<std::pair<std::string, Address>>* elts)
|
||||
-> Value* {
|
||||
-> const Value* {
|
||||
auto* v = new Value();
|
||||
v->tag = ValKind::TupleV;
|
||||
v->u.tuple.elts = elts;
|
||||
@@ -83,7 +85,7 @@ auto MakeTupleVal(std::vector<std::pair<std::string, Address>>* elts)
|
||||
}
|
||||
|
||||
auto MakeAltVal(std::string alt_name, std::string choice_name, Address argument)
|
||||
-> Value* {
|
||||
-> const Value* {
|
||||
auto* v = new Value();
|
||||
v->tag = ValKind::AltV;
|
||||
v->u.alt.alt_name = new std::string(std::move(alt_name));
|
||||
@@ -92,7 +94,8 @@ auto MakeAltVal(std::string alt_name, std::string choice_name, Address argument)
|
||||
return v;
|
||||
}
|
||||
|
||||
auto MakeAltCons(std::string alt_name, std::string choice_name) -> Value* {
|
||||
auto MakeAltCons(std::string alt_name, std::string choice_name)
|
||||
-> const Value* {
|
||||
auto* v = new Value();
|
||||
v->tag = ValKind::AltConsV;
|
||||
v->u.alt.alt_name = new std::string(std::move(alt_name));
|
||||
@@ -100,7 +103,7 @@ auto MakeAltCons(std::string alt_name, std::string choice_name) -> Value* {
|
||||
return v;
|
||||
}
|
||||
|
||||
auto MakeVarPatVal(std::string name, Value* type) -> Value* {
|
||||
auto MakeVarPatVal(std::string name, const Value* type) -> const Value* {
|
||||
auto* v = new Value();
|
||||
v->tag = ValKind::VarPatV;
|
||||
v->u.var_pat.name = new std::string(std::move(name));
|
||||
@@ -108,38 +111,38 @@ auto MakeVarPatVal(std::string name, Value* type) -> Value* {
|
||||
return v;
|
||||
}
|
||||
|
||||
auto MakeVarTypeVal(std::string name) -> Value* {
|
||||
auto MakeVarTypeVal(std::string name) -> const Value* {
|
||||
auto* v = new Value();
|
||||
v->tag = ValKind::VarTV;
|
||||
v->u.var_type = new std::string(std::move(name));
|
||||
return v;
|
||||
}
|
||||
|
||||
auto MakeIntTypeVal() -> Value* {
|
||||
auto MakeIntTypeVal() -> const Value* {
|
||||
auto* v = new Value();
|
||||
v->tag = ValKind::IntTV;
|
||||
return v;
|
||||
}
|
||||
|
||||
auto MakeBoolTypeVal() -> Value* {
|
||||
auto MakeBoolTypeVal() -> const Value* {
|
||||
auto* v = new Value();
|
||||
v->tag = ValKind::BoolTV;
|
||||
return v;
|
||||
}
|
||||
|
||||
auto MakeTypeTypeVal() -> Value* {
|
||||
auto MakeTypeTypeVal() -> const Value* {
|
||||
auto* v = new Value();
|
||||
v->tag = ValKind::TypeTV;
|
||||
return v;
|
||||
}
|
||||
|
||||
auto MakeAutoTypeVal() -> Value* {
|
||||
auto MakeAutoTypeVal() -> const Value* {
|
||||
auto* v = new Value();
|
||||
v->tag = ValKind::AutoTV;
|
||||
return v;
|
||||
}
|
||||
|
||||
auto MakeFunTypeVal(Value* param, Value* ret) -> Value* {
|
||||
auto MakeFunTypeVal(const Value* param, const Value* ret) -> const Value* {
|
||||
auto* v = new Value();
|
||||
v->tag = ValKind::FunctionTV;
|
||||
v->u.fun_type.param = param;
|
||||
@@ -147,7 +150,7 @@ auto MakeFunTypeVal(Value* param, Value* ret) -> Value* {
|
||||
return v;
|
||||
}
|
||||
|
||||
auto MakePtrTypeVal(Value* type) -> Value* {
|
||||
auto MakePtrTypeVal(const Value* type) -> const Value* {
|
||||
auto* v = new Value();
|
||||
v->tag = ValKind::PointerTV;
|
||||
v->u.ptr_type.type = type;
|
||||
@@ -155,7 +158,7 @@ auto MakePtrTypeVal(Value* type) -> Value* {
|
||||
}
|
||||
|
||||
auto MakeStructTypeVal(std::string name, VarValues* fields, VarValues* methods)
|
||||
-> Value* {
|
||||
-> const Value* {
|
||||
auto* v = new Value();
|
||||
v->tag = ValKind::StructTV;
|
||||
v->u.struct_type.name = new std::string(std::move(name));
|
||||
@@ -164,14 +167,14 @@ auto MakeStructTypeVal(std::string name, VarValues* fields, VarValues* methods)
|
||||
return v;
|
||||
}
|
||||
|
||||
auto MakeTupleTypeVal(VarValues* fields) -> Value* {
|
||||
auto MakeTupleTypeVal(VarValues* fields) -> const Value* {
|
||||
auto* v = new Value();
|
||||
v->tag = ValKind::TupleTV;
|
||||
v->u.tuple_type.fields = fields;
|
||||
return v;
|
||||
}
|
||||
|
||||
auto MakeVoidTypeVal() -> Value* {
|
||||
auto MakeVoidTypeVal() -> const Value* {
|
||||
auto* v = new Value();
|
||||
v->tag = ValKind::TupleTV;
|
||||
v->u.tuple_type.fields = new VarValues();
|
||||
@@ -179,8 +182,8 @@ auto MakeVoidTypeVal() -> Value* {
|
||||
}
|
||||
|
||||
auto MakeChoiceTypeVal(std::string name,
|
||||
std::list<std::pair<std::string, Value*>>* alts)
|
||||
-> Value* {
|
||||
std::list<std::pair<std::string, const Value*>>* alts)
|
||||
-> const Value* {
|
||||
auto* v = new Value();
|
||||
v->tag = ValKind::ChoiceTV;
|
||||
// Transitional leak: when we get rid of all pointers, this will disappear.
|
||||
@@ -189,7 +192,7 @@ auto MakeChoiceTypeVal(std::string name,
|
||||
return v;
|
||||
}
|
||||
|
||||
void PrintValue(Value* val, std::ostream& out) {
|
||||
void PrintValue(const Value* val, std::ostream& out) {
|
||||
switch (val->tag) {
|
||||
case ValKind::AltConsV: {
|
||||
out << *val->u.alt_cons.choice_name << "." << *val->u.alt_cons.alt_name;
|
||||
@@ -291,7 +294,7 @@ void PrintValue(Value* val, std::ostream& out) {
|
||||
}
|
||||
}
|
||||
|
||||
auto TypeEqual(Value* t1, Value* t2) -> bool {
|
||||
auto TypeEqual(const Value* t1, const Value* t2) -> bool {
|
||||
if (t1->tag != t2->tag) {
|
||||
return false;
|
||||
}
|
||||
@@ -334,7 +337,7 @@ static auto FieldsValueEqual(VarValues* ts1, VarValues* ts2, int line_num)
|
||||
return true;
|
||||
}
|
||||
|
||||
auto ValueEqual(Value* v1, Value* v2, int line_num) -> bool {
|
||||
auto ValueEqual(const Value* v1, const Value* v2, int line_num) -> bool {
|
||||
if (v1->tag != v2->tag) {
|
||||
return false;
|
||||
}
|
||||
@@ -357,7 +360,7 @@ auto ValueEqual(Value* v1, Value* v2, int line_num) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
auto ToInteger(Value* v) -> int {
|
||||
auto ToInteger(const Value* v) -> int {
|
||||
switch (v->tag) {
|
||||
case ValKind::IntV:
|
||||
return v->u.integer;
|
||||
|
||||
@@ -14,9 +14,10 @@ namespace Carbon {
|
||||
|
||||
struct Value;
|
||||
using Address = unsigned int;
|
||||
using VarValues = std::list<std::pair<std::string, Value*>>;
|
||||
using VarValues = std::list<std::pair<std::string, const Value*>>;
|
||||
|
||||
auto FindInVarValues(const std::string& field, VarValues* inits) -> Value*;
|
||||
auto FindInVarValues(const std::string& field, VarValues* inits)
|
||||
-> const Value*;
|
||||
auto FieldsEqual(VarValues* ts1, VarValues* ts2) -> bool;
|
||||
|
||||
enum class ValKind {
|
||||
@@ -48,12 +49,12 @@ struct Value {
|
||||
bool boolean;
|
||||
struct {
|
||||
std::string* name;
|
||||
Value* param;
|
||||
const Value* param;
|
||||
Statement* body;
|
||||
} fun;
|
||||
struct {
|
||||
Value* type;
|
||||
Value* inits;
|
||||
const Value* type;
|
||||
const Value* inits;
|
||||
} struct_val;
|
||||
struct {
|
||||
std::string* alt_name;
|
||||
@@ -71,14 +72,14 @@ struct Value {
|
||||
std::string* var_type;
|
||||
struct {
|
||||
std::string* name;
|
||||
Value* type;
|
||||
const Value* type;
|
||||
} var_pat;
|
||||
struct {
|
||||
Value* param;
|
||||
Value* ret;
|
||||
const Value* param;
|
||||
const Value* ret;
|
||||
} fun_type;
|
||||
struct {
|
||||
Value* type;
|
||||
const Value* type;
|
||||
} ptr_type;
|
||||
struct {
|
||||
std::string* name;
|
||||
@@ -95,42 +96,44 @@ struct Value {
|
||||
} choice_type;
|
||||
struct {
|
||||
std::list<std::string*>* params;
|
||||
Value* type;
|
||||
const Value* type;
|
||||
} implicit;
|
||||
} u;
|
||||
};
|
||||
|
||||
auto MakeIntVal(int i) -> Value*;
|
||||
auto MakeBoolVal(bool b) -> Value*;
|
||||
auto MakeFunVal(std::string name, Value* param, Statement* body) -> Value*;
|
||||
auto MakePtrVal(Address addr) -> Value*;
|
||||
auto MakeStructVal(Value* type, Value* inits) -> Value*;
|
||||
auto MakeTupleVal(std::vector<std::pair<std::string, Address>>* elts) -> Value*;
|
||||
auto MakeIntVal(int i) -> const Value*;
|
||||
auto MakeBoolVal(bool b) -> const Value*;
|
||||
auto MakeFunVal(std::string name, const Value* param, Statement* body)
|
||||
-> const Value*;
|
||||
auto MakePtrVal(Address addr) -> const Value*;
|
||||
auto MakeStructVal(const Value* type, const Value* inits) -> const Value*;
|
||||
auto MakeTupleVal(std::vector<std::pair<std::string, Address>>* elts)
|
||||
-> const Value*;
|
||||
auto MakeAltVal(std::string alt_name, std::string choice_name, Address argument)
|
||||
-> Value*;
|
||||
auto MakeAltCons(std::string alt_name, std::string choice_name) -> Value*;
|
||||
-> const Value*;
|
||||
auto MakeAltCons(std::string alt_name, std::string choice_name) -> const Value*;
|
||||
|
||||
auto MakeVarPatVal(std::string name, Value* type) -> Value*;
|
||||
auto MakeVarPatVal(std::string name, const Value* type) -> const Value*;
|
||||
|
||||
auto MakeVarTypeVal(std::string name) -> Value*;
|
||||
auto MakeIntTypeVal() -> Value*;
|
||||
auto MakeAutoTypeVal() -> Value*;
|
||||
auto MakeBoolTypeVal() -> Value*;
|
||||
auto MakeTypeTypeVal() -> Value*;
|
||||
auto MakeFunTypeVal(Value* param, Value* ret) -> Value*;
|
||||
auto MakePtrTypeVal(Value* type) -> Value*;
|
||||
auto MakeVarTypeVal(std::string name) -> const Value*;
|
||||
auto MakeIntTypeVal() -> const Value*;
|
||||
auto MakeAutoTypeVal() -> const Value*;
|
||||
auto MakeBoolTypeVal() -> const Value*;
|
||||
auto MakeTypeTypeVal() -> const Value*;
|
||||
auto MakeFunTypeVal(const Value* param, const Value* ret) -> const Value*;
|
||||
auto MakePtrTypeVal(const Value* type) -> const Value*;
|
||||
auto MakeStructTypeVal(std::string name, VarValues* fields, VarValues* methods)
|
||||
-> Value*;
|
||||
auto MakeTupleTypeVal(VarValues* fields) -> Value*;
|
||||
auto MakeVoidTypeVal() -> Value*;
|
||||
auto MakeChoiceTypeVal(std::string name, VarValues* alts) -> Value*;
|
||||
-> const Value*;
|
||||
auto MakeTupleTypeVal(VarValues* fields) -> const Value*;
|
||||
auto MakeVoidTypeVal() -> const Value*;
|
||||
auto MakeChoiceTypeVal(std::string name, VarValues* alts) -> const Value*;
|
||||
|
||||
void PrintValue(Value* val, std::ostream& out);
|
||||
void PrintValue(const Value* val, std::ostream& out);
|
||||
|
||||
auto TypeEqual(Value* t1, Value* t2) -> bool;
|
||||
auto ValueEqual(Value* v1, Value* v2, int line_num) -> bool;
|
||||
auto TypeEqual(const Value* t1, const Value* t2) -> bool;
|
||||
auto ValueEqual(const Value* v1, const Value* v2, int line_num) -> bool;
|
||||
|
||||
auto ToInteger(Value* v) -> int;
|
||||
auto ToInteger(const Value* v) -> int;
|
||||
void CheckAlive(Address a, int line_num);
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
Reference in New Issue
Block a user