diff --git a/.gitignore b/.gitignore index fa18aa19..921d561e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Intermediate files directory. build/ +build_xcode/ # Built applications. wren diff --git a/src/wren_compiler.c b/src/wren_compiler.c index b2b95142..f83735d1 100644 --- a/src/wren_compiler.c +++ b/src/wren_compiler.c @@ -2047,8 +2047,6 @@ static int getNumArguments(const uint8_t* bytecode, const Value* constants, case CODE_CLOSE_UPVALUE: case CODE_RETURN: case CODE_NEW: - case CODE_CLASS: - case CODE_SUBCLASS: case CODE_END: return 0; @@ -2063,6 +2061,7 @@ static int getNumArguments(const uint8_t* bytecode, const Value* constants, case CODE_LOAD_FIELD: case CODE_STORE_FIELD: case CODE_LIST: + case CODE_CLASS: return 1; case CODE_CONSTANT: @@ -2422,14 +2421,15 @@ static void classDefinition(Compiler* compiler) if (match(compiler, TOKEN_IS)) { parsePrecedence(compiler, false, PREC_CALL); - emit(compiler, CODE_SUBCLASS); } else { // Create the empty class. - emit(compiler, CODE_CLASS); + emit(compiler, CODE_NULL); } + emit(compiler, CODE_CLASS); + // Store a placeholder for the number of fields argument. We don't know // the value until we've compiled all the methods to see which fields are // used. diff --git a/src/wren_debug.c b/src/wren_debug.c index 6249adfd..d157beaa 100644 --- a/src/wren_debug.c +++ b/src/wren_debug.c @@ -26,8 +26,12 @@ void wrenDebugPrintStackTrace(WrenVM* vm, ObjFiber* fiber) } } -static void printLine(ObjFn* fn, int i, int* lastLine) +static int debugPrintInstruction(WrenVM* vm, ObjFn* fn, int i, int* lastLine) { + int start = i; + uint8_t* bytecode = fn->bytecode; + Code code = bytecode[i]; + int line = fn->debug->sourceLines[i]; if (lastLine == NULL || *lastLine != line) { @@ -38,32 +42,24 @@ static void printLine(ObjFn* fn, int i, int* lastLine) { printf(" "); } -} -static int debugPrintInstruction(WrenVM* vm, ObjFn* fn, int i, int* lastLine) -{ - int start = i; - uint8_t* bytecode = fn->bytecode; - Code code = bytecode[i++]; + printf(" %04d ", i++); - printLine(fn, i, lastLine); - printf(" %04d ", i); + #define READ_BYTE() (bytecode[i++]) + #define READ_SHORT() (i += 2, (bytecode[i - 2] << 8) | bytecode[i - 1]) - #define PRINT_ARG \ - printLine(fn, i, lastLine); printf(" %04d ", ++i); printf + #define BYTE_INSTRUCTION(name) \ + printf("%-16s %5d\n", name, READ_BYTE()); \ + break; \ - // TODO: Come up with a cleaner way of displaying 16-bit args. - switch (code) { case CODE_CONSTANT: { - int constant = (bytecode[i] << 8) | bytecode[i + 1]; - printf("CONSTANT '"); + int constant = READ_SHORT(); + printf("%-16s %5d '", "CONSTANT", constant); wrenPrintValue(fn->constants[constant]); printf("'\n"); - PRINT_ARG("constant %d\n", constant); - PRINT_ARG("\n"); break; } @@ -71,85 +67,31 @@ static int debugPrintInstruction(WrenVM* vm, ObjFn* fn, int i, int* lastLine) case CODE_FALSE: printf("FALSE\n"); break; case CODE_TRUE: printf("TRUE\n"); break; - case CODE_LOAD_LOCAL: - { - int local = bytecode[i]; - printf("LOAD_LOCAL %d\n", local); - PRINT_ARG("local %d\n", local); - break; - } - - case CODE_STORE_LOCAL: - { - int local = bytecode[i]; - printf("STORE_LOCAL %d\n", local); - PRINT_ARG("local %d\n", local); - break; - } - - case CODE_LOAD_UPVALUE: - { - int upvalue = bytecode[i]; - printf("LOAD_UPVALUE %d\n", upvalue); - PRINT_ARG("upvalue %d\n", upvalue); - break; - } - - case CODE_STORE_UPVALUE: - { - int upvalue = bytecode[i]; - printf("STORE_UPVALUE %d\n", upvalue); - PRINT_ARG("upvalue %d\n", upvalue); - break; - } + case CODE_LOAD_LOCAL: BYTE_INSTRUCTION("LOAD_LOCAL"); + case CODE_STORE_LOCAL: BYTE_INSTRUCTION("STORE_LOCAL"); + case CODE_LOAD_UPVALUE: BYTE_INSTRUCTION("LOAD_UPVALUE"); + case CODE_STORE_UPVALUE: BYTE_INSTRUCTION("STORE_UPVALUE"); case CODE_LOAD_GLOBAL: { - int global = bytecode[i]; - printf("LOAD_GLOBAL \"%s\"\n", vm->globalSymbols.names.data[global]); - PRINT_ARG("global %d\n", global); + int global = READ_BYTE(); + printf("%-16s %5d '%s'\n", "LOAD_GLOBAL", global, + vm->globalSymbols.names.data[global]); break; } case CODE_STORE_GLOBAL: { - int global = bytecode[i]; - printf("STORE_GLOBAL \"%s\"\n", vm->globalSymbols.names.data[global]); - PRINT_ARG("global %d\n", global); + int global = READ_BYTE(); + printf("%-16s %5d '%s'\n", "STORE_GLOBAL", global, + vm->globalSymbols.names.data[global]); break; } - case CODE_LOAD_FIELD_THIS: - { - int field = bytecode[i]; - printf("LOAD_FIELD_THIS %d\n", field); - PRINT_ARG("field %d\n", field); - break; - } - - case CODE_STORE_FIELD_THIS: - { - int field = bytecode[i]; - printf("STORE_FIELD_THIS %d\n", field); - PRINT_ARG("field %d\n", field); - break; - } - - case CODE_LOAD_FIELD: - { - int field = bytecode[i]; - printf("LOAD_FIELD %d\n", field); - PRINT_ARG("field %d\n", field); - break; - } - - case CODE_STORE_FIELD: - { - int field = bytecode[i]; - printf("STORE_FIELD %d\n", field); - PRINT_ARG("field %d\n", field); - break; - } + case CODE_LOAD_FIELD_THIS: BYTE_INSTRUCTION("LOAD_FIELD_THIS"); + case CODE_STORE_FIELD_THIS: BYTE_INSTRUCTION("STORE_FIELD_THIS"); + case CODE_LOAD_FIELD: BYTE_INSTRUCTION("LOAD_FIELD"); + case CODE_STORE_FIELD: BYTE_INSTRUCTION("STORE_FIELD"); case CODE_POP: printf("POP\n"); break; @@ -172,10 +114,9 @@ static int debugPrintInstruction(WrenVM* vm, ObjFn* fn, int i, int* lastLine) case CODE_CALL_16: { int numArgs = bytecode[i - 1] - CODE_CALL_0; - int symbol = (bytecode[i] << 8) | bytecode[i + 1]; - printf("CALL_%d \"%s\"\n", numArgs, vm->methods.names.data[symbol]); - PRINT_ARG("symbol %d\n", symbol); - PRINT_ARG("\n"); + int symbol = READ_SHORT(); + printf("CALL_%-11d %5d '%s'\n", numArgs, symbol, + vm->methods.names.data[symbol]); break; } @@ -198,50 +139,44 @@ static int debugPrintInstruction(WrenVM* vm, ObjFn* fn, int i, int* lastLine) case CODE_SUPER_16: { int numArgs = bytecode[i - 1] - CODE_SUPER_0; - int symbol = (bytecode[i] << 8) | bytecode[i + 1]; - printf("SUPER_%d \"%s\"\n", numArgs, vm->methods.names.data[symbol]); - PRINT_ARG("symbol %d\n", symbol); - PRINT_ARG("\n"); + int symbol = READ_SHORT(); + printf("SUPER_%-10d %5d '%s'\n", numArgs, symbol, + vm->methods.names.data[symbol]); break; } case CODE_JUMP: { - int offset = bytecode[i]; - printf("JUMP %d\n", offset); - PRINT_ARG("offset %d\n", offset); + int offset = READ_SHORT(); + printf("%-16s %5d to %d\n", "JUMP", offset, i + offset); break; } case CODE_LOOP: { - int offset = bytecode[i]; - printf("LOOP %d\n", offset); - PRINT_ARG("offset -%d\n", offset); + int offset = READ_SHORT(); + printf("%-16s %5d to %d\n", "LOOP", offset, i - offset); break; } case CODE_JUMP_IF: { - int offset = bytecode[i]; - printf("JUMP_IF %d\n", offset); - PRINT_ARG("offset %d\n", offset); + int offset = READ_SHORT(); + printf("%-16s %5d to %d\n", "JUMP_IF", offset, i + offset); break; } case CODE_AND: { - int offset = bytecode[i]; - printf("AND %d\n", offset); - PRINT_ARG("offset %d\n", offset); + int offset = READ_SHORT(); + printf("%-16s %5d to %d\n", "AND", offset, i + offset); break; } case CODE_OR: { - int offset = bytecode[i]; - printf("OR %d\n", offset); - PRINT_ARG("offset %d\n", offset); + int offset = READ_SHORT(); + printf("%-16s %5d to %d\n", "OR", offset, i + offset); break; } @@ -252,62 +187,49 @@ static int debugPrintInstruction(WrenVM* vm, ObjFn* fn, int i, int* lastLine) case CODE_LIST: { - int count = bytecode[i]; - printf("LIST\n"); - PRINT_ARG("count %d\n", count); + int length = READ_BYTE(); + printf("%-16s %5d length\n", "LIST", length); break; } case CODE_CLOSURE: { - int constant = (bytecode[i] << 8) | bytecode[i + 1]; - printf("CLOSURE "); + int constant = READ_SHORT(); + printf("%-16s %5d ", "CLOSURE", constant); wrenPrintValue(fn->constants[constant]); - printf("\n"); - PRINT_ARG("constant %d\n", constant); - PRINT_ARG("\n"); + printf(" "); ObjFn* loadedFn = AS_FN(fn->constants[constant]); for (int j = 0; j < loadedFn->numUpvalues; j++) { - int isLocal = bytecode[i]; - PRINT_ARG("upvalue %d isLocal %d\n", j, isLocal); - int index = bytecode[i]; - PRINT_ARG("upvalue %d index %d\n", j, index); + int isLocal = READ_BYTE(); + int index = READ_BYTE(); + if (j > 0) printf(", "); + printf("%s %d", isLocal ? "local" : "upvalue", index); } + printf("\n"); break; } case CODE_CLASS: { - int numFields = bytecode[i]; - printf("CLASS\n"); - PRINT_ARG("num fields %d\n", numFields); - break; - } - - case CODE_SUBCLASS: - { - int numFields = bytecode[i]; - printf("SUBCLASS\n"); - PRINT_ARG("num fields %d\n", numFields); + int numFields = READ_BYTE(); + printf("%-16s %5d fields\n", "CLASS", numFields); break; } case CODE_METHOD_INSTANCE: { - int symbol = (bytecode[i] << 8) | bytecode[i + 1]; - printf("METHOD_INSTANCE \"%s\"\n", vm->methods.names.data[symbol]); - PRINT_ARG("symbol %d\n", symbol); - PRINT_ARG("\n"); + int symbol = READ_SHORT(); + printf("%-16s %5d '%s'\n", "METHOD_INSTANCE", symbol, + vm->methods.names.data[symbol]); break; } case CODE_METHOD_STATIC: { - int symbol = (bytecode[i] << 8) | bytecode[i + 1]; - printf("METHOD_STATIC \"%s\"\n", vm->methods.names.data[symbol]); - PRINT_ARG("symbol %d\n", symbol); - PRINT_ARG("\n"); + int symbol = READ_SHORT(); + printf("%-16s %5d '%s'\n", "METHOD_STATIC", symbol, + vm->methods.names.data[symbol]); break; } diff --git a/src/wren_vm.c b/src/wren_vm.c index 3a11c23f..2f48b78d 100644 --- a/src/wren_vm.c +++ b/src/wren_vm.c @@ -476,7 +476,6 @@ static bool runInterpreter(WrenVM* vm) &&code_LIST, &&code_CLOSURE, &&code_CLASS, - &&code_SUBCLASS, &&code_METHOD_INSTANCE, &&code_METHOD_STATIC, &&code_END @@ -971,22 +970,20 @@ static bool runInterpreter(WrenVM* vm) } CASE_CODE(CLASS): - CASE_CODE(SUBCLASS): { - bool isSubclass = instruction == CODE_SUBCLASS; int numFields = READ_BYTE(); ObjClass* superclass; - if (isSubclass) - { - // TODO: Handle the superclass not being a class object! - superclass = AS_CLASS(PEEK()); - } - else + if (IS_NULL(PEEK())) { // Implicit Object superclass. superclass = vm->objectClass; } + else + { + // TODO: Handle the superclass not being a class object! + superclass = AS_CLASS(PEEK()); + } ObjClass* classObj = wrenNewClass(vm, superclass, numFields); @@ -1001,7 +998,7 @@ static bool runInterpreter(WrenVM* vm) // Don't pop the superclass off the stack until the subclass is done // being created, to make sure it doesn't get collected. - if (isSubclass) POP(); + POP(); PUSH(OBJ_VAL(classObj)); DISPATCH(); diff --git a/src/wren_vm.h b/src/wren_vm.h index faa65b38..ea7e9f83 100644 --- a/src/wren_vm.h +++ b/src/wren_vm.h @@ -151,9 +151,6 @@ typedef enum // Define a new empty class and push it. CODE_CLASS, - // Pop a superclass off the stack, then push a new class that extends it. - CODE_SUBCLASS, - // Define a method for symbol [arg]. The class receiving the method is popped // off the stack, then the function defining the body is popped. CODE_METHOD_INSTANCE, @@ -162,7 +159,7 @@ typedef enum // the method is popped off the stack, then the function defining the body is // popped. CODE_METHOD_STATIC, - + // This pseudo-instruction indicates the end of the bytecode. It should // always be preceded by a `CODE_RETURN`, so is never actually executed. CODE_END