Skip to content

Commit

Permalink
feat: first step everything is a closure
Browse files Browse the repository at this point in the history
  • Loading branch information
shejialuo committed Apr 5, 2023
1 parent ce239aa commit 751e763
Show file tree
Hide file tree
Showing 11 changed files with 90 additions and 25 deletions.
9 changes: 9 additions & 0 deletions code/code.cpp
Expand Up @@ -32,6 +32,7 @@ const Opcode Ops::OpReturn{21};
const Opcode Ops::OpGetLocal{22};
const Opcode Ops::OpSetLocal{23};
const Opcode Ops::OpGetBuiltin{24};
const Opcode Ops::OpClosure{25};

const std::unordered_map<Opcode, Definition> Code::definitions{
// For OpConstant, we store the index not the number itself
Expand Down Expand Up @@ -135,6 +136,12 @@ const std::unordered_map<Opcode, Definition> Code::definitions{
Ops::OpGetBuiltin,
Definition{"OpGetBuiltin", {1}},
},
{
Ops::OpClosure,
// The first operand is the index of the constant, the second operand is
// the number of free variables
Definition{"OpClosure", {2, 1}},
},
};

Instructions Code::make(const Opcode &op, const std::vector<int> &operands) {
Expand Down Expand Up @@ -225,6 +232,8 @@ std::string Code::getString(Instructions &instruction) {
info += definition.name;
} else if (operandCount == 1) {
info += definition.name + " " + std::to_string(operands[0]);
} else if (operandCount == 2) {
info += definition.name + " " + std::to_string(operands[0]) + " " + std::to_string(operands[1]);
} else {
info += "ERROR: unhandled operandCount for" + definition.name;
}
Expand Down
1 change: 1 addition & 0 deletions code/code.hpp
Expand Up @@ -56,6 +56,7 @@ struct Ops {
static const Opcode OpGetLocal;
static const Opcode OpSetLocal;
static const Opcode OpGetBuiltin;
static const Opcode OpClosure;
};

/**
Expand Down
5 changes: 4 additions & 1 deletion code/tests/codeTest.cpp
Expand Up @@ -17,6 +17,7 @@ TEST(Code, TestMake) {
{Ops::OpConstant, {20}, {Ops::OpConstant, std::byte(0), std::byte(20)}},
{Ops::OpAdd, {}, {Ops::OpAdd}},
{Ops::OpGetLocal, {255}, {Ops::OpGetLocal, std::byte(255)}},
{Ops::OpClosure, {65534, 255}, {Ops::OpClosure, std::byte(255), std::byte(254), std::byte(255)}},
};

for (auto &test : tests) {
Expand Down Expand Up @@ -59,12 +60,14 @@ TEST(Code, TestInstructionString) {
Code::make(Ops::OpConstant, {1}),
Code::make(Ops::OpConstant, {2}),
Code::make(Ops::OpConstant, {65535}),
Code::make(Ops::OpClosure, {65535, 255}),
};

std::string expected{"0000 OpAdd\n"
"0001 OpConstant 1\n"
"0004 OpConstant 2\n"
"0007 OpConstant 65535\n"};
"0007 OpConstant 65535\n"
"0010 OpClosure 65535 255\n"};

Instructions instruction{};
for (auto &&ins : instructions) {
Expand Down
4 changes: 3 additions & 1 deletion compiler/compiler.cpp
Expand Up @@ -210,7 +210,9 @@ void Compiler::compile(Node *node) {

std::unique_ptr<Object> compiledFunction = std::make_unique<CompiledFunction>(std::move(instructions), numLocals);

emit(Ops::OpConstant, {addConstant(compiledFunction)});
int functionIndex = addConstant(compiledFunction);

emit(Ops::OpClosure, {functionIndex, 0});
}

ReturnStatement *returnStatement = dynamic_cast<ReturnStatement *>(node);
Expand Down
16 changes: 8 additions & 8 deletions compiler/tests/compilerTest.cpp
Expand Up @@ -541,7 +541,7 @@ TEST(Compiler, TestFunctions) {
},
},
{
Code::make(Ops::OpConstant, {2}),
Code::make(Ops::OpClosure, {2, 0}),
Code::make(Ops::OpPop, {}),
},
},
Expand All @@ -561,7 +561,7 @@ TEST(Compiler, TestFunctions) {
},
},
{
Code::make(Ops::OpConstant, {2}),
Code::make(Ops::OpClosure, {2, 0}),
Code::make(Ops::OpPop, {}),
},
},
Expand All @@ -581,7 +581,7 @@ TEST(Compiler, TestFunctions) {
},
},
{
Code::make(Ops::OpConstant, {2}),
Code::make(Ops::OpClosure, {2, 0}),
Code::make(Ops::OpPop, {}),
},
},
Expand Down Expand Up @@ -641,7 +641,7 @@ TEST(Compiler, TestFunctionCalls) {
},
},
{
Code::make(Ops::OpConstant, {1}),
Code::make(Ops::OpClosure, {1, 0}),
Code::make(Ops::OpCall, {0}),
Code::make(Ops::OpPop, {}),
},
Expand All @@ -660,7 +660,7 @@ TEST(Compiler, TestFunctionCalls) {
},
},
{
Code::make(Ops::OpConstant, {1}),
Code::make(Ops::OpClosure, {1, 0}),
Code::make(Ops::OpSetGlobal, {0}),
Code::make(Ops::OpGetGlobal, {0}),
Code::make(Ops::OpCall, {0}),
Expand Down Expand Up @@ -696,7 +696,7 @@ TEST(Compiler, TestLetStatementScopes) {
{
Code::make(Ops::OpConstant, {0}),
Code::make(Ops::OpSetGlobal, {0}),
Code::make(Ops::OpConstant, {1}),
Code::make(Ops::OpClosure, {1, 0}),
Code::make(Ops::OpPop, {}),
},
},
Expand All @@ -715,7 +715,7 @@ TEST(Compiler, TestLetStatementScopes) {
},
},
{
Code::make(Ops::OpConstant, {1}),
Code::make(Ops::OpClosure, {1, 0}),
Code::make(Ops::OpPop, {}),
},
},
Expand All @@ -739,7 +739,7 @@ TEST(Compiler, TestLetStatementScopes) {
},
},
{
Code::make(Ops::OpConstant, {2}),
Code::make(Ops::OpClosure, {2, 0}),
Code::make(Ops::OpPop, {}),
},
},
Expand Down
13 changes: 13 additions & 0 deletions object/object.cpp
Expand Up @@ -15,6 +15,7 @@ constexpr std::string_view STRING_OBJ = "STRING";
constexpr std::string_view BUILTIN_OBJ = "BUILTIN";
constexpr std::string_view ARRAY_OBJ = "ARRAY";
constexpr std::string_view COMPILED_FUNCTION_OBJ = "COMPILED_FUNCTION";
constexpr std::string_view CLOSURE_OBJ = "CLOSURE";

Integer::Integer(int64_t v) : value{v} {}
std::string Integer::inspect() { return std::to_string(value); }
Expand Down Expand Up @@ -81,6 +82,18 @@ std::string CompiledFunction::inspect() {
}
ObjectType CompiledFunction::type() { return std::string(COMPILED_FUNCTION_OBJ); }

ObjectType Closure::type() { return std::string(CLOSURE_OBJ); }
std::string Closure::inspect() {
const void *address = static_cast<const void *>(this);

std::stringstream ss;
ss << address;

std::string info = "Closure" + ss.str();

return info;
}

Builtin::Builtin(BuiltinFunction f) : fn{f} {}
std::string Builtin::inspect() { return "builtin function"; }
ObjectType Builtin::type() { return std::string(BUILTIN_OBJ); }
Expand Down
10 changes: 10 additions & 0 deletions object/object.hpp
Expand Up @@ -109,6 +109,16 @@ class CompiledFunction : public Object {
std::string inspect() override;
};

class Closure : public Object {
public:
std::shared_ptr<CompiledFunction> fn;

Closure(std::shared_ptr<CompiledFunction> &fn_) : fn{fn_} {}

ObjectType type() override;
std::string inspect() override;
};

/**
* @brief Error class represents the error
*
Expand Down
2 changes: 1 addition & 1 deletion vm/frame.cpp
@@ -1,3 +1,3 @@
#include "frame.hpp"

Instructions &Frame::instructions() { return fn->instructions; }
Instructions &Frame::instructions() { return closure->fn->instructions; }
4 changes: 2 additions & 2 deletions vm/frame.hpp
Expand Up @@ -8,14 +8,14 @@

class Frame {
public:
std::shared_ptr<CompiledFunction> fn;
std::shared_ptr<Closure> closure;
int ip;
int basePointer;

Frame() = default;
Frame(const Frame &f) = default;
Frame(Frame &&f) = default;
Frame(std::shared_ptr<CompiledFunction> &fn_, int basePointer_) : fn{fn_}, ip{-1}, basePointer{basePointer_} {}
Frame(std::shared_ptr<Closure> &closure_, int basePointer_) : closure{closure_}, ip{-1}, basePointer{basePointer_} {}

Instructions &instructions();
};
Expand Down
32 changes: 26 additions & 6 deletions vm/vm.cpp
Expand Up @@ -124,6 +124,13 @@ void VM::run() {
std::shared_ptr<Object> definition = Builtins::getBuiltinByIndex(builtIndex);

push(definition);
} else if (op == Ops::OpClosure) {
int constantIndex = readTwoBytes(instructions, ip);
int freeVariableSize = int(instructions[ip + 3]);
currentFrame()->ip += 3;

pushClosure(constantIndex);

} else {
spdlog::error("unknown opcode: {}", op);
}
Expand Down Expand Up @@ -331,9 +338,9 @@ std::shared_ptr<Frame> VM::popFrame() {
}

void VM::executeCall(int argumentSize) {
std::shared_ptr<CompiledFunction> fn = std::dynamic_pointer_cast<CompiledFunction>(stack[sp - 1 - argumentSize]);
if (fn != nullptr) {
return callFunction(fn, argumentSize);
std::shared_ptr<Closure> closure = std::dynamic_pointer_cast<Closure>(stack[sp - 1 - argumentSize]);
if (closure != nullptr) {
return callClosure(closure, argumentSize);
}

std::shared_ptr<Builtin> builtin = std::dynamic_pointer_cast<Builtin>(stack[sp - 1 - argumentSize]);
Expand All @@ -343,13 +350,13 @@ void VM::executeCall(int argumentSize) {

spdlog::error("calling non-function and non-builtin");
}
void VM::callFunction(std::shared_ptr<CompiledFunction> &fn, int argumentSize) {
auto frame = std::make_shared<Frame>(fn, sp - argumentSize);
void VM::callClosure(std::shared_ptr<Closure> &closure, int argumentSize) {
auto frame = std::make_shared<Frame>(closure, sp - argumentSize);
pushFrame(frame);

// we extend the sp value for storing locals, the local constant
// need the binding here.
sp += fn->numLocals;
sp += closure->fn->numLocals;
}

void VM::callBuiltin(std::shared_ptr<Builtin> &builtin, int argumentSize) {
Expand All @@ -365,3 +372,16 @@ void VM::callBuiltin(std::shared_ptr<Builtin> &builtin, int argumentSize) {
push(result);
}
}

void VM::pushClosure(int constantIndex) {
auto constant = constants[constantIndex];
auto fn = std::dynamic_pointer_cast<CompiledFunction>(constant);
if (fn == nullptr) {
spdlog::error("not a function: {}", constant->type());
return;
}

std::shared_ptr<Object> closure = std::make_shared<Closure>(fn);

push(closure);
}
19 changes: 13 additions & 6 deletions vm/vm.hpp
Expand Up @@ -39,8 +39,8 @@ class VM {
: constants{std::move(constants_)}, sp{0}, stack(StackSize), frames(MaxFrames), framesIndex{1} {
globals = std::make_shared<std::vector<std::shared_ptr<Object>>>(GlobalSize);
auto mainFn = std::make_shared<CompiledFunction>(std::move(instructions), 0);
// Here, we must set the frame's ip to -1
auto mainFrame = std::make_shared<Frame>(mainFn, 0);
auto mainClosure = std::make_shared<Closure>(mainFn);
auto mainFrame = std::make_shared<Frame>(mainClosure, 0);
frames[0] = mainFrame;
}

Expand All @@ -54,7 +54,8 @@ class VM {
, frames(MaxFrames)
, framesIndex{1} {
auto mainFn = std::make_shared<CompiledFunction>(std::move(instructions), 0);
auto mainFrame = std::make_shared<Frame>(mainFn, 0);
auto mainClosure = std::make_shared<Closure>(mainFn);
auto mainFrame = std::make_shared<Frame>(mainClosure, 0);
frames[0] = mainFrame;
}

Expand Down Expand Up @@ -162,12 +163,18 @@ class VM {
void executeCall(int argumentSize);

/**
* @brief execute the function call
* @brief execute the function closure
*
* @param fn
* @param closure
* @param argumentSize
*/
void callFunction(std::shared_ptr<CompiledFunction> &fn, int argumentSize);
void callClosure(std::shared_ptr<Closure> &closure, int argumentSize);

/**
* @brief push the closure to the stack at the run time
*
*/
void pushClosure(int constantIndex);

/**
* @brief execute the builtin function call
Expand Down

0 comments on commit 751e763

Please sign in to comment.