mirror of
https://github.com/wren-lang/wren.git
synced 2026-01-11 22:28:45 +01:00
Argument lists.
This commit is contained in:
@ -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")
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
61
src/vm.c
61
src/vm.c
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
38
src/vm.h
38
src/vm.h
@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user