diff --git a/clox/src/chunk.h b/clox/src/chunk.h index 9fff535..9c75c1d 100644 --- a/clox/src/chunk.h +++ b/clox/src/chunk.h @@ -37,6 +37,7 @@ typedef enum { OP_CLOSE_UPVALUE, OP_RETURN, OP_CLASS, + OP_METHOD, } OpCode; typedef struct { diff --git a/clox/src/compiler.c b/clox/src/compiler.c index 6ab4855..31a7937 100644 --- a/clox/src/compiler.c +++ b/clox/src/compiler.c @@ -374,6 +374,15 @@ static void function(FunctionType type) { } } +static void method() { + consume(TOKEN_IDENTIFIER, "Expect method name."); + uint8_t constant = identifierConstant(&parser.previous); + + FunctionType type = TYPE_FUNCTION; + function(type); + emitBytes(OP_METHOD, constant); +} + static bool identifiersEqual(Token *a, Token *b) { if (a->length != b->length) return false; @@ -411,16 +420,46 @@ static void declareVariable() { addLocal(*name); } +static void namedVariable(Token name, bool canAssign) { + uint8_t getOp, setOp; + int arg = resolveLocal(current, &name); + + if (arg != -1) { + getOp = OP_GET_LOCAL; + setOp = OP_SET_LOCAL; + } else if ((arg = resolveUpvalue(current, &name)) != -1) { + getOp = OP_GET_UPVALUE; + setOp = OP_SET_UPVALUE; + } else { + arg = identifierConstant(&name); + getOp = OP_GET_GLOBAL; + setOp = OP_SET_GLOBAL; + } + + if (canAssign && match(TOKEN_EQUAL)) { + expression(); + emitBytes(setOp, arg); + } else { + emitBytes(getOp, arg); + } +} + static void classDeclaration() { consume(TOKEN_IDENTIFIER, "Expect class name"); + Token className = parser.previous; uint8_t nameConstant = identifierConstant(&parser.previous); declareVariable(); emitBytes(OP_CLASS, nameConstant); defineVariable(nameConstant); + namedVariable(className, false); consume(TOKEN_LEFT_BRACE, "Expect '{' before class body."); + while (!check(TOKEN_RIGHT_BRACE) && !check(TOKEN_EOF)) { + method(); + } consume(TOKEN_RIGHT_BRACE, "Expect '}' after class body."); + emitByte(OP_POP); } static void markInitialized() { @@ -643,30 +682,6 @@ static void string(bool canAssign) { copyString(parser.previous.start + 1, parser.previous.length - 2))); } -static void namedVariable(Token name, bool canAssign) { - uint8_t getOp, setOp; - int arg = resolveLocal(current, &name); - - if (arg != -1) { - getOp = OP_GET_LOCAL; - setOp = OP_SET_LOCAL; - } else if ((arg = resolveUpvalue(current, &name)) != -1) { - getOp = OP_GET_UPVALUE; - setOp = OP_SET_UPVALUE; - } else { - arg = identifierConstant(&name); - getOp = OP_GET_GLOBAL; - setOp = OP_SET_GLOBAL; - } - - if (canAssign && match(TOKEN_EQUAL)) { - expression(); - emitBytes(setOp, arg); - } else { - emitBytes(getOp, arg); - } -} - static void variable(bool canAssign) { namedVariable(parser.previous, canAssign); } diff --git a/clox/src/debug.c b/clox/src/debug.c index fe96c3d..74be178 100644 --- a/clox/src/debug.c +++ b/clox/src/debug.c @@ -128,6 +128,8 @@ int disassembleInstruction(Chunk *chunk, int offset) { return simpleInstruction("OP_RETURN", offset); case OP_CLASS: return constantInstruction("OP_CLASS", chunk, offset); + case OP_METHOD: + return constantInstruction("OP_METHOD", chunk, offset); default: printf("Unknown opcode %d\n", instruction); return offset + 1; diff --git a/clox/src/memory.c b/clox/src/memory.c index 8c32386..13891e4 100644 --- a/clox/src/memory.c +++ b/clox/src/memory.c @@ -79,6 +79,7 @@ static void blackenObject(Obj *object) { case OBJ_CLASS: { ObjClass *klass = (ObjClass *)object; markObject((Obj *)klass->name); + markTable(&klass->methods); break; } case OBJ_CLOSURE: { @@ -117,6 +118,8 @@ static void freeObject(Obj *object) { switch (object->type) { case OBJ_CLASS: { + ObjClass *klass = (ObjClass *)object; + freeTable(&klass->methods); FREE(ObjClass, object); break; } diff --git a/clox/src/object.c b/clox/src/object.c index a431314..7e0dd6c 100644 --- a/clox/src/object.c +++ b/clox/src/object.c @@ -28,6 +28,7 @@ static Obj *allocateObject(size_t size, ObjType type) { ObjClass *newClass(ObjString *name) { ObjClass *klass = ALLOCATE_OBJ(ObjClass, OBJ_CLASS); klass->name = name; + initTable(&klass->methods); return klass; } diff --git a/clox/src/object.h b/clox/src/object.h index 1cef631..4c115ce 100644 --- a/clox/src/object.h +++ b/clox/src/object.h @@ -78,6 +78,7 @@ typedef struct { typedef struct { Obj obj; ObjString *name; + Table methods; } ObjClass; typedef struct { diff --git a/clox/src/vm.c b/clox/src/vm.c index 1d82dd1..fb359c2 100644 --- a/clox/src/vm.c +++ b/clox/src/vm.c @@ -163,6 +163,13 @@ static void closeUpvalues(Value *last) { } } +static void defineMethod(ObjString *name) { + Value method = peek(0); + ObjClass *klass = AS_CLASS(peek(1)); + tableSet(&klass->methods, name, method); + pop(); +} + static bool isFalsey(Value value) { return IS_NIL(value) || (IS_BOOL(value) && !AS_BOOL(value)); } @@ -422,6 +429,9 @@ static InterpretResult run() { case OP_CLASS: push(OBJ_VAL(newClass(READ_STRING()))); break; + case OP_METHOD: + defineMethod(READ_STRING()); + break; } }