Chapter 28.3
This commit is contained in:
parent
389908c499
commit
7871383a40
2 changed files with 31 additions and 5 deletions
|
@ -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 ¤t->function->chunk; }
|
static Chunk *currentChunk() { return ¤t->function->chunk; }
|
||||||
|
@ -200,8 +205,13 @@ static void initCompiler(Compiler *compiler, FunctionType type) {
|
||||||
Local *local = ¤t->locals[current->localCount++];
|
Local *local = ¤t->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},
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
Loading…
Reference in a new issue