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;
|
||||
} 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 ¤t->function->chunk; }
|
||||
|
@ -200,9 +205,14 @@ static void initCompiler(Compiler *compiler, FunctionType type) {
|
|||
Local *local = ¤t->locals[current->localCount++];
|
||||
local->depth = 0;
|
||||
local->isCaptured = false;
|
||||
if (type != TYPE_FUNCTION) {
|
||||
local->name.start = "this";
|
||||
local->name.length = 4;
|
||||
} else {
|
||||
local->name.start = "";
|
||||
local->name.length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static ObjFunction *endCompiler() {
|
||||
emitReturn();
|
||||
|
@ -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},
|
||||
|
|
|
@ -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: {
|
||||
|
|
Loading…
Reference in a new issue