Chapter 28.1

This commit is contained in:
Tom Willemse 2022-08-13 12:20:00 -07:00
parent 4e77cfa612
commit 07f691425c
7 changed files with 57 additions and 24 deletions

View file

@ -37,6 +37,7 @@ typedef enum {
OP_CLOSE_UPVALUE, OP_CLOSE_UPVALUE,
OP_RETURN, OP_RETURN,
OP_CLASS, OP_CLASS,
OP_METHOD,
} OpCode; } OpCode;
typedef struct { typedef struct {

View file

@ -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) { static bool identifiersEqual(Token *a, Token *b) {
if (a->length != b->length) if (a->length != b->length)
return false; return false;
@ -411,16 +420,46 @@ static void declareVariable() {
addLocal(*name); 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() { static void classDeclaration() {
consume(TOKEN_IDENTIFIER, "Expect class name"); consume(TOKEN_IDENTIFIER, "Expect class name");
Token className = parser.previous;
uint8_t nameConstant = identifierConstant(&parser.previous); uint8_t nameConstant = identifierConstant(&parser.previous);
declareVariable(); declareVariable();
emitBytes(OP_CLASS, nameConstant); emitBytes(OP_CLASS, nameConstant);
defineVariable(nameConstant); defineVariable(nameConstant);
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)) {
method();
}
consume(TOKEN_RIGHT_BRACE, "Expect '}' after class body."); consume(TOKEN_RIGHT_BRACE, "Expect '}' after class body.");
emitByte(OP_POP);
} }
static void markInitialized() { static void markInitialized() {
@ -643,30 +682,6 @@ static void string(bool canAssign) {
copyString(parser.previous.start + 1, parser.previous.length - 2))); 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) { static void variable(bool canAssign) {
namedVariable(parser.previous, canAssign); namedVariable(parser.previous, canAssign);
} }

View file

@ -128,6 +128,8 @@ int disassembleInstruction(Chunk *chunk, int offset) {
return simpleInstruction("OP_RETURN", offset); return simpleInstruction("OP_RETURN", offset);
case OP_CLASS: case OP_CLASS:
return constantInstruction("OP_CLASS", chunk, offset); return constantInstruction("OP_CLASS", chunk, offset);
case OP_METHOD:
return constantInstruction("OP_METHOD", chunk, offset);
default: default:
printf("Unknown opcode %d\n", instruction); printf("Unknown opcode %d\n", instruction);
return offset + 1; return offset + 1;

View file

@ -79,6 +79,7 @@ static void blackenObject(Obj *object) {
case OBJ_CLASS: { case OBJ_CLASS: {
ObjClass *klass = (ObjClass *)object; ObjClass *klass = (ObjClass *)object;
markObject((Obj *)klass->name); markObject((Obj *)klass->name);
markTable(&klass->methods);
break; break;
} }
case OBJ_CLOSURE: { case OBJ_CLOSURE: {
@ -117,6 +118,8 @@ static void freeObject(Obj *object) {
switch (object->type) { switch (object->type) {
case OBJ_CLASS: { case OBJ_CLASS: {
ObjClass *klass = (ObjClass *)object;
freeTable(&klass->methods);
FREE(ObjClass, object); FREE(ObjClass, object);
break; break;
} }

View file

@ -28,6 +28,7 @@ static Obj *allocateObject(size_t size, ObjType type) {
ObjClass *newClass(ObjString *name) { ObjClass *newClass(ObjString *name) {
ObjClass *klass = ALLOCATE_OBJ(ObjClass, OBJ_CLASS); ObjClass *klass = ALLOCATE_OBJ(ObjClass, OBJ_CLASS);
klass->name = name; klass->name = name;
initTable(&klass->methods);
return klass; return klass;
} }

View file

@ -78,6 +78,7 @@ typedef struct {
typedef struct { typedef struct {
Obj obj; Obj obj;
ObjString *name; ObjString *name;
Table methods;
} ObjClass; } ObjClass;
typedef struct { typedef struct {

View file

@ -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) { static bool isFalsey(Value value) {
return IS_NIL(value) || (IS_BOOL(value) && !AS_BOOL(value)); return IS_NIL(value) || (IS_BOOL(value) && !AS_BOOL(value));
} }
@ -422,6 +429,9 @@ static InterpretResult run() {
case OP_CLASS: case OP_CLASS:
push(OBJ_VAL(newClass(READ_STRING()))); push(OBJ_VAL(newClass(READ_STRING())));
break; break;
case OP_METHOD:
defineMethod(READ_STRING());
break;
} }
} }