Chapter 28.3

This commit is contained in:
Tom Willemse 2022-08-13 14:52:57 -07:00
parent 389908c499
commit 7871383a40
2 changed files with 31 additions and 5 deletions

View file

@ -51,7 +51,7 @@ typedef struct {
bool isLocal; bool isLocal;
} Upvalue; } Upvalue;
typedef enum { TYPE_FUNCTION, TYPE_SCRIPT } FunctionType; typedef enum { TYPE_FUNCTION, TYPE_METHOD, TYPE_SCRIPT } FunctionType;
typedef struct Compiler { typedef struct Compiler {
struct Compiler *enclosing; struct Compiler *enclosing;
@ -64,10 +64,15 @@ typedef struct Compiler {
int scopeDepth; int scopeDepth;
} Compiler; } Compiler;
typedef struct ClassCompiler {
struct ClassCompiler *enclosing;
} ClassCompiler;
static int resolveUpvalue(Compiler *, Token *); static int resolveUpvalue(Compiler *, Token *);
Parser parser; Parser parser;
Compiler *current = NULL; Compiler *current = NULL;
ClassCompiler *currentClass = NULL;
Chunk *compilingChunk; Chunk *compilingChunk;
static Chunk *currentChunk() { return &current->function->chunk; } 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 *local = &current->locals[current->localCount++];
local->depth = 0; local->depth = 0;
local->isCaptured = false; local->isCaptured = false;
if (type != TYPE_FUNCTION) {
local->name.start = "this";
local->name.length = 4;
} else {
local->name.start = ""; local->name.start = "";
local->name.length = 0; local->name.length = 0;
}
} }
static ObjFunction *endCompiler() { static ObjFunction *endCompiler() {
@ -378,7 +388,7 @@ static void method() {
consume(TOKEN_IDENTIFIER, "Expect method name."); consume(TOKEN_IDENTIFIER, "Expect method name.");
uint8_t constant = identifierConstant(&parser.previous); uint8_t constant = identifierConstant(&parser.previous);
FunctionType type = TYPE_FUNCTION; FunctionType type = TYPE_METHOD;
function(type); function(type);
emitBytes(OP_METHOD, constant); emitBytes(OP_METHOD, constant);
} }
@ -453,6 +463,10 @@ static void classDeclaration() {
emitBytes(OP_CLASS, nameConstant); emitBytes(OP_CLASS, nameConstant);
defineVariable(nameConstant); defineVariable(nameConstant);
ClassCompiler classCompiler;
classCompiler.enclosing = currentClass;
currentClass = &classCompiler;
namedVariable(className, false); namedVariable(className, false);
consume(TOKEN_LEFT_BRACE, "Expect '{' before class body."); consume(TOKEN_LEFT_BRACE, "Expect '{' before class body.");
while (!check(TOKEN_RIGHT_BRACE) && !check(TOKEN_EOF)) { while (!check(TOKEN_RIGHT_BRACE) && !check(TOKEN_EOF)) {
@ -460,6 +474,8 @@ static void classDeclaration() {
} }
consume(TOKEN_RIGHT_BRACE, "Expect '}' after class body."); consume(TOKEN_RIGHT_BRACE, "Expect '}' after class body.");
emitByte(OP_POP); emitByte(OP_POP);
currentClass = currentClass->enclosing;
} }
static void markInitialized() { static void markInitialized() {
@ -686,6 +702,15 @@ static void variable(bool canAssign) {
namedVariable(parser.previous, 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) { static void unary(bool canAssign) {
TokenType operatorType = parser.previous.type; TokenType operatorType = parser.previous.type;
@ -745,7 +770,7 @@ ParseRule rules[] = {
[TOKEN_PRINT] = {NULL, NULL, PREC_NONE}, [TOKEN_PRINT] = {NULL, NULL, PREC_NONE},
[TOKEN_RETURN] = {NULL, NULL, PREC_NONE}, [TOKEN_RETURN] = {NULL, NULL, PREC_NONE},
[TOKEN_SUPER] = {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_TRUE] = {literal, NULL, PREC_NONE},
[TOKEN_VAR] = {NULL, NULL, PREC_NONE}, [TOKEN_VAR] = {NULL, NULL, PREC_NONE},
[TOKEN_WHILE] = {NULL, NULL, PREC_NONE}, [TOKEN_WHILE] = {NULL, NULL, PREC_NONE},

View file

@ -110,6 +110,7 @@ static bool callValue(Value callee, int argCount) {
switch (OBJ_TYPE(callee)) { switch (OBJ_TYPE(callee)) {
case OBJ_BOUND_METHOD: { case OBJ_BOUND_METHOD: {
ObjBoundMethod *bound = AS_BOUND_METHOD(callee); ObjBoundMethod *bound = AS_BOUND_METHOD(callee);
vm.stackTop[-argCount - 1] = bound->receiver;
return call(bound->method, argCount); return call(bound->method, argCount);
} }
case OBJ_CLASS: { case OBJ_CLASS: {