|
|
@@ -15,8 +15,9 @@
|
|
|
#include "common/check.h"
|
|
|
#include "executable_semantics/ast/expression.h"
|
|
|
#include "executable_semantics/ast/function_definition.h"
|
|
|
+#include "executable_semantics/interpreter/action.h"
|
|
|
+#include "executable_semantics/interpreter/frame.h"
|
|
|
#include "executable_semantics/interpreter/stack.h"
|
|
|
-#include "executable_semantics/interpreter/typecheck.h"
|
|
|
#include "executable_semantics/tracing_flag.h"
|
|
|
|
|
|
namespace Carbon {
|
|
|
@@ -30,109 +31,6 @@ auto Step() -> void;
|
|
|
// Auxiliary Functions
|
|
|
//
|
|
|
|
|
|
-auto Heap::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.
|
|
|
- CHECK(v != nullptr);
|
|
|
- Address a(values_.size());
|
|
|
- values_.push_back(v);
|
|
|
- alive_.push_back(true);
|
|
|
- return a;
|
|
|
-}
|
|
|
-
|
|
|
-auto Heap::Read(const Address& a, int line_num) -> const Value* {
|
|
|
- this->CheckAlive(a, line_num);
|
|
|
- return values_[a.index]->GetField(a.field_path, line_num);
|
|
|
-}
|
|
|
-
|
|
|
-auto Heap::Write(const Address& a, const Value* v, int line_num) -> void {
|
|
|
- CHECK(v != nullptr);
|
|
|
- this->CheckAlive(a, line_num);
|
|
|
- values_[a.index] = values_[a.index]->SetField(a.field_path, v, line_num);
|
|
|
-}
|
|
|
-
|
|
|
-void Heap::CheckAlive(const Address& address, int line_num) {
|
|
|
- if (!alive_[address.index]) {
|
|
|
- std::cerr << line_num << ": undefined behavior: access to dead value ";
|
|
|
- PrintValue(values_[address.index], std::cerr);
|
|
|
- std::cerr << std::endl;
|
|
|
- exit(-1);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-auto CopyVal(const Value* val, int line_num) -> const Value* {
|
|
|
- switch (val->tag()) {
|
|
|
- case ValKind::TupleValue: {
|
|
|
- std::vector<TupleElement> elements;
|
|
|
- for (const TupleElement& element : val->GetTupleValue().elements) {
|
|
|
- elements.push_back(
|
|
|
- {.name = element.name, .value = CopyVal(element.value, line_num)});
|
|
|
- }
|
|
|
- return Value::MakeTupleValue(std::move(elements));
|
|
|
- }
|
|
|
- case ValKind::AlternativeValue: {
|
|
|
- const Value* arg = CopyVal(val->GetAlternativeValue().argument, line_num);
|
|
|
- return Value::MakeAlternativeValue(val->GetAlternativeValue().alt_name,
|
|
|
- val->GetAlternativeValue().choice_name,
|
|
|
- arg);
|
|
|
- }
|
|
|
- case ValKind::StructValue: {
|
|
|
- const Value* inits = CopyVal(val->GetStructValue().inits, line_num);
|
|
|
- return Value::MakeStructValue(val->GetStructValue().type, inits);
|
|
|
- }
|
|
|
- case ValKind::IntValue:
|
|
|
- return Value::MakeIntValue(val->GetIntValue());
|
|
|
- case ValKind::BoolValue:
|
|
|
- return Value::MakeBoolValue(val->GetBoolValue());
|
|
|
- case ValKind::FunctionValue:
|
|
|
- return Value::MakeFunctionValue(val->GetFunctionValue().name,
|
|
|
- val->GetFunctionValue().param,
|
|
|
- val->GetFunctionValue().body);
|
|
|
- case ValKind::PointerValue:
|
|
|
- return Value::MakePointerValue(val->GetPointerValue());
|
|
|
- case ValKind::ContinuationValue:
|
|
|
- // Copying a continuation is "shallow".
|
|
|
- return val;
|
|
|
- case ValKind::FunctionType:
|
|
|
- return Value::MakeFunctionType(
|
|
|
- CopyVal(val->GetFunctionType().param, line_num),
|
|
|
- CopyVal(val->GetFunctionType().ret, line_num));
|
|
|
-
|
|
|
- case ValKind::PointerType:
|
|
|
- return Value::MakePointerType(
|
|
|
- CopyVal(val->GetPointerType().type, line_num));
|
|
|
- case ValKind::IntType:
|
|
|
- return Value::MakeIntType();
|
|
|
- case ValKind::BoolType:
|
|
|
- return Value::MakeBoolType();
|
|
|
- case ValKind::TypeType:
|
|
|
- return Value::MakeTypeType();
|
|
|
- case ValKind::AutoType:
|
|
|
- return Value::MakeAutoType();
|
|
|
- case ValKind::ContinuationType:
|
|
|
- return Value::MakeContinuationType();
|
|
|
- case ValKind::StructType:
|
|
|
- case ValKind::ChoiceType:
|
|
|
- case ValKind::BindingPlaceholderValue:
|
|
|
- case ValKind::AlternativeConstructorValue:
|
|
|
- return val; // no need to copy these because they are immutable?
|
|
|
- // No, they need to be copied so they don't get killed. -Jeremy
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void Heap::Deallocate(const Address& address) {
|
|
|
- CHECK(address.field_path.IsEmpty());
|
|
|
- if (alive_[address.index]) {
|
|
|
- alive_[address.index] = false;
|
|
|
- } else {
|
|
|
- std::cerr << "runtime error, deallocating an already dead value"
|
|
|
- << std::endl;
|
|
|
- exit(-1);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
void PrintEnv(Env values, std::ostream& out) {
|
|
|
for (const auto& [name, address] : values) {
|
|
|
out << name << ": ";
|
|
|
@@ -142,16 +40,9 @@ void PrintEnv(Env values, std::ostream& out) {
|
|
|
}
|
|
|
|
|
|
//
|
|
|
-// Frame and State Operations
|
|
|
+// State Operations
|
|
|
//
|
|
|
|
|
|
-void PrintFrame(Frame* frame, std::ostream& out) {
|
|
|
- out << frame->name;
|
|
|
- out << "{";
|
|
|
- Action::PrintList(frame->todo, out);
|
|
|
- out << "}";
|
|
|
-}
|
|
|
-
|
|
|
void PrintStack(Stack<Frame*> ls, std::ostream& out) {
|
|
|
if (!ls.IsEmpty()) {
|
|
|
PrintFrame(ls.Pop(), out);
|
|
|
@@ -162,20 +53,6 @@ void PrintStack(Stack<Frame*> ls, std::ostream& out) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void Heap::PrintHeap(std::ostream& out) {
|
|
|
- for (size_t i = 0; i < values_.size(); ++i) {
|
|
|
- PrintAddress(Address(i), out);
|
|
|
- out << ", ";
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-auto Heap::PrintAddress(const Address& a, std::ostream& out) -> void {
|
|
|
- if (!alive_[a.index]) {
|
|
|
- out << "!!";
|
|
|
- }
|
|
|
- PrintValue(values_[a.index], out);
|
|
|
-}
|
|
|
-
|
|
|
auto CurrentEnv(State* state) -> Env {
|
|
|
Frame* frame = state->stack.Top();
|
|
|
return frame->scopes.Top()->values;
|