Argument lists.

This commit is contained in:
Bob Nystrom
2013-10-26 16:01:44 -07:00
parent d9a4da94a3
commit b9baf46e9a
4 changed files with 85 additions and 35 deletions

View File

@ -5,4 +5,4 @@ class Foo { // line comment
} }
var a = Foo.new var a = Foo.new
a.bar a.bar
"a string" "something".contains("meth")

View File

@ -275,13 +275,28 @@ void call(Compiler* compiler)
{ {
primary(compiler); primary(compiler);
if (match(compiler, TOKEN_DOT)) while (match(compiler, TOKEN_DOT))
{ {
consume(compiler, TOKEN_NAME); consume(compiler, TOKEN_NAME);
int symbol = internSymbol(compiler); 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. // Compile the method call.
emit(compiler, CODE_CALL); emit(compiler, CODE_CALL_0 + numArgs);
// TODO(bob): Handle > 10 args.
emit(compiler, symbol); emit(compiler, symbol);
} }
} }

View File

@ -36,9 +36,10 @@ typedef struct
static void callBlock(Fiber* fiber, ObjBlock* block, int firstLocal); static void callBlock(Fiber* fiber, ObjBlock* block, int firstLocal);
static void push(Fiber* fiber, Value value); static void push(Fiber* fiber, Value value);
static Value pop(Fiber* fiber); static Value pop(Fiber* fiber);
static Value primitive_metaclass_new(Value receiver); static Value primitive_metaclass_new(Value* args, int numArgs);
static Value primitive_num_abs(Value receiver); static Value primitive_num_abs(Value* args, int numArgs);
static Value primitive_string_count(Value receiver); static Value primitive_string_contains(Value* args, int numArgs);
static Value primitive_string_count(Value* args, int numArgs);
VM* newVM() VM* newVM()
{ {
@ -64,6 +65,7 @@ VM* newVM()
PRIMITIVE(num, abs); PRIMITIVE(num, abs);
vm->stringClass = makeClass(); vm->stringClass = makeClass();
PRIMITIVE(string, contains);
PRIMITIVE(string, count); PRIMITIVE(string, count);
return vm; return vm;
@ -294,11 +296,21 @@ Value interpret(VM* vm, ObjBlock* block)
pop(&fiber); pop(&fiber);
break; 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); int numArgs = frame->block->bytecode[frame->ip - 1] - CODE_CALL_0;
// TODO(bob): Arguments.
Value receiver = fiber.stack[fiber.stackSize - numArgs - 1];
int symbol = frame->block->bytecode[frame->ip++]; int symbol = frame->block->bytecode[frame->ip++];
// TODO(bob): Support classes for other object types. // TODO(bob): Support classes for other object types.
@ -340,17 +352,21 @@ Value interpret(VM* vm, ObjBlock* block)
break; break;
case METHOD_CALL: case METHOD_CALL:
// TODO(bob): Should pass in correct index for locals. callBlock(&fiber, (ObjBlock*)receiver, fiber.stackSize - numArgs);
callBlock(&fiber, (ObjBlock*)receiver, fiber.stackSize);
break; break;
case METHOD_PRIMITIVE: 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; break;
case METHOD_BLOCK: case METHOD_BLOCK:
// TODO(bob): Should pass in correct index for locals. callBlock(&fiber, method->block, fiber.stackSize - numArgs);
callBlock(&fiber, method->block, fiber.stackSize);
break; break;
} }
break; break;
@ -439,25 +455,34 @@ Value pop(Fiber* fiber)
return fiber->stack[--fiber->stackSize]; 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. // TODO(bob): Invoke initializer method.
return (Value)makeInstance(classObj); 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; if (value < 0) value = -value;
return (Value)makeNum(value); return (Value)makeNum(value);
} }
Value primitive_string_contains(Value* args, int numArgs)
Value primitive_string_count(Value receiver)
{ {
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); return (Value)makeNum(count);
} }

View File

@ -49,7 +49,7 @@ typedef struct
int numLocals; int numLocals;
} ObjBlock; } ObjBlock;
typedef Value (*Primitive)(Value receiver); typedef Value (*Primitive)(Value* args, int numArgs);
typedef enum typedef enum
{ {
@ -86,40 +86,50 @@ typedef struct
typedef enum typedef enum
{ {
CODE_CONSTANT,
// Load the constant at index [arg]. // Load the constant at index [arg].
CODE_CONSTANT,
CODE_CLASS,
// Define a new empty class and push it. // 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 // 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. // class on the top of stack. Does not modify the stack.
CODE_METHOD,
CODE_DUP,
// Push a copy of the top of stack. // Push a copy of the top of stack.
CODE_DUP,
CODE_POP,
// Pop and discard the top of stack. // Pop and discard the top of stack.
CODE_POP,
CODE_LOAD_LOCAL,
// Pushes the value in local slot [arg]. // Pushes the value in local slot [arg].
CODE_LOAD_LOCAL,
CODE_STORE_LOCAL,
// Stores the top of stack in local slot [arg]. Does not pop it. // 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]. // 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. // Stores the top of stack in global slot [arg]. Does not pop it.
CODE_STORE_GLOBAL,
CODE_CALL, // Invoke the method with symbol [arg]. The number indicates the number of
// Invoke the method with symbol [arg]. // 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. // The current block is done and should be exited.
CODE_END
} Code; } Code;
typedef struct typedef struct