diff --git a/src/wren_vm.c b/src/wren_vm.c index 2a039898..c23f2cca 100644 --- a/src/wren_vm.c +++ b/src/wren_vm.c @@ -24,6 +24,34 @@ static void* defaultReallocate(void* memory, size_t oldSize, size_t newSize) return realloc(memory, newSize); } +char* methodNotFound(char* className, char* symbolName) +{ + // Count the number of spaces to determine number of arguments for this + // symbol. + int pos = strlen(symbolName) - 1; + while (symbolName[pos] == ' ') pos--; + + int arguments = strlen(symbolName) - pos - 1; + + // Create a new string that contains only the symbol name. + char *canonicalizedSymbol = malloc(pos + 1); + strncpy(canonicalizedSymbol, symbolName, pos + 1); + + int messageLength = strlen(className) + strlen(canonicalizedSymbol) + + (arguments > 9 ? 48 : 47) + (arguments == 1 ? 0 : 1); + char *message = malloc(messageLength); + + snprintf(message, messageLength, "%s does not implement method '%s' with %d argument%s.", + className, + canonicalizedSymbol, + arguments, + arguments == 1 ? "" : "s"); + + free(canonicalizedSymbol); + + return &message[0]; +} + WrenVM* wrenNewVM(WrenConfiguration* configuration) { WrenReallocateFn reallocate = defaultReallocate; @@ -575,11 +603,10 @@ static bool runInterpreter(WrenVM* vm) // If the class's method table doesn't include the symbol, bail. if (symbol >= classObj->methods.count) { - char message[100]; - snprintf(message, 100, "%s does not implement method '%s'.", - classObj->name->value, - vm->methodNames.data[symbol]); + char *message = methodNotFound(classObj->name->value, + vm->methodNames.data[symbol]); RUNTIME_ERROR(message); + free(message); } Method* method = &classObj->methods.data[symbol]; @@ -628,11 +655,10 @@ static bool runInterpreter(WrenVM* vm) case METHOD_NONE: { - char message[100]; - snprintf(message, 100, "%s does not implement method '%s'.", - classObj->name->value, - vm->methodNames.data[symbol]); + char *message = methodNotFound(classObj->name->value, + vm->methodNames.data[symbol]); RUNTIME_ERROR(message); + free(message); } } DISPATCH(); @@ -679,10 +705,10 @@ static bool runInterpreter(WrenVM* vm) // If the class's method table doesn't include the symbol, bail. if (symbol >= classObj->methods.count) { - char message[100]; - snprintf(message, 100, "%s does not implement method '%s'.", - classObj->name->value, vm->methodNames.data[symbol]); + char *message = methodNotFound(classObj->name->value, + vm->methodNames.data[symbol]); RUNTIME_ERROR(message); + free(message); } Method* method = &classObj->methods.data[symbol]; @@ -731,10 +757,10 @@ static bool runInterpreter(WrenVM* vm) case METHOD_NONE: { - char message[100]; - snprintf(message, 100, "%s does not implement method '%s'.", - classObj->name->value, vm->methodNames.data[symbol]); + char *message = methodNotFound(classObj->name->value, + vm->methodNames.data[symbol]); RUNTIME_ERROR(message); + free(message); } } DISPATCH(); diff --git a/test/fiber/error.wren b/test/fiber/error.wren index ccd1e87b..33e2c3c7 100644 --- a/test/fiber/error.wren +++ b/test/fiber/error.wren @@ -3,5 +3,5 @@ var fiber = new Fiber { } IO.print(fiber.error) // expect: null -IO.print(fiber.try) // expect: String does not implement method 'unknown'. -IO.print(fiber.error) // expect: String does not implement method 'unknown'. +IO.print(fiber.try) // expect: String does not implement method 'unknown' with 0 arguments. +IO.print(fiber.error) // expect: String does not implement method 'unknown' with 0 arguments. diff --git a/test/fiber/try.wren b/test/fiber/try.wren index 9abfec89..b4cf68ed 100644 --- a/test/fiber/try.wren +++ b/test/fiber/try.wren @@ -6,5 +6,5 @@ var fiber = new Fiber { IO.print(fiber.try) // expect: before -// expect: Bool does not implement method 'unknownMethod'. +// expect: Bool does not implement method 'unknownMethod' with 0 arguments. IO.print("after try") // expect: after try diff --git a/test/inheritance/do_not_inherit_static_methods.wren b/test/inheritance/do_not_inherit_static_methods.wren index b19f7a21..643efad0 100644 --- a/test/inheritance/do_not_inherit_static_methods.wren +++ b/test/inheritance/do_not_inherit_static_methods.wren @@ -4,4 +4,4 @@ class Foo { class Bar is Foo {} -Bar.methodOnFoo // expect runtime error: Bar metaclass does not implement method 'methodOnFoo'. +Bar.methodOnFoo // expect runtime error: Bar metaclass does not implement method 'methodOnFoo' with 0 arguments. diff --git a/test/method/not_found.wren b/test/method/not_found.wren index 3e26a186..033a7571 100644 --- a/test/method/not_found.wren +++ b/test/method/not_found.wren @@ -1,3 +1,3 @@ class Foo {} -(new Foo).someUnknownMethod // expect runtime error: Foo does not implement method 'someUnknownMethod'. +(new Foo).someUnknownMethod // expect runtime error: Foo does not implement method 'someUnknownMethod' with 0 arguments. diff --git a/test/method/not_found_eleven_arguments.wren b/test/method/not_found_eleven_arguments.wren new file mode 100644 index 00000000..6bdccaa6 --- /dev/null +++ b/test/method/not_found_eleven_arguments.wren @@ -0,0 +1,3 @@ +class Foo {} + +(new Foo).someUnknownMethod(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) // expect runtime error: Foo does not implement method 'someUnknownMethod' with 11 arguments. \ No newline at end of file diff --git a/test/method/not_found_multiple_arguments.wren b/test/method/not_found_multiple_arguments.wren new file mode 100644 index 00000000..3ff67353 --- /dev/null +++ b/test/method/not_found_multiple_arguments.wren @@ -0,0 +1,3 @@ +class Foo {} + +(new Foo).someUnknownMethod(1, 2) // expect runtime error: Foo does not implement method 'someUnknownMethod' with 2 arguments. \ No newline at end of file diff --git a/test/method/not_found_one_argument.wren b/test/method/not_found_one_argument.wren new file mode 100644 index 00000000..07958bd7 --- /dev/null +++ b/test/method/not_found_one_argument.wren @@ -0,0 +1,3 @@ +class Foo {} + +(new Foo).someUnknownMethod(1) // expect runtime error: Foo does not implement method 'someUnknownMethod' with 1 argument. \ No newline at end of file diff --git a/test/method/static_method_not_found.wren b/test/method/static_method_not_found.wren index cd58d155..39ee8af2 100644 --- a/test/method/static_method_not_found.wren +++ b/test/method/static_method_not_found.wren @@ -1,3 +1,3 @@ class Foo {} -Foo.bar // expect runtime error: Foo metaclass does not implement method 'bar'. \ No newline at end of file +Foo.bar // expect runtime error: Foo metaclass does not implement method 'bar' with 0 arguments. \ No newline at end of file diff --git a/test/super/no_superclass_method.wren b/test/super/no_superclass_method.wren index d1126c95..a3369b96 100644 --- a/test/super/no_superclass_method.wren +++ b/test/super/no_superclass_method.wren @@ -1,7 +1,7 @@ class Base {} class Derived is Base { - foo { super.doesNotExist } // expect runtime error: Base does not implement method 'doesNotExist'. + foo { super.doesNotExist } // expect runtime error: Base does not implement method 'doesNotExist' with 0 arguments. } (new Derived).foo