Chapter 28.1
This commit is contained in:
parent
4e77cfa612
commit
07f691425c
7 changed files with 57 additions and 24 deletions
|
@ -37,6 +37,7 @@ typedef enum {
|
|||
OP_CLOSE_UPVALUE,
|
||||
OP_RETURN,
|
||||
OP_CLASS,
|
||||
OP_METHOD,
|
||||
} OpCode;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -374,6 +374,15 @@ static void function(FunctionType type) {
|
|||
}
|
||||
}
|
||||
|
||||
static void method() {
|
||||
consume(TOKEN_IDENTIFIER, "Expect method name.");
|
||||
uint8_t constant = identifierConstant(&parser.previous);
|
||||
|
||||
FunctionType type = TYPE_FUNCTION;
|
||||
function(type);
|
||||
emitBytes(OP_METHOD, constant);
|
||||
}
|
||||
|
||||
static bool identifiersEqual(Token *a, Token *b) {
|
||||
if (a->length != b->length)
|
||||
return false;
|
||||
|
@ -411,16 +420,46 @@ static void declareVariable() {
|
|||
addLocal(*name);
|
||||
}
|
||||
|
||||
static void namedVariable(Token name, bool canAssign) {
|
||||
uint8_t getOp, setOp;
|
||||
int arg = resolveLocal(current, &name);
|
||||
|
||||
if (arg != -1) {
|
||||
getOp = OP_GET_LOCAL;
|
||||
setOp = OP_SET_LOCAL;
|
||||
} else if ((arg = resolveUpvalue(current, &name)) != -1) {
|
||||
getOp = OP_GET_UPVALUE;
|
||||
setOp = OP_SET_UPVALUE;
|
||||
} else {
|
||||
arg = identifierConstant(&name);
|
||||
getOp = OP_GET_GLOBAL;
|
||||
setOp = OP_SET_GLOBAL;
|
||||
}
|
||||
|
||||
if (canAssign && match(TOKEN_EQUAL)) {
|
||||
expression();
|
||||
emitBytes(setOp, arg);
|
||||
} else {
|
||||
emitBytes(getOp, arg);
|
||||
}
|
||||
}
|
||||
|
||||
static void classDeclaration() {
|
||||
consume(TOKEN_IDENTIFIER, "Expect class name");
|
||||
Token className = parser.previous;
|
||||
uint8_t nameConstant = identifierConstant(&parser.previous);
|
||||
declareVariable();
|
||||
|
||||
emitBytes(OP_CLASS, nameConstant);
|
||||
defineVariable(nameConstant);
|
||||
|
||||
namedVariable(className, false);
|
||||
consume(TOKEN_LEFT_BRACE, "Expect '{' before class body.");
|
||||
while (!check(TOKEN_RIGHT_BRACE) && !check(TOKEN_EOF)) {
|
||||
method();
|
||||
}
|
||||
consume(TOKEN_RIGHT_BRACE, "Expect '}' after class body.");
|
||||
emitByte(OP_POP);
|
||||
}
|
||||
|
||||
static void markInitialized() {
|
||||
|
@ -643,30 +682,6 @@ static void string(bool canAssign) {
|
|||
copyString(parser.previous.start + 1, parser.previous.length - 2)));
|
||||
}
|
||||
|
||||
static void namedVariable(Token name, bool canAssign) {
|
||||
uint8_t getOp, setOp;
|
||||
int arg = resolveLocal(current, &name);
|
||||
|
||||
if (arg != -1) {
|
||||
getOp = OP_GET_LOCAL;
|
||||
setOp = OP_SET_LOCAL;
|
||||
} else if ((arg = resolveUpvalue(current, &name)) != -1) {
|
||||
getOp = OP_GET_UPVALUE;
|
||||
setOp = OP_SET_UPVALUE;
|
||||
} else {
|
||||
arg = identifierConstant(&name);
|
||||
getOp = OP_GET_GLOBAL;
|
||||
setOp = OP_SET_GLOBAL;
|
||||
}
|
||||
|
||||
if (canAssign && match(TOKEN_EQUAL)) {
|
||||
expression();
|
||||
emitBytes(setOp, arg);
|
||||
} else {
|
||||
emitBytes(getOp, arg);
|
||||
}
|
||||
}
|
||||
|
||||
static void variable(bool canAssign) {
|
||||
namedVariable(parser.previous, canAssign);
|
||||
}
|
||||
|
|
|
@ -128,6 +128,8 @@ int disassembleInstruction(Chunk *chunk, int offset) {
|
|||
return simpleInstruction("OP_RETURN", offset);
|
||||
case OP_CLASS:
|
||||
return constantInstruction("OP_CLASS", chunk, offset);
|
||||
case OP_METHOD:
|
||||
return constantInstruction("OP_METHOD", chunk, offset);
|
||||
default:
|
||||
printf("Unknown opcode %d\n", instruction);
|
||||
return offset + 1;
|
||||
|
|
|
@ -79,6 +79,7 @@ static void blackenObject(Obj *object) {
|
|||
case OBJ_CLASS: {
|
||||
ObjClass *klass = (ObjClass *)object;
|
||||
markObject((Obj *)klass->name);
|
||||
markTable(&klass->methods);
|
||||
break;
|
||||
}
|
||||
case OBJ_CLOSURE: {
|
||||
|
@ -117,6 +118,8 @@ static void freeObject(Obj *object) {
|
|||
|
||||
switch (object->type) {
|
||||
case OBJ_CLASS: {
|
||||
ObjClass *klass = (ObjClass *)object;
|
||||
freeTable(&klass->methods);
|
||||
FREE(ObjClass, object);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ static Obj *allocateObject(size_t size, ObjType type) {
|
|||
ObjClass *newClass(ObjString *name) {
|
||||
ObjClass *klass = ALLOCATE_OBJ(ObjClass, OBJ_CLASS);
|
||||
klass->name = name;
|
||||
initTable(&klass->methods);
|
||||
return klass;
|
||||
}
|
||||
|
||||
|
|
|
@ -78,6 +78,7 @@ typedef struct {
|
|||
typedef struct {
|
||||
Obj obj;
|
||||
ObjString *name;
|
||||
Table methods;
|
||||
} ObjClass;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -163,6 +163,13 @@ static void closeUpvalues(Value *last) {
|
|||
}
|
||||
}
|
||||
|
||||
static void defineMethod(ObjString *name) {
|
||||
Value method = peek(0);
|
||||
ObjClass *klass = AS_CLASS(peek(1));
|
||||
tableSet(&klass->methods, name, method);
|
||||
pop();
|
||||
}
|
||||
|
||||
static bool isFalsey(Value value) {
|
||||
return IS_NIL(value) || (IS_BOOL(value) && !AS_BOOL(value));
|
||||
}
|
||||
|
@ -422,6 +429,9 @@ static InterpretResult run() {
|
|||
case OP_CLASS:
|
||||
push(OBJ_VAL(newClass(READ_STRING())));
|
||||
break;
|
||||
case OP_METHOD:
|
||||
defineMethod(READ_STRING());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue