diff --git a/executable_semantics/interpreter/BUILD b/executable_semantics/interpreter/BUILD index 04c883a91c12..707cbbe9735a 100644 --- a/executable_semantics/interpreter/BUILD +++ b/executable_semantics/interpreter/BUILD @@ -20,6 +20,7 @@ cc_library( "assoc_list.h", "cons_list.h", "interpreter.h", + "stack.h", "typecheck.h", "value.h", ], diff --git a/executable_semantics/interpreter/action.cpp b/executable_semantics/interpreter/action.cpp index 3c7b06a95ed6..c35186f03fa4 100644 --- a/executable_semantics/interpreter/action.cpp +++ b/executable_semantics/interpreter/action.cpp @@ -12,6 +12,7 @@ #include "executable_semantics/ast/expression.h" #include "executable_semantics/ast/function_definition.h" #include "executable_semantics/interpreter/interpreter.h" +#include "executable_semantics/interpreter/stack.h" #include "executable_semantics/interpreter/typecheck.h" namespace Carbon { @@ -48,12 +49,12 @@ void PrintAct(Action* act, std::ostream& out) { } } -void PrintActList(Cons* ls, std::ostream& out) { - if (ls) { - PrintAct(ls->curr, out); - if (ls->next) { +void PrintActList(Stack ls, std::ostream& out) { + if (!ls.IsEmpty()) { + PrintAct(ls.Pop(), out); + if (!ls.IsEmpty()) { out << " :: "; - PrintActList(ls->next, out); + PrintActList(ls, out); } } } diff --git a/executable_semantics/interpreter/action.h b/executable_semantics/interpreter/action.h index 478c31e9db8e..8ce5be6210bf 100644 --- a/executable_semantics/interpreter/action.h +++ b/executable_semantics/interpreter/action.h @@ -37,7 +37,7 @@ struct Action { }; void PrintAct(Action* act, std::ostream& out); -void PrintActList(Cons* ls, std::ostream& out); +void PrintActList(Stack ls, std::ostream& out); auto MakeExpAct(Expression* e) -> Action*; auto MakeLvalAct(Expression* e) -> Action*; auto MakeStmtAct(Statement* s) -> Action*; diff --git a/executable_semantics/interpreter/cons_list.h b/executable_semantics/interpreter/cons_list.h index bc3512a1ed0d..6340874e66a5 100644 --- a/executable_semantics/interpreter/cons_list.h +++ b/executable_semantics/interpreter/cons_list.h @@ -7,24 +7,25 @@ namespace Carbon { +template +struct Stack; + template struct Cons { + friend struct Stack; + + private: Cons(T e, Cons* n) : curr(e), next(n) {} - T curr; - Cons* next; + const T curr; + Cons* const next; + + // Cons cells are part of a "persistent data structure" and are thus + // immutable. + Cons& operator=(const Cons&) = delete; + Cons& operator=(Cons&&) = delete; }; -template -auto MakeCons(const T& x) -> Cons* { - return new Cons(x, nullptr); -} - -template -auto MakeCons(const T& x, Cons* ls) -> Cons* { - return new Cons(x, ls); -} - template auto Length(Cons* ls) -> unsigned int { if (ls) { diff --git a/executable_semantics/interpreter/interpreter.cpp b/executable_semantics/interpreter/interpreter.cpp index 90ebd666086e..49f2ddc18826 100644 --- a/executable_semantics/interpreter/interpreter.cpp +++ b/executable_semantics/interpreter/interpreter.cpp @@ -13,6 +13,7 @@ #include "executable_semantics/ast/expression.h" #include "executable_semantics/ast/function_definition.h" +#include "executable_semantics/interpreter/stack.h" #include "executable_semantics/interpreter/typecheck.h" namespace Carbon { @@ -150,12 +151,12 @@ void PrintFrame(Frame* frame, std::ostream& out) { out << "}"; } -void PrintStack(Cons* ls, std::ostream& out) { - if (ls) { - PrintFrame(ls->curr, out); - if (ls->next) { +void PrintStack(Stack ls, std::ostream& out) { + if (!ls.IsEmpty()) { + PrintFrame(ls.Pop(), out); + if (!ls.IsEmpty()) { out << " :: "; - PrintStack(ls->next, out); + PrintStack(ls, out); } } } @@ -172,8 +173,8 @@ void PrintHeap(const std::vector& heap, std::ostream& out) { } auto CurrentEnv(State* state) -> Env* { - Frame* frame = state->stack->curr; - return frame->scopes->curr->env; + Frame* frame = state->stack.Top(); + return frame->scopes.Top()->env; } void PrintState(std::ostream& out) { @@ -321,24 +322,24 @@ void CallFunction(int line_num, std::vector operas, State* state) { } // Create the new frame and push it on the stack auto* scope = new Scope(env, params); - auto* frame = new Frame(*operas[0]->u.fun.name, MakeCons(scope), - MakeCons(MakeStmtAct(operas[0]->u.fun.body))); - state->stack = MakeCons(frame, state->stack); + auto* frame = new Frame(*operas[0]->u.fun.name, Stack(scope), + Stack(MakeStmtAct(operas[0]->u.fun.body))); + state->stack.Push(frame); break; } case ValKind::StructTV: { Value* arg = CopyVal(operas[1], line_num); Value* sv = MakeStructVal(operas[0], arg); - Frame* frame = state->stack->curr; - frame->todo = MakeCons(MakeValAct(sv), frame->todo); + Frame* frame = state->stack.Top(); + frame->todo.Push(MakeValAct(sv)); break; } case ValKind::AltConsV: { Value* arg = CopyVal(operas[1], line_num); Value* av = MakeAltVal(*operas[0]->u.alt_cons.alt_name, *operas[0]->u.alt_cons.choice_name, arg); - Frame* frame = state->stack->curr; - frame->todo = MakeCons(MakeValAct(av), frame->todo); + Frame* frame = state->stack.Top(); + frame->todo.Push(MakeValAct(av)); break; } default: @@ -357,8 +358,7 @@ void KillScope(int line_num, Scope* scope) { } void KillLocals(int line_num, Frame* frame) { - Cons* scopes = frame->scopes; - for (Scope* scope = scopes->curr; scopes; scopes = scopes->next) { + for (auto scope : frame->scopes) { KillScope(line_num, scope); } } @@ -373,7 +373,8 @@ void CreateTuple(Frame* frame, Action* act, Expression* /*exp*/) { elts->push_back(make_pair(f->first, a)); } Value* tv = MakeTupleVal(elts); - frame->todo = MakeCons(MakeValAct(tv), frame->todo->next); + frame->todo.Pop(1); + frame->todo.Push(MakeValAct(tv)); } auto ToValue(Expression* value) -> Value* { @@ -546,8 +547,8 @@ void PatternAssignment(Value* pat, Value* val, int line_num) { /***** state transitions for lvalues *****/ void StepLvalue() { - Frame* frame = state->stack->curr; - Action* act = frame->todo->curr; + Frame* frame = state->stack.Top(); + Action* act = frame->todo.Top(); Expression* exp = act->u.exp; std::cout << "--- step lvalue "; PrintExp(exp); @@ -560,21 +561,21 @@ void StepLvalue() { *(exp->u.variable.name), PrintErrorString); Value* v = MakePtrVal(a); CheckAlive(v, exp->line_num); - frame->todo = MakeCons(MakeValAct(v), frame->todo->next); + frame->todo.Pop(); + frame->todo.Push(MakeValAct(v)); break; } case ExpressionKind::GetField: { // { {e.f :: C, E, F} :: S, H} // -> { e :: [].f :: C, E, F} :: S, H} - frame->todo = - MakeCons(MakeLvalAct(exp->u.get_field.aggregate), frame->todo); + frame->todo.Push(MakeLvalAct(exp->u.get_field.aggregate)); act->pos++; break; } case ExpressionKind::Index: { // { {e[i] :: C, E, F} :: S, H} // -> { e :: [][i] :: C, E, F} :: S, H} - frame->todo = MakeCons(MakeExpAct(exp->u.index.aggregate), frame->todo); + frame->todo.Push(MakeExpAct(exp->u.index.aggregate)); act->pos++; break; } @@ -582,7 +583,7 @@ void StepLvalue() { // { {(f1=e1,...) :: C, E, F} :: S, H} // -> { {e1 :: (f1=[],...) :: C, E, F} :: S, H} Expression* e1 = (*exp->u.tuple.fields)[0].second; - frame->todo = MakeCons(MakeLvalAct(e1), frame->todo); + frame->todo.Push(MakeLvalAct(e1)); act->pos++; break; } @@ -596,8 +597,9 @@ void StepLvalue() { case ExpressionKind::FunctionT: case ExpressionKind::AutoT: case ExpressionKind::PatternVariable: { - frame->todo = MakeCons(MakeExpAct(exp), - MakeCons(MakeExpToLvalAct(), frame->todo->next)); + frame->todo.Pop(); + frame->todo.Push(MakeExpToLvalAct()); + frame->todo.Push(MakeExpAct(exp)); } } } @@ -605,23 +607,22 @@ void StepLvalue() { /***** state transitions for expressions *****/ void StepExp() { - Frame* frame = state->stack->curr; - Action* act = frame->todo->curr; + Frame* frame = state->stack.Top(); + Action* act = frame->todo.Top(); Expression* exp = act->u.exp; std::cout << "--- step exp "; PrintExp(exp); std::cout << " --->" << std::endl; switch (exp->tag) { case ExpressionKind::PatternVariable: { - frame->todo = - MakeCons(MakeExpAct(exp->u.pattern_variable.type), frame->todo); + frame->todo.Push(MakeExpAct(exp->u.pattern_variable.type)); act->pos++; break; } case ExpressionKind::Index: { // { { e[i] :: C, E, F} :: S, H} // -> { { e :: [][i] :: C, E, F} :: S, H} - frame->todo = MakeCons(MakeExpAct(exp->u.index.aggregate), frame->todo); + frame->todo.Push(MakeExpAct(exp->u.index.aggregate)); act->pos++; break; } @@ -630,7 +631,7 @@ void StepExp() { // { {(f1=e1,...) :: C, E, F} :: S, H} // -> { {e1 :: (f1=[],...) :: C, E, F} :: S, H} Expression* e1 = (*exp->u.tuple.fields)[0].second; - frame->todo = MakeCons(MakeExpAct(e1), frame->todo); + frame->todo.Push(MakeExpAct(e1)); act->pos++; } else { CreateTuple(frame, act, exp); @@ -640,8 +641,7 @@ void StepExp() { case ExpressionKind::GetField: { // { { e.f :: C, E, F} :: S, H} // -> { { e :: [].f :: C, E, F} :: S, H} - frame->todo = - MakeCons(MakeLvalAct(exp->u.get_field.aggregate), frame->todo); + frame->todo.Push(MakeLvalAct(exp->u.get_field.aggregate)); act->pos++; break; } @@ -650,63 +650,67 @@ void StepExp() { Address a = Lookup(exp->line_num, CurrentEnv(state), *(exp->u.variable.name), PrintErrorString); Value* v = state->heap[a]; - frame->todo = MakeCons(MakeValAct(v), frame->todo->next); + frame->todo.Pop(1); + frame->todo.Push(MakeValAct(v)); break; } case ExpressionKind::Integer: // { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H} - frame->todo = - MakeCons(MakeValAct(MakeIntVal(exp->u.integer)), frame->todo->next); + frame->todo.Pop(1); + frame->todo.Push(MakeValAct(MakeIntVal(exp->u.integer))); break; case ExpressionKind::Boolean: // { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H} - frame->todo = - MakeCons(MakeValAct(MakeBoolVal(exp->u.boolean)), frame->todo->next); + frame->todo.Pop(1); + frame->todo.Push(MakeValAct(MakeBoolVal(exp->u.boolean))); break; case ExpressionKind::PrimitiveOp: if (exp->u.primitive_op.arguments->size() > 0) { // { {op(e :: es) :: C, E, F} :: S, H} // -> { e :: op([] :: es) :: C, E, F} :: S, H} - frame->todo = MakeCons( - MakeExpAct(exp->u.primitive_op.arguments->front()), frame->todo); + frame->todo.Push(MakeExpAct(exp->u.primitive_op.arguments->front())); act->pos++; } else { // { {v :: op(]) :: C, E, F} :: S, H} // -> { {eval_prim(op, ()) :: C, E, F} :: S, H} Value* v = EvalPrim(exp->u.primitive_op.op, act->results, exp->line_num); - frame->todo = MakeCons(MakeValAct(v), frame->todo->next->next); + frame->todo.Pop(2); + frame->todo.Push(MakeValAct(v)); } break; case ExpressionKind::Call: // { {e1(e2) :: C, E, F} :: S, H} // -> { {e1 :: [](e2) :: C, E, F} :: S, H} - frame->todo = MakeCons(MakeExpAct(exp->u.call.function), frame->todo); + frame->todo.Push(MakeExpAct(exp->u.call.function)); act->pos++; break; case ExpressionKind::IntT: { Value* v = MakeIntTypeVal(); - frame->todo = MakeCons(MakeValAct(v), frame->todo->next); + frame->todo.Pop(1); + frame->todo.Push(MakeValAct(v)); break; } case ExpressionKind::BoolT: { Value* v = MakeBoolTypeVal(); - frame->todo = MakeCons(MakeValAct(v), frame->todo->next); + frame->todo.Pop(1); + frame->todo.Push(MakeValAct(v)); break; } case ExpressionKind::AutoT: { Value* v = MakeAutoTypeVal(); - frame->todo = MakeCons(MakeValAct(v), frame->todo->next); + frame->todo.Pop(1); + frame->todo.Push(MakeValAct(v)); break; } case ExpressionKind::TypeT: { Value* v = MakeTypeTypeVal(); - frame->todo = MakeCons(MakeValAct(v), frame->todo->next); + frame->todo.Pop(1); + frame->todo.Push(MakeValAct(v)); break; } case ExpressionKind::FunctionT: { - frame->todo = - MakeCons(MakeExpAct(exp->u.function_type.parameter), frame->todo); + frame->todo.Push(MakeExpAct(exp->u.function_type.parameter)); act->pos++; break; } @@ -744,8 +748,8 @@ auto IsBlockAct(Action* act) -> bool { } void StepStmt() { - Frame* frame = state->stack->curr; - Action* act = frame->todo->curr; + Frame* frame = state->stack.Top(); + Action* act = frame->todo.Top(); Statement* stmt = act->u.stmt; std::cout << "--- step stmt "; PrintStatement(stmt, 1); @@ -754,92 +758,91 @@ void StepStmt() { case StatementKind::Match: // { { (match (e) ...) :: C, E, F} :: S, H} // -> { { e :: (match ([]) ...) :: C, E, F} :: S, H} - frame->todo = MakeCons(MakeExpAct(stmt->u.match_stmt.exp), frame->todo); + frame->todo.Push(MakeExpAct(stmt->u.match_stmt.exp)); act->pos++; break; case StatementKind::While: // { { (while (e) s) :: C, E, F} :: S, H} // -> { { e :: (while ([]) s) :: C, E, F} :: S, H} - frame->todo = MakeCons(MakeExpAct(stmt->u.while_stmt.cond), frame->todo); + frame->todo.Push(MakeExpAct(stmt->u.while_stmt.cond)); act->pos++; break; case StatementKind::Break: // { { break; :: ... :: (while (e) s) :: C, E, F} :: S, H} // -> { { C, E', F} :: S, H} - frame->todo = frame->todo->next; - while (frame->todo && !IsWhileAct(frame->todo->curr)) { - if (IsBlockAct(frame->todo->curr)) { - KillScope(stmt->line_num, frame->scopes->curr); - frame->scopes = frame->scopes->next; + frame->todo.Pop(1); + while (!frame->todo.IsEmpty() && !IsWhileAct(frame->todo.Top())) { + if (IsBlockAct(frame->todo.Top())) { + KillScope(stmt->line_num, frame->scopes.Top()); + frame->scopes.Pop(1); } - frame->todo = frame->todo->next; + frame->todo.Pop(1); } - frame->todo = frame->todo->next; + frame->todo.Pop(1); break; case StatementKind::Continue: // { { continue; :: ... :: (while (e) s) :: C, E, F} :: S, H} // -> { { (while (e) s) :: C, E', F} :: S, H} - frame->todo = frame->todo->next; - while (frame->todo && !IsWhileAct(frame->todo->curr)) { - if (IsBlockAct(frame->todo->curr)) { - KillScope(stmt->line_num, frame->scopes->curr); - frame->scopes = frame->scopes->next; + frame->todo.Pop(1); + while (!frame->todo.IsEmpty() && !IsWhileAct(frame->todo.Top())) { + if (IsBlockAct(frame->todo.Top())) { + KillScope(stmt->line_num, frame->scopes.Top()); + frame->scopes.Pop(1); } - frame->todo = frame->todo->next; + frame->todo.Pop(1); } break; case StatementKind::Block: { if (act->pos == -1) { auto* scope = new Scope(CurrentEnv(state), std::list()); - frame->scopes = MakeCons(scope, frame->scopes); - frame->todo = MakeCons(MakeStmtAct(stmt->u.block.stmt), frame->todo); + frame->scopes.Push(scope); + frame->todo.Push(MakeStmtAct(stmt->u.block.stmt)); act->pos++; } else { - Scope* scope = frame->scopes->curr; + Scope* scope = frame->scopes.Top(); KillScope(stmt->line_num, scope); - frame->scopes = frame->scopes->next; - frame->todo = frame->todo->next; + frame->scopes.Pop(1); + frame->todo.Pop(1); } break; } case StatementKind::VariableDefinition: // { {(var x = e) :: C, E, F} :: S, H} // -> { {e :: (var x = []) :: C, E, F} :: S, H} - frame->todo = - MakeCons(MakeExpAct(stmt->u.variable_definition.init), frame->todo); + frame->todo.Push(MakeExpAct(stmt->u.variable_definition.init)); act->pos++; break; case StatementKind::ExpressionStatement: // { {e :: C, E, F} :: S, H} // -> { {e :: C, E, F} :: S, H} - frame->todo = MakeCons(MakeExpAct(stmt->u.exp), frame->todo); + frame->todo.Push(MakeExpAct(stmt->u.exp)); break; case StatementKind::Assign: // { {(lv = e) :: C, E, F} :: S, H} // -> { {lv :: ([] = e) :: C, E, F} :: S, H} - frame->todo = MakeCons(MakeLvalAct(stmt->u.assign.lhs), frame->todo); + frame->todo.Push(MakeLvalAct(stmt->u.assign.lhs)); act->pos++; break; case StatementKind::If: // { {(if (e) then_stmt else else_stmt) :: C, E, F} :: S, H} // -> { { e :: (if ([]) then_stmt else else_stmt) :: C, E, F} :: S, H} - frame->todo = MakeCons(MakeExpAct(stmt->u.if_stmt.cond), frame->todo); + frame->todo.Push(MakeExpAct(stmt->u.if_stmt.cond)); act->pos++; break; case StatementKind::Return: // { {return e :: C, E, F} :: S, H} // -> { {e :: return [] :: C, E, F} :: S, H} - frame->todo = MakeCons(MakeExpAct(stmt->u.return_stmt), frame->todo); + frame->todo.Push(MakeExpAct(stmt->u.return_stmt)); act->pos++; break; case StatementKind::Sequence: // { { (s1,s2) :: C, E, F} :: S, H} // -> { { s1 :: s2 :: C, E, F} :: S, H} - Cons* todo = frame->todo->next; + frame->todo.Pop(1); if (stmt->u.sequence.next) { - todo = MakeCons(MakeStmtAct(stmt->u.sequence.next), todo); + frame->todo.Push(MakeStmtAct(stmt->u.sequence.next)); } - frame->todo = MakeCons(MakeStmtAct(stmt->u.sequence.stmt), todo); + frame->todo.Push(MakeStmtAct(stmt->u.sequence.stmt)); break; } } @@ -885,33 +888,37 @@ auto GetMember(Address a, const std::string& f) -> Address { } } -auto InsertDelete(Action* del, Cons* todo) -> Cons* { - if (todo) { - switch (todo->curr->tag) { +void InsertDelete(Action* del, Stack& todo) { + if (!todo.IsEmpty()) { + switch (todo.Top()->tag) { case ActionKind::StatementAction: { // This places the delete before the enclosing statement. // Not sure if that is OK. Conceptually it should go after // but that is tricky for some statements, like 'return'. -Jeremy - return MakeCons(del, todo); + todo.Push(del); + break; } case ActionKind::LValAction: case ActionKind::ExpressionAction: case ActionKind::ValAction: case ActionKind::ExpToLValAction: case ActionKind::DeleteTmpAction: - return MakeCons(todo->curr, InsertDelete(del, todo->next)); + auto top = todo.Pop(); + InsertDelete(del, todo); + todo.Push(top); + break; } } else { - return MakeCons(del, todo); + todo.Push(del); } } /***** State transition for handling a value *****/ void HandleValue() { - Frame* frame = state->stack->curr; - Action* val_act = frame->todo->curr; - Action* act = frame->todo->next->curr; + Frame* frame = state->stack.Top(); + Action* val_act = frame->todo.Top(); + Action* act = frame->todo.Popped().Top(); act->results.push_back(val_act->u.val); act->pos++; @@ -924,14 +931,16 @@ void HandleValue() { switch (act->tag) { case ActionKind::DeleteTmpAction: { KillValue(state->heap[act->u.delete_tmp]); - frame->todo = MakeCons(val_act, frame->todo->next->next); + frame->todo.Pop(2); + frame->todo.Push(val_act); break; } case ActionKind::ExpToLValAction: { Address a = AllocateValue(act->results[0]); auto del = MakeDeleteAct(a); - frame->todo = MakeCons(MakeValAct(MakePtrVal(a)), - InsertDelete(del, frame->todo->next->next)); + frame->todo.Pop(2); + InsertDelete(del, frame->todo); + frame->todo.Push(MakeValAct(MakePtrVal(a))); break; } case ActionKind::LValAction: { @@ -943,14 +952,14 @@ void HandleValue() { Value* str = act->results[0]; Address a = GetMember(ValToPtr(str, exp->line_num), *exp->u.get_field.field); - frame->todo = - MakeCons(MakeValAct(MakePtrVal(a)), frame->todo->next->next); + frame->todo.Pop(2); + frame->todo.Push(MakeValAct(MakePtrVal(a))); break; } case ExpressionKind::Index: { if (act->pos == 1) { - frame->todo = - MakeCons(MakeExpAct(exp->u.index.offset), frame->todo->next); + frame->todo.Pop(1); + frame->todo.Push(MakeExpAct(exp->u.index.offset)); } else if (act->pos == 2) { // { v :: [][i] :: C, E, F} :: S, H} // -> { { &v[i] :: C, E, F} :: S, H } @@ -963,8 +972,8 @@ void HandleValue() { std::cerr << std::endl; exit(-1); } - frame->todo = - MakeCons(MakeValAct(MakePtrVal(*a)), frame->todo->next->next); + frame->todo.Pop(2); + frame->todo.Push(MakeValAct(MakePtrVal(*a))); } break; } @@ -975,9 +984,10 @@ void HandleValue() { // -> { { ek+1 :: (f1=v1,..., fk=vk, fk+1=[],...) :: C, E, F} :: S, // H} Expression* elt = (*exp->u.tuple.fields)[act->pos].second; - frame->todo = MakeCons(MakeLvalAct(elt), frame->todo->next); + frame->todo.Pop(1); + frame->todo.Push(MakeLvalAct(elt)); } else { - frame->todo = frame->todo->next; + frame->todo.Pop(1); CreateTuple(frame, act, exp); } break; @@ -995,7 +1005,8 @@ void HandleValue() { case ExpressionKind::PatternVariable: { auto v = MakeVarPatVal(*exp->u.pattern_variable.name, act->results[0]); - frame->todo = MakeCons(MakeValAct(v), frame->todo->next->next); + frame->todo.Pop(2); + frame->todo.Push(MakeValAct(v)); break; } case ExpressionKind::Tuple: { @@ -1005,17 +1016,18 @@ void HandleValue() { // -> { { ek+1 :: (f1=v1,..., fk=vk, fk+1=[],...) :: C, E, F} :: S, // H} Expression* elt = (*exp->u.tuple.fields)[act->pos].second; - frame->todo = MakeCons(MakeExpAct(elt), frame->todo->next); + frame->todo.Pop(1); + frame->todo.Push(MakeExpAct(elt)); } else { - frame->todo = frame->todo->next; + frame->todo.Pop(1); CreateTuple(frame, act, exp); } break; } case ExpressionKind::Index: { if (act->pos == 1) { - frame->todo = - MakeCons(MakeExpAct(exp->u.index.offset), frame->todo->next); + frame->todo.Pop(1); + frame->todo.Push(MakeExpAct(exp->u.index.offset)); } else if (act->pos == 2) { auto tuple = act->results[0]; switch (tuple->tag) { @@ -1030,8 +1042,8 @@ void HandleValue() { std::cerr << std::endl; exit(-1); } - frame->todo = MakeCons(MakeValAct(state->heap[*a]), - frame->todo->next->next); + frame->todo.Pop(2); + frame->todo.Push(MakeValAct(state->heap[*a])); break; } default: @@ -1049,8 +1061,8 @@ void HandleValue() { // -> { { v_f :: C, E, F} : S, H} auto a = GetMember(ValToPtr(act->results[0], exp->line_num), *exp->u.get_field.field); - frame->todo = - MakeCons(MakeValAct(state->heap[a]), frame->todo->next->next); + frame->todo.Pop(2); + frame->todo.Push(MakeValAct(state->heap[a])); break; } case ExpressionKind::PrimitiveOp: { @@ -1059,13 +1071,15 @@ void HandleValue() { // { {v :: op(vs,[],e,es) :: C, E, F} :: S, H} // -> { {e :: op(vs,v,[],es) :: C, E, F} :: S, H} Expression* arg = (*exp->u.primitive_op.arguments)[act->pos]; - frame->todo = MakeCons(MakeExpAct(arg), frame->todo->next); + frame->todo.Pop(1); + frame->todo.Push(MakeExpAct(arg)); } else { // { {v :: op(vs,[]) :: C, E, F} :: S, H} // -> { {eval_prim(op, (vs,v)) :: C, E, F} :: S, H} Value* v = EvalPrim(exp->u.primitive_op.op, act->results, exp->line_num); - frame->todo = MakeCons(MakeValAct(v), frame->todo->next->next); + frame->todo.Pop(2); + frame->todo.Push(MakeValAct(v)); } break; } @@ -1073,12 +1087,12 @@ void HandleValue() { if (act->pos == 1) { // { { v :: [](e) :: C, E, F} :: S, H} // -> { { e :: v([]) :: C, E, F} :: S, H} - frame->todo = - MakeCons(MakeExpAct(exp->u.call.argument), frame->todo->next); + frame->todo.Pop(1); + frame->todo.Push(MakeExpAct(exp->u.call.argument)); } else if (act->pos == 2) { // { { v2 :: v1([]) :: C, E, F} :: S, H} // -> { {C',E',F'} :: {C, E, F} :: S, H} - frame->todo = frame->todo->next->next; + frame->todo.Pop(2); CallFunction(exp->line_num, act->results, state); } else { std::cerr << "internal error in handle_value with Call" @@ -1092,12 +1106,13 @@ void HandleValue() { // { { 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]); - frame->todo = MakeCons(MakeValAct(v), frame->todo->next->next); + frame->todo.Pop(2); + frame->todo.Push(MakeValAct(v)); } else { // { { pt :: fn [] -> e :: C, E, F} :: S, H} // -> { { e :: fn pt -> []) :: C, E, F} :: S, H} - frame->todo = MakeCons(MakeExpAct(exp->u.function_type.return_type), - frame->todo->next); + frame->todo.Pop(1); + frame->todo.Push(MakeExpAct(exp->u.function_type.return_type)); } break; } @@ -1118,29 +1133,29 @@ void HandleValue() { Statement* stmt = act->u.stmt; switch (stmt->tag) { case StatementKind::ExpressionStatement: - frame->todo = frame->todo->next->next; + frame->todo.Pop(2); break; case StatementKind::VariableDefinition: { if (act->pos == 1) { - frame->todo = MakeCons(MakeExpAct(stmt->u.variable_definition.pat), - frame->todo->next); + frame->todo.Pop(1); + frame->todo.Push(MakeExpAct(stmt->u.variable_definition.pat)); } 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]; // Address a = AllocateValue(CopyVal(v)); - frame->scopes->curr->env = - PatternMatch(p, v, frame->scopes->curr->env, - &frame->scopes->curr->locals, stmt->line_num); - if (!frame->scopes->curr->env) { + frame->scopes.Top()->env = + PatternMatch(p, v, frame->scopes.Top()->env, + &frame->scopes.Top()->locals, stmt->line_num); + if (!frame->scopes.Top()->env) { std::cerr << stmt->line_num << ": internal error in variable definition, match failed" << std::endl; exit(-1); } - frame->todo = frame->todo->next->next; + frame->todo.Pop(2); } break; } @@ -1148,15 +1163,15 @@ void HandleValue() { if (act->pos == 1) { // { { a :: ([] = e) :: C, E, F} :: S, H} // -> { { e :: (a = []) :: C, E, F} :: S, H} - frame->todo = - MakeCons(MakeExpAct(stmt->u.assign.rhs), frame->todo->next); + frame->todo.Pop(1); + frame->todo.Push(MakeExpAct(stmt->u.assign.rhs)); } else if (act->pos == 2) { // { { v :: (a = []) :: C, E, F} :: S, H} // -> { { C, E, F} :: S, H(a := v)} auto pat = act->results[0]; auto val = act->results[1]; PatternAssignment(pat, val, stmt->line_num); - frame->todo = frame->todo->next->next; + frame->todo.Pop(2); } break; case StatementKind::If: @@ -1164,30 +1179,31 @@ void HandleValue() { // { {true :: if ([]) then_stmt else else_stmt :: C, E, F} :: // S, H} // -> { { then_stmt :: C, E, F } :: S, H} - frame->todo = MakeCons(MakeStmtAct(stmt->u.if_stmt.then_stmt), - frame->todo->next->next); + frame->todo.Pop(2); + frame->todo.Push(MakeStmtAct(stmt->u.if_stmt.then_stmt)); } else { // { {false :: if ([]) then_stmt else else_stmt :: C, E, F} :: // S, H} // -> { { else_stmt :: C, E, F } :: S, H} - frame->todo = MakeCons(MakeStmtAct(stmt->u.if_stmt.else_stmt), - frame->todo->next->next); + frame->todo.Pop(2); + frame->todo.Push(MakeStmtAct(stmt->u.if_stmt.else_stmt)); } break; case StatementKind::While: if (ValToBool(act->results[0], stmt->line_num)) { // { {true :: (while ([]) s) :: C, E, F} :: S, H} // -> { { s :: (while (e) s) :: C, E, F } :: S, H} - frame->todo->next->curr->pos = -1; - frame->todo->next->curr->results.clear(); - frame->todo = MakeCons(MakeStmtAct(stmt->u.while_stmt.body), - frame->todo->next); + frame->todo.Pop(1); + frame->todo.Top()->pos = -1; + frame->todo.Top()->results.clear(); + frame->todo.Push(MakeStmtAct(stmt->u.while_stmt.body)); } else { // { {false :: (while ([]) s) :: C, E, F} :: S, H} // -> { { C, E, F } :: S, H} - frame->todo->next->curr->pos = -1; - frame->todo->next->curr->results.clear(); - frame->todo = frame->todo->next->next; + frame->todo.Pop(1); + frame->todo.Top()->pos = -1; + frame->todo.Top()->results.clear(); + frame->todo.Pop(1); } break; case StatementKind::Match: { @@ -1203,7 +1219,7 @@ void HandleValue() { auto clause_num = (act->pos - 1) / 2; if (clause_num >= static_cast(stmt->u.match_stmt.clauses->size())) { - frame->todo = frame->todo->next->next; + frame->todo.Pop(2); break; } auto c = stmt->u.match_stmt.clauses->begin(); @@ -1213,7 +1229,8 @@ void HandleValue() { // start interpreting the pattern of the clause // { {v :: (match ([]) ...) :: C, E, F} :: S, H} // -> { {pi :: (match ([]) ...) :: C, E, F} :: S, H} - frame->todo = MakeCons(MakeExpAct(c->first), frame->todo->next); + frame->todo.Pop(1); + frame->todo.Push(MakeExpAct(c->first)); } else { // try to match auto v = act->results[0]; auto pat = act->results[clause_num + 1]; @@ -1222,13 +1239,13 @@ void HandleValue() { 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); - frame->scopes = MakeCons(new_scope, frame->scopes); + frame->scopes.Push(new_scope); Statement* body_block = MakeBlock(stmt->line_num, c->second); Action* body_act = MakeStmtAct(body_block); body_act->pos = 0; - frame->todo = - MakeCons(MakeStmtAct(c->second), - MakeCons(body_act, frame->todo->next->next)); + frame->todo.Pop(2); + frame->todo.Push(body_act); + frame->todo.Push(MakeStmtAct(c->second)); } else { act->pos++; clause_num = (act->pos - 1) / 2; @@ -1237,9 +1254,10 @@ void HandleValue() { // move on to the next clause c = stmt->u.match_stmt.clauses->begin(); std::advance(c, clause_num); - frame->todo = MakeCons(MakeExpAct(c->first), frame->todo->next); + frame->todo.Pop(1); + frame->todo.Push(MakeExpAct(c->first)); } else { // No more clauses in match - frame->todo = frame->todo->next->next; + frame->todo.Pop(2); } } } @@ -1250,9 +1268,9 @@ void HandleValue() { // -> { {v :: C', E', F'} :: S, H} Value* ret_val = CopyVal(val_act->u.val, stmt->line_num); KillLocals(stmt->line_num, frame); - state->stack = state->stack->next; - frame = state->stack->curr; - frame->todo = MakeCons(MakeValAct(ret_val), frame->todo); + state->stack.Pop(1); + frame = state->stack.Top(); + frame->todo.Push(MakeValAct(ret_val)); break; } case StatementKind::Block: @@ -1274,14 +1292,14 @@ void HandleValue() { // State transition. void Step() { - Frame* frame = state->stack->curr; - if (!frame->todo) { + Frame* frame = state->stack.Top(); + if (frame->todo.IsEmpty()) { std::cerr << "runtime error: fell off end of function " << frame->name << " without `return`" << std::endl; exit(-1); } - Action* act = frame->todo->curr; + Action* act = frame->todo.Top(); switch (act->tag) { case ActionKind::DeleteTmpAction: std::cerr << "internal error in step, did not expect DeleteTmpAction" @@ -1315,35 +1333,37 @@ auto InterpProgram(std::list* fs) -> int { Expression* arg = MakeTuple(0, new std::vector>()); Expression* call_main = MakeCall(0, MakeVar(0, "main"), arg); - Cons* todo = MakeCons(MakeExpAct(call_main)); + auto todo = Stack(MakeExpAct(call_main)); auto* scope = new Scope(globals, std::list()); - auto* frame = new Frame("top", MakeCons(scope), todo); - state->stack = MakeCons(frame); + auto* frame = new Frame("top", Stack(scope), todo); + state->stack = Stack(frame); std::cout << "********** calling main function **********" << std::endl; PrintState(std::cout); - while (Length(state->stack) > 1 || Length(state->stack->curr->todo) > 1 || - state->stack->curr->todo->curr->tag != ActionKind::ValAction) { + while (state->stack.CountExceeds(1) || + state->stack.Top()->todo.CountExceeds(1) || + state->stack.Top()->todo.Top()->tag != ActionKind::ValAction) { Step(); PrintState(std::cout); } - Value* v = state->stack->curr->todo->curr->u.val; + 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* { - Cons* todo = MakeCons(MakeExpAct(e)); + auto todo = Stack(MakeExpAct(e)); auto* scope = new Scope(env, std::list()); - auto* frame = new Frame("InterpExp", MakeCons(scope), todo); - state->stack = MakeCons(frame); + auto* frame = new Frame("InterpExp", Stack(scope), todo); + state->stack = Stack(frame); - while (Length(state->stack) > 1 || Length(state->stack->curr->todo) > 1 || - state->stack->curr->todo->curr->tag != ActionKind::ValAction) { + while (state->stack.CountExceeds(1) || + state->stack.Top()->todo.CountExceeds(1) || + state->stack.Top()->todo.Top()->tag != ActionKind::ValAction) { Step(); } - Value* v = state->stack->curr->todo->curr->u.val; + Value* v = state->stack.Top()->todo.Top()->u.val; return v; } diff --git a/executable_semantics/interpreter/interpreter.h b/executable_semantics/interpreter/interpreter.h index cb291dddd5a2..668a770074d6 100644 --- a/executable_semantics/interpreter/interpreter.h +++ b/executable_semantics/interpreter/interpreter.h @@ -12,7 +12,7 @@ #include "executable_semantics/ast/declaration.h" #include "executable_semantics/interpreter/action.h" #include "executable_semantics/interpreter/assoc_list.h" -#include "executable_semantics/interpreter/cons_list.h" +#include "executable_semantics/interpreter/stack.h" #include "executable_semantics/interpreter/value.h" namespace Carbon { @@ -31,15 +31,15 @@ struct Scope { struct Frame { std::string name; - Cons* scopes; - Cons* todo; + Stack scopes; + Stack todo; - Frame(std::string n, Cons* s, Cons* c) + Frame(std::string n, Stack s, Stack c) : name(std::move(std::move(n))), scopes(s), todo(c) {} }; struct State { - Cons* stack; + Stack stack; std::vector heap; }; diff --git a/executable_semantics/interpreter/stack.h b/executable_semantics/interpreter/stack.h new file mode 100644 index 000000000000..6b0dee533bdb --- /dev/null +++ b/executable_semantics/interpreter/stack.h @@ -0,0 +1,136 @@ +// 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_STACK_H_ +#define EXECUTABLE_SEMANTICS_INTERPRETER_STACK_H_ + +#include +#include +#include + +namespace Carbon { + +/// A persistent stack data structure. +/// +/// - Note: this data structure leaks memory. +template +struct Stack { + /// A forward iterator over elements of a `Stack`. + struct Iterator { + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = const T*; + using reference = const T&; + using iterator_category = std::forward_iterator_tag; + + Iterator(Cons* x) : p(x) {} + Iterator(const Iterator& mit) : p(mit.p) {} + Iterator& operator++() { + p = p->next; + return *this; + } + Iterator operator++(int) { + Iterator tmp(*this); + operator++(); + return tmp; + } + bool operator==(const Iterator& rhs) const { return p == rhs.p; } + bool operator!=(const Iterator& rhs) const { return p != rhs.p; } + const T& operator*() { return p->curr; } + const T* operator->() { return &p->curr; } + + private: + Cons* p; + }; + + /// The position of the first/`Top()` element, or `end()` if + /// `this->IsEmpty()`. + auto begin() const -> Iterator { return Iterator(head); } + + /// The position one past that of the last element. + auto end() const -> Iterator { return Iterator(nullptr); } + + /// Creates an empty instance. + Stack() { head = nullptr; } + + /// Creates an instance containing just `x`. + Stack(T x) : Stack() { Push(x); } + + /// Pushes `x` onto the top of the stack. + void Push(T x) { head = new Cons(x, head); } + + /// Returns a copy of `*this`, with `x` pushed onto the top. + auto Pushing(T x) const -> Stack { + auto r = *this; + r.Push(x); + return r; + } + + /// Removes and returns the top element of the stack. + /// + /// - Requires: !this->IsEmpty() + auto Pop() -> T { + assert(!IsEmpty() && "Can't pop from empty stack."); + auto r = head->curr; + head = head->next; + return r; + } + + /// Removes the top `n` elements of the stack. + /// + /// - Requires: n >= 0 && n <= Count() + void Pop(int n) { + assert(n >= 0 && "Negative pop count disallowed."); + while (n--) { + assert(head != nullptr && "Can only pop as many elements as stack has."); + head = head->next; + } + } + + /// Returns a copy of `*this`, sans the top element. + /// + /// - Requires: !this->IsEmpty() + auto Popped() const -> Stack { + auto r = *this; + r.Pop(); + return r; + } + + /// Returns the top element of the stack. + /// + /// - Requires: !this->IsEmpty() + auto Top() const -> T { + assert(!IsEmpty() && "Empty stack has no Top()."); + return head->curr; + } + + /// Returns `true` iff `Count() > 0`. + auto IsEmpty() const -> bool { return head == nullptr; } + + /// Returns `true` iff `Count() > n`. + /// + /// - Complexity: O(`n`) + auto CountExceeds(int n) const -> bool { + if (n < 0) + return true; + + for (auto p = head; p != nullptr; p = p->next) { + if (n-- == 0) + return true; + } + + return false; + } + + /// Returns the number of elements in `*this`. + auto Count() const -> int { return std::distance(begin(), end()); } + + private: + /// An linked list of cells containing the elements of self. + Cons* head; +}; + +} // namespace Carbon + +#endif // EXECUTABLE_SEMANTICS_INTERPRETER_CONS_LIST_H_ diff --git a/executable_semantics/interpreter/typecheck.cpp b/executable_semantics/interpreter/typecheck.cpp index 9fa30f631688..1c8c9f78544a 100644 --- a/executable_semantics/interpreter/typecheck.cpp +++ b/executable_semantics/interpreter/typecheck.cpp @@ -4,7 +4,9 @@ #include "executable_semantics/interpreter/typecheck.h" +#include #include +#include #include #include #include @@ -15,19 +17,6 @@ namespace Carbon { -auto Find(const std::string& s, Cons* ls, int n) -> int { - if (ls) { - if (ls->curr == s) { - return n; - } else { - return Find(s, ls->next, n + 1); - } - } else { - std::cerr << "could not find " << s << std::endl; - exit(-1); - } -} - void ExpectType(int line_num, const std::string& context, Value* expected, Value* actual) { if (!TypeEqual(expected, actual)) { diff --git a/executable_semantics/testdata/match_int.golden b/executable_semantics/testdata/match_int.golden index 09c9b93feaae..c0e330959c2f 100644 --- a/executable_semantics/testdata/match_int.golden +++ b/executable_semantics/testdata/match_int.golden @@ -169,7 +169,7 @@ env: t: 5, main: fun
, --- handle value 0 with return 0;<1>(0,) ---> { stack: top{0<-1>} -heap: fun
, 5, +heap: fun
, !!5, env: main: fun
, } result: 0 diff --git a/executable_semantics/testdata/match_int_default.golden b/executable_semantics/testdata/match_int_default.golden index 822c67942d7d..f37685493c5d 100644 --- a/executable_semantics/testdata/match_int_default.golden +++ b/executable_semantics/testdata/match_int_default.golden @@ -211,7 +211,7 @@ env: _: 5, t: 5, main: fun
, --- handle value 0 with return 0;<1>(0,) ---> { stack: top{0<-1>} -heap: fun
, 5, !!5, +heap: fun
, !!5, !!5, env: main: fun
, } result: 0 diff --git a/executable_semantics/testdata/tuple_match.golden b/executable_semantics/testdata/tuple_match.golden index f799a5869a1d..367151e15b6c 100644 --- a/executable_semantics/testdata/tuple_match.golden +++ b/executable_semantics/testdata/tuple_match.golden @@ -312,7 +312,7 @@ env: b: 2, a: 5, t: (0 = 5@3, 1 = 2@4), main: fun
, --- handle value 0 with return ((a + b) - 7);<1>(0,) ---> { stack: top{0<-1>} -heap: fun
, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), auto: a, auto: b, !!5, !!2, +heap: fun
, 5, 2, !!5, !!2, !!(0 = !!5@3, 1 = !!2@4), auto: a, auto: b, !!5, !!2, env: main: fun
, } result: 0