1
0
forked from Mirror/wren

Allow multi-part method calls.

Also correctly mangle names with arguments and parts.
This commit is contained in:
Bob Nystrom
2013-10-27 11:20:19 -07:00
parent b9baf46e9a
commit c7e11059f4
2 changed files with 59 additions and 16 deletions

View File

@ -5,6 +5,8 @@
#include "compiler.h"
#define MAX_NAME 256
typedef enum
{
TOKEN_LEFT_PAREN,
@ -271,29 +273,70 @@ void expression(Compiler* compiler)
// foo.bar
// foo.bar(arg, arg)
// foo.bar { block } other { block }
// foo.bar(arg) nextPart { arg } lastBit
void call(Compiler* compiler)
{
primary(compiler);
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.
char name[MAX_NAME];
int length = 0;
int numArgs = 0;
if (match(compiler, TOKEN_LEFT_PAREN))
consume(compiler, TOKEN_NAME);
// Build the method name. The mangled name includes all of the name parts
// in a mixfix call as well as spaces for every argument.
// So a method call like:
//
// foo.bar(arg, arg) else { block } last
//
// Will have name: "bar else last"
// Compile all of the name parts.
for (;;)
{
for (;;)
// Add the just-consumed part name to the method name.
int partLength = compiler->parser->previous.end -
compiler->parser->previous.start;
strncpy(name + length,
compiler->parser->source + compiler->parser->previous.start,
partLength);
length += partLength;
// TODO(bob): Check for length overflow.
// TODO(bob): Allow block arguments.
// Parse the argument list, if any.
if (match(compiler, TOKEN_LEFT_PAREN))
{
expression(compiler);
numArgs++;
if (!match(compiler, TOKEN_COMMA)) break;
for (;;)
{
expression(compiler);
numArgs++;
// Add a space in the name for each argument. Lets us overload by
// arity.
name[length++] = ' ';
if (!match(compiler, TOKEN_COMMA)) break;
}
consume(compiler, TOKEN_RIGHT_PAREN);
// If there isn't another part name after the argument list, stop.
if (!match(compiler, TOKEN_NAME)) break;
}
else
{
// If there isn't an argument list, we're done.
break;
}
consume(compiler, TOKEN_RIGHT_PAREN);
}
int symbol = ensureSymbol(&compiler->parser->vm->symbols, name, length);
// Compile the method call.
emit(compiler, CODE_CALL_0 + numArgs);
// TODO(bob): Handle > 10 args.

View File

@ -4,9 +4,9 @@
#include "vm.h"
#define PRIMITIVE(cls, prim) \
#define PRIMITIVE(cls, name, prim) \
{ \
int symbol = ensureSymbol(&vm->symbols, #prim, strlen(#prim)); \
int symbol = ensureSymbol(&vm->symbols, name, strlen(name)); \
vm->cls##Class->methods[symbol].type = METHOD_PRIMITIVE; \
vm->cls##Class->methods[symbol].primitive = primitive_##cls##_##prim; \
}
@ -62,11 +62,11 @@ VM* newVM()
vm->classClass = makeClass();
vm->numClass = makeClass();
PRIMITIVE(num, abs);
PRIMITIVE(num, "abs", abs);
vm->stringClass = makeClass();
PRIMITIVE(string, contains);
PRIMITIVE(string, count);
PRIMITIVE(string, "contains ", contains);
PRIMITIVE(string, "count", count);
return vm;
}