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:
Dave Abrahams
2021-03-21 09:00:00 -07:00
committed by GitHub
parent 1da97fc9cf
commit dd4e37e761
9 changed files with 149 additions and 139 deletions
@@ -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;
}