From 322eea1af5a182c840877913238183fd445e3fb4 Mon Sep 17 00:00:00 2001 From: Bob Nystrom Date: Thu, 26 Mar 2015 07:17:09 -0700 Subject: [PATCH] Generate a runtime error if a foreign method was not found. --- src/vm/wren_vm.c | 21 +++++++++++++++++-- .../foreign/foreign_after_static.wren | 3 +++ .../foreign/foreign_method_with_body.wren | 3 +++ test/language/foreign/unknown_method.wren | 3 +++ 4 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 test/language/foreign/foreign_after_static.wren create mode 100644 test/language/foreign/foreign_method_with_body.wren create mode 100644 test/language/foreign/unknown_method.wren diff --git a/src/vm/wren_vm.c b/src/vm/wren_vm.c index 1c21686d..61031f9c 100644 --- a/src/vm/wren_vm.c +++ b/src/vm/wren_vm.c @@ -312,7 +312,14 @@ static WrenForeignMethodFn findForeignMethod(WrenVM* vm, return NULL; } -static void bindMethod(WrenVM* vm, int methodType, int symbol, +// Defines [methodValue] as a method on [classObj]. +// +// Handles both foreign methods where [methodValue] is a string containing the +// method's signature and Wren methods where [methodValue] is a function. +// +// Returns an error string if the method is a foreign method that could not be +// found. Otherwise returns `NULL_VAL`. +static Value bindMethod(WrenVM* vm, int methodType, int symbol, ObjModule* module, ObjClass* classObj, Value methodValue) { Method method; @@ -324,6 +331,13 @@ static void bindMethod(WrenVM* vm, int methodType, int symbol, classObj->name->value, methodType == CODE_METHOD_STATIC, name); + + if (method.fn.foreign == NULL) + { + return wrenStringFormat(vm, + "Could not find foreign method '@' for class $ in module '$'.", + methodValue, classObj->name->value, module->name->value); + } } else { @@ -341,6 +355,7 @@ static void bindMethod(WrenVM* vm, int methodType, int symbol, if (methodType == CODE_METHOD_STATIC) classObj = classObj->obj.classObj; wrenBindMethod(vm, classObj, symbol, method); + return NULL_VAL; } static void callForeign(WrenVM* vm, ObjFiber* fiber, @@ -1219,7 +1234,9 @@ static bool runInterpreter(WrenVM* vm) uint16_t symbol = READ_SHORT(); ObjClass* classObj = AS_CLASS(PEEK()); Value method = PEEK2(); - bindMethod(vm, instruction, symbol, fn->module, classObj, method); + Value error = bindMethod(vm, instruction, symbol, fn->module, classObj, + method); + if (IS_STRING(error)) RUNTIME_ERROR(error); DROP(); DROP(); DISPATCH(); diff --git a/test/language/foreign/foreign_after_static.wren b/test/language/foreign/foreign_after_static.wren new file mode 100644 index 00000000..9bb91c4a --- /dev/null +++ b/test/language/foreign/foreign_after_static.wren @@ -0,0 +1,3 @@ +class Foo { + static foreign method // expect error +} diff --git a/test/language/foreign/foreign_method_with_body.wren b/test/language/foreign/foreign_method_with_body.wren new file mode 100644 index 00000000..aaff1e3a --- /dev/null +++ b/test/language/foreign/foreign_method_with_body.wren @@ -0,0 +1,3 @@ +class Foo { + foreign method { "body" } // expect error +} diff --git a/test/language/foreign/unknown_method.wren b/test/language/foreign/unknown_method.wren new file mode 100644 index 00000000..9b7c7c45 --- /dev/null +++ b/test/language/foreign/unknown_method.wren @@ -0,0 +1,3 @@ +class Foo { + foreign someUnknownMethod // expect runtime error: Could not find foreign method 'someUnknownMethod' for class Foo in module 'main'. +}