Chapter 28.5

This commit is contained in:
Tom Willemse 2022-08-14 19:56:32 -07:00
parent e91006b59a
commit 62858b60e4
4 changed files with 52 additions and 0 deletions

View file

@ -33,6 +33,7 @@ typedef enum {
OP_JUMP_IF_FALSE,
OP_LOOP,
OP_CALL,
OP_INVOKE,
OP_CLOSURE,
OP_CLOSE_UPVALUE,
OP_RETURN,

View file

@ -335,6 +335,10 @@ static void dot(bool canAssign) {
if (canAssign && match(TOKEN_EQUAL)) {
expression();
emitBytes(OP_SET_PROPERTY, name);
} else if (match(TOKEN_LEFT_PAREN)) {
uint8_t argCount = argumentList();
emitBytes(OP_INVOKE, name);
emitByte(argCount);
} else {
emitBytes(OP_GET_PROPERTY, name);
}

View file

@ -20,6 +20,15 @@ static int constantInstruction(const char *name, Chunk *chunk, int offset) {
return offset + 2;
}
static int invokeInstruction(const char *name, Chunk *chunk, int offset) {
uint8_t constant = chunk->code[offset + 1];
uint8_t argCount = chunk->code[offset + 2];
printf("%-16s (%d args) %4d '", name, argCount, constant);
printValue(chunk->constants.values[constant]);
printf("'\n'");
return offset + 3;
}
static int simpleInstruction(const char *name, int offset) {
printf("%s\n", name);
return offset + 1;
@ -105,6 +114,8 @@ int disassembleInstruction(Chunk *chunk, int offset) {
return jumpInstruction("OP_LOOP", -1, chunk, offset);
case OP_CALL:
return byteInstruction("OP_CALL", chunk, offset);
case OP_INVOKE:
return invokeInstruction("OP_INVOKE", chunk, offset);
case OP_CLOSURE: {
offset++;
uint8_t constant = chunk->code[offset++];

View file

@ -146,6 +146,33 @@ static bool callValue(Value callee, int argCount) {
return false;
}
static bool invokeFromClass(ObjClass *klass, ObjString *name, int argCount) {
Value method;
if (!tableGet(&klass->methods, name, &method)) {
runtimeError("Undefined property '%s'.", name->chars);
return false;
}
return call(AS_CLOSURE(method), argCount);
}
static bool invoke(ObjString *name, int argCount) {
Value receiver = peek(argCount);
if (!IS_INSTANCE(receiver)) {
runtimeError("Only instances have methods.");
return false;
}
ObjInstance *instance = AS_INSTANCE(receiver);
Value value;
if (tableGet(&instance->fields, name, &value)) {
vm.stackTop[-argCount - 1] = value;
return callValue(value, argCount);
}
return invokeFromClass(instance->klass, name, argCount);
}
static bool bindMethod(ObjClass *klass, ObjString *name) {
Value method;
if (!tableGet(&klass->methods, name, &method)) {
@ -424,6 +451,15 @@ static InterpretResult run() {
frame = &vm.frames[vm.frameCount - 1];
break;
}
case OP_INVOKE: {
ObjString *method = READ_STRING();
int argCount = READ_BYTE();
if (!invoke(method, argCount)) {
return INTERPRET_RUNTIME_ERROR;
}
frame = &vm.frames[vm.frameCount - 1];
break;
}
case OP_CLOSURE: {
ObjFunction *function = AS_FUNCTION(READ_CONSTANT());
ObjClosure *closure = newClosure(function);