From b9baf46e9a7ecd8375f9bece05c113b76c230d2e Mon Sep 17 00:00:00 2001 From: Bob Nystrom Date: Sat, 26 Oct 2013 16:01:44 -0700 Subject: [PATCH] Argument lists. --- example/hello.wren | 2 +- src/compiler.c | 19 +++++++++++++-- src/vm.c | 61 ++++++++++++++++++++++++++++++++-------------- src/vm.h | 38 ++++++++++++++++++----------- 4 files changed, 85 insertions(+), 35 deletions(-) diff --git a/example/hello.wren b/example/hello.wren index 76116364..5db92305 100644 --- a/example/hello.wren +++ b/example/hello.wren @@ -5,4 +5,4 @@ class Foo { // line comment } var a = Foo.new a.bar -"a string" +"something".contains("meth") diff --git a/src/compiler.c b/src/compiler.c index 6a072a42..908fc3b7 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -275,13 +275,28 @@ void call(Compiler* compiler) { primary(compiler); - if (match(compiler, TOKEN_DOT)) + while (match(compiler, TOKEN_DOT)) { consume(compiler, TOKEN_NAME); int symbol = internSymbol(compiler); + // Parse the argument list, if any. + // TODO(bob): Arg list should mangle method name. + int numArgs = 0; + if (match(compiler, TOKEN_LEFT_PAREN)) + { + for (;;) + { + expression(compiler); + numArgs++; + if (!match(compiler, TOKEN_COMMA)) break; + } + consume(compiler, TOKEN_RIGHT_PAREN); + } + // Compile the method call. - emit(compiler, CODE_CALL); + emit(compiler, CODE_CALL_0 + numArgs); + // TODO(bob): Handle > 10 args. emit(compiler, symbol); } } diff --git a/src/vm.c b/src/vm.c index c93f4afd..74829278 100644 --- a/src/vm.c +++ b/src/vm.c @@ -36,9 +36,10 @@ 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 primitive_metaclass_new(Value receiver); -static Value primitive_num_abs(Value receiver); -static Value primitive_string_count(Value receiver); +static Value primitive_metaclass_new(Value* args, int numArgs); +static Value primitive_num_abs(Value* args, int numArgs); +static Value primitive_string_contains(Value* args, int numArgs); +static Value primitive_string_count(Value* args, int numArgs); VM* newVM() { @@ -64,6 +65,7 @@ VM* newVM() PRIMITIVE(num, abs); vm->stringClass = makeClass(); + PRIMITIVE(string, contains); PRIMITIVE(string, count); return vm; @@ -294,11 +296,21 @@ Value interpret(VM* vm, ObjBlock* block) pop(&fiber); break; - case CODE_CALL: + case CODE_CALL_0: + case CODE_CALL_1: + case CODE_CALL_2: + case CODE_CALL_3: + case CODE_CALL_4: + case CODE_CALL_5: + case CODE_CALL_6: + case CODE_CALL_7: + case CODE_CALL_8: + case CODE_CALL_9: + case CODE_CALL_10: { - Value receiver = pop(&fiber); - // TODO(bob): Arguments. + int numArgs = frame->block->bytecode[frame->ip - 1] - CODE_CALL_0; + Value receiver = fiber.stack[fiber.stackSize - numArgs - 1]; int symbol = frame->block->bytecode[frame->ip++]; // TODO(bob): Support classes for other object types. @@ -340,17 +352,21 @@ Value interpret(VM* vm, ObjBlock* block) break; case METHOD_CALL: - // TODO(bob): Should pass in correct index for locals. - callBlock(&fiber, (ObjBlock*)receiver, fiber.stackSize); + callBlock(&fiber, (ObjBlock*)receiver, fiber.stackSize - numArgs); break; case METHOD_PRIMITIVE: - push(&fiber, method->primitive(receiver)); + // TODO(bob): Pass args to primitive. + fiber.stack[fiber.stackSize - numArgs - 1] = + method->primitive(&fiber.stack[fiber.stackSize - numArgs - 1], + numArgs); + + // Discard the stack slots for the arguments. + fiber.stackSize = fiber.stackSize - numArgs; break; case METHOD_BLOCK: - // TODO(bob): Should pass in correct index for locals. - callBlock(&fiber, method->block, fiber.stackSize); + callBlock(&fiber, method->block, fiber.stackSize - numArgs); break; } break; @@ -439,25 +455,34 @@ Value pop(Fiber* fiber) return fiber->stack[--fiber->stackSize]; } -Value primitive_metaclass_new(Value receiver) +Value primitive_metaclass_new(Value* args, int numArgs) { - ObjClass* classObj = (ObjClass*)receiver; + ObjClass* classObj = (ObjClass*)args[0]; // TODO(bob): Invoke initializer method. return (Value)makeInstance(classObj); } -Value primitive_num_abs(Value receiver) +Value primitive_num_abs(Value* args, int numArgs) { - double value = ((ObjNum*)receiver)->value; + double value = ((ObjNum*)args[0])->value; if (value < 0) value = -value; return (Value)makeNum(value); } - -Value primitive_string_count(Value receiver) +Value primitive_string_contains(Value* args, int numArgs) { - double count = strlen(((ObjString*)receiver)->value); + const char* string = ((ObjString*)args[0])->value; + // TODO(bob): Check type of arg first! + const char* search = ((ObjString*)args[1])->value; + + // TODO(bob): Return bool. + return (Value)makeNum(strstr(string, search) != NULL); +} + +Value primitive_string_count(Value* args, int numArgs) +{ + double count = strlen(((ObjString*)args[0])->value); return (Value)makeNum(count); } diff --git a/src/vm.h b/src/vm.h index 5c9ea56b..5d424f40 100644 --- a/src/vm.h +++ b/src/vm.h @@ -49,7 +49,7 @@ typedef struct int numLocals; } ObjBlock; -typedef Value (*Primitive)(Value receiver); +typedef Value (*Primitive)(Value* args, int numArgs); typedef enum { @@ -86,40 +86,50 @@ typedef struct typedef enum { - CODE_CONSTANT, // Load the constant at index [arg]. + CODE_CONSTANT, - CODE_CLASS, // Define a new empty class and push it. + CODE_CLASS, - CODE_METHOD, // Add a method for symbol [arg1] with body stored in constant [arg2] to the // class on the top of stack. Does not modify the stack. + CODE_METHOD, - CODE_DUP, // Push a copy of the top of stack. + CODE_DUP, - CODE_POP, // Pop and discard the top of stack. + CODE_POP, + // Pushes the value in local slot [arg]. CODE_LOAD_LOCAL, - // Pushes the value in local slot [arg]. - CODE_STORE_LOCAL, // Stores the top of stack in local slot [arg]. Does not pop it. + CODE_STORE_LOCAL, - CODE_LOAD_GLOBAL, // Pushes the value in global slot [arg]. + CODE_LOAD_GLOBAL, - CODE_STORE_GLOBAL, // Stores the top of stack in global slot [arg]. Does not pop it. + CODE_STORE_GLOBAL, - CODE_CALL, - // Invoke the method with symbol [arg]. + // Invoke the method with symbol [arg]. The number indicates the number of + // arguments (not including the receiver). + CODE_CALL_0, + CODE_CALL_1, + CODE_CALL_2, + CODE_CALL_3, + CODE_CALL_4, + CODE_CALL_5, + CODE_CALL_6, + CODE_CALL_7, + CODE_CALL_8, + CODE_CALL_9, + CODE_CALL_10, - CODE_END // The current block is done and should be exited. - + CODE_END } Code; typedef struct