diff --git a/example/hello.wren b/example/hello.wren index e82f6102..79d3cee8 100644 --- a/example/hello.wren +++ b/example/hello.wren @@ -1,6 +1,6 @@ -{ - 123 +var a = { + var b = 234 + 3 + b } -var a = 123 -var b = 345 -a +a.call diff --git a/src/compiler.c b/src/compiler.c index c26bfd1f..2bb2d138 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -110,8 +110,15 @@ static void consume(Compiler* compiler, TokenType expected); static void advance(Parser* parser); // Tokens: + +// Lex the next token in the source file and store it in parser.current. Omits +// newlines that aren't meaningful. static void readNextToken(Parser* parser); + +// Lex the next token and store it in parser.current. Does not do any newline +// filtering. static void readRawToken(Parser* parser); + static void readName(Parser* parser); static void readNumber(Parser* parser); static void readString(Parser* parser); diff --git a/src/main.c b/src/main.c index 5c8b3ebc..54296cc7 100644 --- a/src/main.c +++ b/src/main.c @@ -27,9 +27,14 @@ int main(int argc, const char * argv[]) char* source = readFile(argv[1], &length); VM* vm = newVM(); ObjBlock* block = compile(vm, source, length); - Value value = interpret(vm, block); - printValue(value); - printf("\n"); + + if (block) + { + Value value = interpret(vm, block); + printValue(value); + printf("\n"); + } + freeVM(vm); free(source); diff --git a/src/vm.c b/src/vm.c index b7812826..67b84d83 100644 --- a/src/vm.c +++ b/src/vm.c @@ -4,6 +4,13 @@ #include "vm.h" +#define PRIMITIVE(cls, prim) \ + { \ + int symbol = ensureSymbol(&vm->symbols, #prim, strlen(#prim)); \ + vm->cls##Class->methods[symbol].type = METHOD_PRIMITIVE; \ + vm->cls##Class->methods[symbol].primitive = primitive_##cls##_##prim; \ + } + typedef struct { // Index of the current (really next-to-be-executed) instruction in the @@ -29,17 +36,26 @@ typedef struct static void callBlock(Fiber* fiber, ObjBlock* block, int firstLocal); static void push(Fiber* fiber, Value value); static Value pop(Fiber* fiber); -static Value primitiveNumAbs(Value number); +static Value primitive_num_abs(Value block); VM* newVM() { VM* vm = malloc(sizeof(VM)); initSymbolTable(&vm->symbols); + vm->blockClass = makeClass(); + + // The call method is special: neither a primitive nor a user-defined one. + // This is because it mucks with the fiber itself. + { + int symbol = ensureSymbol(&vm->symbols, "call", strlen("call")); + vm->blockClass->methods[symbol].type = METHOD_CALL; + } + + vm->classClass = makeClass(); + vm->numClass = makeClass(); - int symbol = ensureSymbol(&vm->symbols, "abs", 3); - vm->numClass->methods[symbol].type = METHOD_PRIMITIVE; - vm->numClass->methods[symbol].primitive = primitiveNumAbs; + PRIMITIVE(num, abs); return vm; } @@ -198,7 +214,22 @@ Value interpret(VM* vm, ObjBlock* block) int symbol = frame->block->bytecode[frame->ip++]; // TODO(bob): Support classes for other object types. - ObjClass* classObj = vm->numClass; + ObjClass* classObj; + switch (receiver->type) + { + case OBJ_BLOCK: + classObj = vm->blockClass; + break; + + case OBJ_CLASS: + classObj = vm->classClass; + break; + + case OBJ_NUM: + classObj = vm->numClass; + break; + } + Method* method = &classObj->methods[symbol]; switch (method->type) { @@ -208,6 +239,11 @@ Value interpret(VM* vm, ObjBlock* block) exit(1); break; + case METHOD_CALL: + // TODO(bob): Should pass in correct index for locals. + callBlock(&fiber, (ObjBlock*)receiver, fiber.stackSize); + break; + case METHOD_PRIMITIVE: push(&fiber, method->primitive(receiver)); break; @@ -282,7 +318,7 @@ Value pop(Fiber* fiber) return fiber->stack[--fiber->stackSize]; } -Value primitiveNumAbs(Value number) +Value primitive_num_abs(Value number) { double value = ((ObjNum*)number)->value; if (value < 0) value = -value; diff --git a/src/vm.h b/src/vm.h index fd6cd159..ebbc913e 100644 --- a/src/vm.h +++ b/src/vm.h @@ -46,6 +46,7 @@ typedef Value (*Primitive)(Value receiver); typedef enum { METHOD_NONE, + METHOD_CALL, METHOD_PRIMITIVE, METHOD_BLOCK } MethodType; @@ -105,6 +106,9 @@ typedef struct typedef struct { SymbolTable symbols; + + ObjClass* blockClass; + ObjClass* classClass; ObjClass* numClass; } VM;