feat: add parameter list parsing and up to 8 function call primitives

Extract shared parameter list parsing from namedSignature into a new parameterList function called by function, and replace single fn_call primitive with fn_call0 through fn_call8 primitives to support up to 8 arguments. Add comprehensive fn_parameters.wren test covering 0-8 parameter calls.
This commit is contained in:
Bob Nystrom
2013-11-15 02:25:28 +00:00
parent 338dc2288f
commit f88fb3d9bb
4 changed files with 111 additions and 30 deletions
+22 -21
View File
@@ -658,6 +658,25 @@ typedef struct
GrammarRule rules[];
static void parameterList(Compiler* compiler, char* name, int* length)
{
// Parse the parameter list, if any.
if (match(compiler, TOKEN_LEFT_PAREN))
{
do
{
// Define a local variable in the method for the parameter.
declareVariable(compiler);
// Add a space in the name for the parameter.
if (name != NULL) name[(*length)++] = ' ';
// TODO(bob): Check for length overflow.
}
while (match(compiler, TOKEN_COMMA));
consume(compiler, TOKEN_RIGHT_PAREN, "Expect ')' after parameters.");
}
}
static void grouping(Compiler* compiler, int allowAssignment)
{
expression(compiler, 0);
@@ -705,6 +724,8 @@ static void function(Compiler* compiler, int allowAssignment)
// that later locals have the correct slot indices.
addSymbol(&fnCompiler.locals, "(this)", 6);
parameterList(&fnCompiler, NULL, NULL);
if (match(&fnCompiler, TOKEN_LEFT_BRACE))
{
// Block body.
@@ -939,26 +960,6 @@ void infixOp(Compiler* compiler, int allowAssignment)
emit(compiler, symbol);
}
// Compiles a method signature for a regular named method.
void namedSignature(Compiler* compiler, char* name, int* length)
{
// Parse the parameter list, if any.
if (match(compiler, TOKEN_LEFT_PAREN))
{
do
{
// Define a local variable in the method for the parameter.
declareVariable(compiler);
// Add a space in the name for the parameter.
name[(*length)++] = ' ';
// TODO(bob): Check for length overflow.
}
while (match(compiler, TOKEN_COMMA));
consume(compiler, TOKEN_RIGHT_PAREN, "Expect ')' after parameters.");
}
}
// Compiles a method signature for an infix operator.
void infixSignature(Compiler* compiler, char* name, int* length)
{
@@ -1038,7 +1039,7 @@ GrammarRule rules[] =
/* TOKEN_THIS */ PREFIX(this_),
/* TOKEN_TRUE */ PREFIX(boolean),
/* TOKEN_VAR */ UNUSED,
/* TOKEN_NAME */ { name, NULL, namedSignature, PREC_NONE, NULL },
/* TOKEN_NAME */ { name, NULL, parameterList, PREC_NONE, NULL },
/* TOKEN_NUMBER */ PREFIX(number),
/* TOKEN_STRING */ PREFIX(string),
/* TOKEN_LINE */ UNUSED,
+63 -6
View File
@@ -54,16 +54,65 @@ DEF_PRIMITIVE(bool_toString)
}
}
DEF_PRIMITIVE(fn_call)
// The call instruction leading to this primitive has one argument for the
// receiver plus as many arguments as were passed. When we push the block onto
// the callstack, we again use as many arguments. That ensures that the result
// of evaluating the block goes into the slot that the caller of *this*
// primitive is expecting.
DEF_PRIMITIVE(fn_call0)
{
// The call instruction leading to this primitive has one argument. So when
// we push the block onto the callstack, we again use one argument. That
// ensures that the result of evaluating the block goes into the slot that
// the caller of *this* primitive is expecting.
callFunction(fiber, AS_FN(args[0]), 1);
return NULL;
}
DEF_PRIMITIVE(fn_call1)
{
callFunction(fiber, AS_FN(args[0]), 2);
return NULL;
}
DEF_PRIMITIVE(fn_call2)
{
callFunction(fiber, AS_FN(args[0]), 3);
return NULL;
}
DEF_PRIMITIVE(fn_call3)
{
callFunction(fiber, AS_FN(args[0]), 4);
return NULL;
}
DEF_PRIMITIVE(fn_call4)
{
callFunction(fiber, AS_FN(args[0]), 5);
return NULL;
}
DEF_PRIMITIVE(fn_call5)
{
callFunction(fiber, AS_FN(args[0]), 6);
return NULL;
}
DEF_PRIMITIVE(fn_call6)
{
callFunction(fiber, AS_FN(args[0]), 7);
return NULL;
}
DEF_PRIMITIVE(fn_call7)
{
callFunction(fiber, AS_FN(args[0]), 8);
return NULL;
}
DEF_PRIMITIVE(fn_call8)
{
callFunction(fiber, AS_FN(args[0]), 9);
return NULL;
}
DEF_PRIMITIVE(fn_eqeq)
{
if (args[1]->type != OBJ_FN) return newBool(vm, 0);
@@ -252,7 +301,15 @@ void loadCore(VM* vm)
vm->classClass = AS_CLASS(findGlobal(vm, "Class"));
vm->fnClass = AS_CLASS(findGlobal(vm, "Function"));
PRIMITIVE(vm->fnClass, "call", fn_call);
PRIMITIVE(vm->fnClass, "call", fn_call0);
PRIMITIVE(vm->fnClass, "call ", fn_call1);
PRIMITIVE(vm->fnClass, "call ", fn_call2);
PRIMITIVE(vm->fnClass, "call ", fn_call3);
PRIMITIVE(vm->fnClass, "call ", fn_call4);
PRIMITIVE(vm->fnClass, "call ", fn_call5);
PRIMITIVE(vm->fnClass, "call ", fn_call6);
PRIMITIVE(vm->fnClass, "call ", fn_call7);
PRIMITIVE(vm->fnClass, "call ", fn_call8);
PRIMITIVE(vm->fnClass, "== ", fn_eqeq);
PRIMITIVE(vm->fnClass, "!= ", fn_bangeq);