diff --git a/source/metacall/include/metacall/metacall_error.h b/source/metacall/include/metacall/metacall_error.h index 6324746795..07d25d228d 100644 --- a/source/metacall/include/metacall/metacall_error.h +++ b/source/metacall/include/metacall/metacall_error.h @@ -106,6 +106,18 @@ METACALL_API int metacall_error_last(metacall_exception ex); */ METACALL_API void metacall_error_clear(void); +/** +* @brief +* Record a throwable value as the last error for the calling thread. Called +* internally by metacallfv_s when a loader returns a TYPE_THROWABLE value. +* May also be called by ports or loaders that want to set the last error +* directly. Copies @v so the caller retains ownership of the original value. +* +* @param[in] v +* Throwable value to record; must be of type TYPE_THROWABLE +*/ +METACALL_API void metacall_error_set_last(void *v); + #ifdef __cplusplus } #endif diff --git a/source/metacall/source/metacall.c b/source/metacall/source/metacall.c index b35445b245..17cfdc21d2 100644 --- a/source/metacall/source/metacall.c +++ b/source/metacall/source/metacall.c @@ -1144,6 +1144,11 @@ void *metacallfv_s(void *func, void *args[], size_t size) ret = function_call(f, args, size); + if (ret != NULL && type_id_throwable(value_type_id(ret)) == 0) + { + metacall_error_set_last(ret); + } + if (ret != NULL) { type t = signature_get_return(s); diff --git a/source/metacall/source/metacall_error.c b/source/metacall/source/metacall_error.c index 503df87efa..bedb4df730 100644 --- a/source/metacall/source/metacall_error.c +++ b/source/metacall/source/metacall_error.c @@ -24,8 +24,14 @@ #include +#include + #include +/* -- Private Variables -- */ + +static PORTABILITY_THREAD_LOCAL value metacall_error_last_v = NULL; + /* -- Methods -- */ void *metacall_error_throw(const char *label, int64_t code, const char *stacktrace, const char *message, ...) @@ -92,13 +98,34 @@ int metacall_error_from_value(void *v, metacall_exception ex) int metacall_error_last(metacall_exception ex) { - // TODO - (void)ex; + if (metacall_error_last_v == NULL) + { + return 1; + } - return 1; + return metacall_error_from_value(metacall_error_last_v, ex); } void metacall_error_clear(void) { - // TODO + if (metacall_error_last_v != NULL) + { + value_type_destroy(metacall_error_last_v); + metacall_error_last_v = NULL; + } +} + +void metacall_error_set_last(void *v) +{ + if (v == NULL || type_id_throwable(value_type_id((value)v)) != 0) + { + return; + } + + if (metacall_error_last_v != NULL) + { + value_type_destroy(metacall_error_last_v); + } + + metacall_error_last_v = value_type_copy((value)v); }