aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Tom Willemse2022-08-13 12:20:00 -0700
committerGravatar Tom Willemse2022-08-13 12:20:00 -0700
commit07f691425c95a53323229accd8a907c5dea7e530 (patch)
treef19d102a75daa1ac1d73208cbd19e5fbe471c300
parent4e77cfa61262a03055aeb273108fd9a49e8dfa4f (diff)
downloadcrafting-interpreters-07f691425c95a53323229accd8a907c5dea7e530.tar.gz
crafting-interpreters-07f691425c95a53323229accd8a907c5dea7e530.zip
Chapter 28.1
-rw-r--r--clox/src/chunk.h1
-rw-r--r--clox/src/compiler.c63
-rw-r--r--clox/src/debug.c2
-rw-r--r--clox/src/memory.c3
-rw-r--r--clox/src/object.c1
-rw-r--r--clox/src/object.h1
-rw-r--r--clox/src/vm.c10
7 files changed, 57 insertions, 24 deletions
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;
}
}