From cb42c811218b30ff9ff1a194b18fe3d85ea68a50 Mon Sep 17 00:00:00 2001 From: Tom Willemse Date: Sun, 14 Aug 2022 16:11:39 -0700 Subject: [PATCH] Chapter 28.4 --- clox/src/compiler.c | 23 +++++++++++++++++++++-- clox/src/memory.c | 1 + clox/src/vm.c | 11 +++++++++++ clox/src/vm.h | 1 + 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/clox/src/compiler.c b/clox/src/compiler.c index a773e97..4dded64 100644 --- a/clox/src/compiler.c +++ b/clox/src/compiler.c @@ -51,7 +51,12 @@ typedef struct { bool isLocal; } Upvalue; -typedef enum { TYPE_FUNCTION, TYPE_METHOD, TYPE_SCRIPT } FunctionType; +typedef enum { + TYPE_FUNCTION, + TYPE_INITIALIZER, + TYPE_METHOD, + TYPE_SCRIPT +} FunctionType; typedef struct Compiler { struct Compiler *enclosing; @@ -159,7 +164,12 @@ static int emitJump(uint8_t instruction) { } static void emitReturn() { - emitByte(OP_NIL); + if (current->type == TYPE_INITIALIZER) { + emitBytes(OP_GET_LOCAL, 0); + } else { + emitByte(OP_NIL); + } + emitByte(OP_RETURN); } @@ -389,6 +399,11 @@ static void method() { uint8_t constant = identifierConstant(&parser.previous); FunctionType type = TYPE_METHOD; + if (parser.previous.length == 4 && + memcmp(parser.previous.start, "init", 4) == 0) { + type = TYPE_INITIALIZER; + } + function(type); emitBytes(OP_METHOD, constant); } @@ -588,6 +603,10 @@ static void returnStatement() { if (match(TOKEN_SEMICOLON)) { emitReturn(); } else { + if (current->type == TYPE_INITIALIZER) { + error("Can't return a value from an initializer."); + } + expression(); consume(TOKEN_SEMICOLON, "Expect ';' after return value."); emitByte(OP_RETURN); diff --git a/clox/src/memory.c b/clox/src/memory.c index b93b6d6..abf1cdd 100644 --- a/clox/src/memory.c +++ b/clox/src/memory.c @@ -180,6 +180,7 @@ static void markRoots() { markTable(&vm.globals); markCompilerRoots(); + markObject((Obj *)vm.initString); } static void traceReferences() { diff --git a/clox/src/vm.c b/clox/src/vm.c index 6b15a3a..d248609 100644 --- a/clox/src/vm.c +++ b/clox/src/vm.c @@ -65,12 +65,16 @@ void initVM() { initTable(&vm.globals); initTable(&vm.strings); + vm.initString = NULL; + vm.initString = copyString("init", 4); + defineNative("clock", clockNative); } void freeVM() { freeTable(&vm.globals); freeTable(&vm.strings); + vm.initString = NULL; freeObjects(); } @@ -116,6 +120,13 @@ static bool callValue(Value callee, int argCount) { case OBJ_CLASS: { ObjClass *klass = AS_CLASS(callee); vm.stackTop[-argCount - 1] = OBJ_VAL(newInstance(klass)); + Value initializer; + if (tableGet(&klass->methods, vm.initString, &initializer)) { + return call(AS_CLOSURE(initializer), argCount); + } else if (argCount != 0) { + runtimeError("Expected 0 arguments but got %d.", argCount); + return false; + } return true; } case OBJ_CLOSURE: diff --git a/clox/src/vm.h b/clox/src/vm.h index e108daa..18495c8 100644 --- a/clox/src/vm.h +++ b/clox/src/vm.h @@ -23,6 +23,7 @@ typedef struct { Value *stackTop; Table globals; Table strings; + ObjString *initString; ObjUpvalue *openUpvalues; size_t bytesAllocated;