Chapter 27.2
This commit is contained in:
parent
63527558a7
commit
a819a85209
4 changed files with 58 additions and 38 deletions
|
@ -34,6 +34,7 @@ typedef enum {
|
||||||
OP_CLOSURE,
|
OP_CLOSURE,
|
||||||
OP_CLOSE_UPVALUE,
|
OP_CLOSE_UPVALUE,
|
||||||
OP_RETURN,
|
OP_RETURN,
|
||||||
|
OP_CLASS,
|
||||||
} OpCode;
|
} OpCode;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -362,6 +362,55 @@ static void function(FunctionType type) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool identifiersEqual(Token *a, Token *b) {
|
||||||
|
if (a->length != b->length)
|
||||||
|
return false;
|
||||||
|
return memcmp(a->start, b->start, a->length) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void addLocal(Token name) {
|
||||||
|
if (current->localCount == UINT8_COUNT) {
|
||||||
|
error("Too many local variables in function.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Local *local = ¤t->locals[current->localCount++];
|
||||||
|
local->name = name;
|
||||||
|
local->depth = -1;
|
||||||
|
local->isCaptured = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void declareVariable() {
|
||||||
|
if (current->scopeDepth == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Token *name = &parser.previous;
|
||||||
|
for (int i = current->localCount - 1; i >= 0; i--) {
|
||||||
|
Local *local = ¤t->locals[i];
|
||||||
|
if (local->depth != -1 && local->depth < current->scopeDepth) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (identifiersEqual(name, &local->name)) {
|
||||||
|
error("Already a variable with this name in this scope.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addLocal(*name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void classDeclaration() {
|
||||||
|
consume(TOKEN_IDENTIFIER, "Expect class name");
|
||||||
|
uint8_t nameConstant = identifierConstant(&parser.previous);
|
||||||
|
declareVariable();
|
||||||
|
|
||||||
|
emitBytes(OP_CLASS, nameConstant);
|
||||||
|
defineVariable(nameConstant);
|
||||||
|
|
||||||
|
consume(TOKEN_LEFT_BRACE, "Expect '{' before class body.");
|
||||||
|
consume(TOKEN_RIGHT_BRACE, "Expect '}' after class body.");
|
||||||
|
}
|
||||||
|
|
||||||
static void markInitialized() {
|
static void markInitialized() {
|
||||||
if (current->scopeDepth == 0)
|
if (current->scopeDepth == 0)
|
||||||
return;
|
return;
|
||||||
|
@ -518,7 +567,9 @@ static void synchronize() {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void declaration() {
|
static void declaration() {
|
||||||
if (match(TOKEN_FUN)) {
|
if (match(TOKEN_CLASS)) {
|
||||||
|
classDeclaration();
|
||||||
|
} else if (match(TOKEN_FUN)) {
|
||||||
funDeclaration();
|
funDeclaration();
|
||||||
} else if (match(TOKEN_VAR)) {
|
} else if (match(TOKEN_VAR)) {
|
||||||
varDeclaration();
|
varDeclaration();
|
||||||
|
@ -701,12 +752,6 @@ static uint8_t identifierConstant(Token *name) {
|
||||||
return makeConstant(OBJ_VAL(copyString(name->start, name->length)));
|
return makeConstant(OBJ_VAL(copyString(name->start, name->length)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool identifiersEqual(Token *a, Token *b) {
|
|
||||||
if (a->length != b->length)
|
|
||||||
return false;
|
|
||||||
return memcmp(a->start, b->start, a->length) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int resolveLocal(Compiler *compiler, Token *name) {
|
static int resolveLocal(Compiler *compiler, Token *name) {
|
||||||
for (int i = compiler->localCount - 1; i >= 0; i--) {
|
for (int i = compiler->localCount - 1; i >= 0; i--) {
|
||||||
Local *local = &compiler->locals[i];
|
Local *local = &compiler->locals[i];
|
||||||
|
@ -759,37 +804,6 @@ static int resolveUpvalue(Compiler *compiler, Token *name) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addLocal(Token name) {
|
|
||||||
if (current->localCount == UINT8_COUNT) {
|
|
||||||
error("Too many local variables in function.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Local *local = ¤t->locals[current->localCount++];
|
|
||||||
local->name = name;
|
|
||||||
local->depth = -1;
|
|
||||||
local->isCaptured = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void declareVariable() {
|
|
||||||
if (current->scopeDepth == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Token *name = &parser.previous;
|
|
||||||
for (int i = current->localCount - 1; i >= 0; i--) {
|
|
||||||
Local *local = ¤t->locals[i];
|
|
||||||
if (local->depth != -1 && local->depth < current->scopeDepth) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (identifiersEqual(name, &local->name)) {
|
|
||||||
error("Already a variable with this name in this scope.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
addLocal(*name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t parseVariable(const char *errorMessage) {
|
static uint8_t parseVariable(const char *errorMessage) {
|
||||||
consume(TOKEN_IDENTIFIER, errorMessage);
|
consume(TOKEN_IDENTIFIER, errorMessage);
|
||||||
|
|
||||||
|
|
|
@ -122,6 +122,8 @@ int disassembleInstruction(Chunk *chunk, int offset) {
|
||||||
return simpleInstruction("OP_CLOSE_UPVALUE", offset);
|
return simpleInstruction("OP_CLOSE_UPVALUE", offset);
|
||||||
case OP_RETURN:
|
case OP_RETURN:
|
||||||
return simpleInstruction("OP_RETURN", offset);
|
return simpleInstruction("OP_RETURN", offset);
|
||||||
|
case OP_CLASS:
|
||||||
|
return constantInstruction("OP_CLASS", chunk, offset);
|
||||||
default:
|
default:
|
||||||
printf("Unknown opcode %d\n", instruction);
|
printf("Unknown opcode %d\n", instruction);
|
||||||
return offset + 1;
|
return offset + 1;
|
||||||
|
|
|
@ -384,6 +384,9 @@ static InterpretResult run() {
|
||||||
frame = &vm.frames[vm.frameCount - 1];
|
frame = &vm.frames[vm.frameCount - 1];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case OP_CLASS:
|
||||||
|
push(OBJ_VAL(newClass(READ_STRING())));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue