diff --git a/src/compiler.c b/src/compiler.c index 908fc3b7..185038e0 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -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. diff --git a/src/vm.c b/src/vm.c index 74829278..17a7e5a6 100644 --- a/src/vm.c +++ b/src/vm.c @@ -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; }