aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Tom Willemse2022-08-13 14:52:57 -0700
committerGravatar Tom Willemse2022-08-13 14:52:57 -0700
commit7871383a400f0a37dbd8459755aa9f98e2742f7a (patch)
treee57873baa63fafe19ec45577371d41dacb35a1a0
parent389908c49936cd8fcb3170fadcd217ae9f0f5ff8 (diff)
downloadcrafting-interpreters-7871383a400f0a37dbd8459755aa9f98e2742f7a.tar.gz
crafting-interpreters-7871383a400f0a37dbd8459755aa9f98e2742f7a.zip
Chapter 28.3
-rw-r--r--clox/src/compiler.c35
-rw-r--r--clox/src/vm.c1
2 files changed, 31 insertions, 5 deletions
diff --git a/clox/src/compiler.c b/clox/src/compiler.c
index 31a7937..a773e97 100644
--- a/clox/src/compiler.c
+++ b/clox/src/compiler.c
@@ -51,7 +51,7 @@ typedef struct {
bool isLocal;
} Upvalue;
-typedef enum { TYPE_FUNCTION, TYPE_SCRIPT } FunctionType;
+typedef enum { TYPE_FUNCTION, TYPE_METHOD, TYPE_SCRIPT } FunctionType;
typedef struct Compiler {
struct Compiler *enclosing;
@@ -64,10 +64,15 @@ typedef struct Compiler {
int scopeDepth;
} Compiler;
+typedef struct ClassCompiler {
+ struct ClassCompiler *enclosing;
+} ClassCompiler;
+
static int resolveUpvalue(Compiler *, Token *);
Parser parser;
Compiler *current = NULL;
+ClassCompiler *currentClass = NULL;
Chunk *compilingChunk;
static Chunk *currentChunk() { return &current->function->chunk; }
@@ -200,8 +205,13 @@ static void initCompiler(Compiler *compiler, FunctionType type) {
Local *local = &current->locals[current->localCount++];
local->depth = 0;
local->isCaptured = false;
- local->name.start = "";
- local->name.length = 0;
+ if (type != TYPE_FUNCTION) {
+ local->name.start = "this";
+ local->name.length = 4;
+ } else {
+ local->name.start = "";
+ local->name.length = 0;
+ }
}
static ObjFunction *endCompiler() {
@@ -378,7 +388,7 @@ static void method() {
consume(TOKEN_IDENTIFIER, "Expect method name.");
uint8_t constant = identifierConstant(&parser.previous);
- FunctionType type = TYPE_FUNCTION;
+ FunctionType type = TYPE_METHOD;
function(type);
emitBytes(OP_METHOD, constant);
}
@@ -453,6 +463,10 @@ static void classDeclaration() {
emitBytes(OP_CLASS, nameConstant);
defineVariable(nameConstant);
+ ClassCompiler classCompiler;
+ classCompiler.enclosing = currentClass;
+ currentClass = &classCompiler;
+
namedVariable(className, false);
consume(TOKEN_LEFT_BRACE, "Expect '{' before class body.");
while (!check(TOKEN_RIGHT_BRACE) && !check(TOKEN_EOF)) {
@@ -460,6 +474,8 @@ static void classDeclaration() {
}
consume(TOKEN_RIGHT_BRACE, "Expect '}' after class body.");
emitByte(OP_POP);
+
+ currentClass = currentClass->enclosing;
}
static void markInitialized() {
@@ -686,6 +702,15 @@ static void variable(bool canAssign) {
namedVariable(parser.previous, canAssign);
}
+static void this_(bool canAssign) {
+ if (currentClass == NULL) {
+ error("Can't use 'this' outside of a class.");
+ return;
+ }
+
+ variable(false);
+}
+
static void unary(bool canAssign) {
TokenType operatorType = parser.previous.type;
@@ -745,7 +770,7 @@ ParseRule rules[] = {
[TOKEN_PRINT] = {NULL, NULL, PREC_NONE},
[TOKEN_RETURN] = {NULL, NULL, PREC_NONE},
[TOKEN_SUPER] = {NULL, NULL, PREC_NONE},
- [TOKEN_THIS] = {NULL, NULL, PREC_NONE},
+ [TOKEN_THIS] = {this_, NULL, PREC_NONE},
[TOKEN_TRUE] = {literal, NULL, PREC_NONE},
[TOKEN_VAR] = {NULL, NULL, PREC_NONE},
[TOKEN_WHILE] = {NULL, NULL, PREC_NONE},
diff --git a/clox/src/vm.c b/clox/src/vm.c
index 4b0fe48..6b15a3a 100644
--- a/clox/src/vm.c
+++ b/clox/src/vm.c
@@ -110,6 +110,7 @@ static bool callValue(Value callee, int argCount) {
switch (OBJ_TYPE(callee)) {
case OBJ_BOUND_METHOD: {
ObjBoundMethod *bound = AS_BOUND_METHOD(callee);
+ vm.stackTop[-argCount - 1] = bound->receiver;
return call(bound->method, argCount);
}
case OBJ_CLASS: {