|
|
@@ -31,8 +31,8 @@ static void runtimeError(const char *format, ...) {
|
|
|
fputs("\n", stderr);
|
|
|
for (int i = vm.frameCount - 1; i >= 0; i--) {
|
|
|
CallFrame *frame = &vm.frames[i];
|
|
|
- ObjFunction *function = frame->function;
|
|
|
- size_t instruction = frame->ip - frame->function->chunk.code - 1;
|
|
|
+ ObjFunction *function = frame->closure->function;
|
|
|
+ size_t instruction = frame->ip - function->chunk.code - 1;
|
|
|
int line = function->chunk.lines[instruction];
|
|
|
fprintf(stderr, "[line %d] in ", line);
|
|
|
if (function->name == NULL) {
|
|
|
@@ -70,9 +70,9 @@ void initVM() {
|
|
|
static Value peek(int distance) {
|
|
|
return vm.stackTop[-1 - distance];
|
|
|
}
|
|
|
-static bool call(ObjFunction *function, int argCount) {
|
|
|
- if (argCount != function->arity) {
|
|
|
- runtimeError("Expected %d arguments but got %d", function->arity, argCount);
|
|
|
+static bool call(ObjClosure *closure, int argCount) {
|
|
|
+ if (argCount != closure->function->arity) {
|
|
|
+ runtimeError("Expected %d arguments but got %d", closure->function->arity, argCount);
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
@@ -82,16 +82,16 @@ static bool call(ObjFunction *function, int argCount) {
|
|
|
}
|
|
|
|
|
|
CallFrame *frame = &vm.frames[vm.frameCount++];
|
|
|
- frame->function = function;
|
|
|
- frame->ip = function->chunk.code;
|
|
|
+ frame->closure = closure;
|
|
|
+ frame->ip = closure->function->chunk.code;
|
|
|
frame->slots = vm.stackTop - argCount - 1;
|
|
|
return true;
|
|
|
}
|
|
|
static bool callValue(Value callee, int argCount) {
|
|
|
if (IS_OBJ(callee)) {
|
|
|
switch (OBJ_TYPE(callee)) {
|
|
|
- case OBJ_FUNCTION:
|
|
|
- return call(AS_FUNCTION(callee), argCount);
|
|
|
+ case OBJ_CLOSURE:
|
|
|
+ return call(AS_CLOSURE(callee), argCount);
|
|
|
case OBJ_NATIVE: {
|
|
|
NativeFn fn = AS_NATIVE(callee);
|
|
|
Value result = fn(argCount, vm.stackTop - argCount);
|
|
|
@@ -124,6 +124,12 @@ static void concatenate() {
|
|
|
ObjString *result = takeString(chars, length);
|
|
|
push(OBJ_VAL(result));
|
|
|
}
|
|
|
+static ObjUpvalue *captureUpvalue(Value *local) {
|
|
|
+ ObjUpvalue *createdUpvalue = newUpvalue(local);
|
|
|
+ return createdUpvalue;
|
|
|
+}
|
|
|
+/// VM run function - exec opcode
|
|
|
+/// \return
|
|
|
static InterpretResult run() {
|
|
|
CallFrame *frame = &vm.frames[vm.frameCount - 1];
|
|
|
|
|
|
@@ -132,7 +138,9 @@ static InterpretResult run() {
|
|
|
#define READ_BYTE() (*frame->ip++)
|
|
|
//! reads the next byte from the bytecode
|
|
|
//! treats the resulting number as an index
|
|
|
-#define READ_CONSTANT() (frame->function->chunk.constants.values[READ_BYTE()])
|
|
|
+#define READ_CONSTANT() \
|
|
|
+ (frame->closure->function->chunk.constants.values[READ_BYTE()])
|
|
|
+
|
|
|
#define READ_SHORT() \
|
|
|
(frame->ip += 2, (uint16_t) ((frame->ip[-2] << 8) | frame->ip[-1]))
|
|
|
#define READ_STRING() AS_STRING(READ_CONSTANT())
|
|
|
@@ -164,7 +172,7 @@ static InterpretResult run() {
|
|
|
//! <Stack tracing> end
|
|
|
|
|
|
printf("The Instruction: \n");
|
|
|
- disassembleInstruction(&frame->function->chunk, (int) (frame->ip - frame->function->chunk.code));
|
|
|
+ disassembleInstruction(&frame->closure->function->chunk, (int) (frame->ip - frame->closure->function->chunk.code));
|
|
|
#endif
|
|
|
uint8_t opCode = READ_BYTE();
|
|
|
switch (opCode) {
|
|
|
@@ -293,6 +301,31 @@ static InterpretResult run() {
|
|
|
frame = &vm.frames[vm.frameCount - 1];
|
|
|
break;
|
|
|
}
|
|
|
+ case OP_CLOSURE: {
|
|
|
+ ObjFunction *function = AS_FUNCTION(READ_CONSTANT());
|
|
|
+ ObjClosure *closure = newClosure(function);
|
|
|
+ push(OBJ_VAL(closure));
|
|
|
+ for (int i = 0; i < closure->upvalueCount; i++) {
|
|
|
+ uint8_t isLocal = READ_BYTE();
|
|
|
+ uint8_t index = READ_BYTE();
|
|
|
+ if (isLocal) {
|
|
|
+ closure->upvalues[i] = captureUpvalue(frame->slots + index);
|
|
|
+ } else {
|
|
|
+ closure->upvalues[i] = frame->closure->upvalues[index];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case OP_GET_UPVALUE: {
|
|
|
+ uint8_t slot = READ_BYTE();
|
|
|
+ push(*frame->closure->upvalues[slot]->location);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case OP_SET_UPVALUE: {
|
|
|
+ uint8_t slot = READ_BYTE();
|
|
|
+ *frame->closure->upvalues[slot]->location = peek(0);
|
|
|
+ break;
|
|
|
+ }
|
|
|
case OP_RETURN: {
|
|
|
Value result = pop();
|
|
|
vm.frameCount--;
|
|
|
@@ -329,12 +362,15 @@ InterpretResult interpret(const char *source) {
|
|
|
if (function == NULL) return INTERPRET_COMPILE_ERROR;
|
|
|
|
|
|
push(OBJ_VAL(function));
|
|
|
+ ObjClosure *closure = newClosure(function);
|
|
|
+ pop();
|
|
|
+ push(OBJ_VAL(closure));
|
|
|
|
|
|
// CallFrame *frame = &vm.frames[vm.frameCount++];
|
|
|
// frame->function = function;
|
|
|
// frame->ip = function->chunk.code;
|
|
|
// frame->slots = vm.stack;
|
|
|
- call(function, 0);
|
|
|
+ call(closure, 0);
|
|
|
|
|
|
return run();
|
|
|
}
|