From 629b681a298ca4a4f43b4cc1c7aaa3499958c734 Mon Sep 17 00:00:00 2001 From: Julian Smith Date: Thu, 26 Aug 2021 22:19:08 +0100 Subject: [PATCH] simgear/nasal/code.c:setupFuncall(): improve diagnostic if not callable. If we have an uncallable object error, also show the type and value of the uncallable object. To make this work, have upgraded simgear/nasal/lib.c:dosprintf() to be globally available. Could perhaps rename it and declare in a different header. But it's C so we don't want to make it part of simgear's general utility functions. --- simgear/nasal/code.c | 26 +++++++++++++++++++++++++- simgear/nasal/lib.c | 6 +----- simgear/nasal/nasal.h | 6 ++++++ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/simgear/nasal/code.c b/simgear/nasal/code.c index 5662de8c..2f920ab0 100644 --- a/simgear/nasal/code.c +++ b/simgear/nasal/code.c @@ -328,6 +328,24 @@ static void checkNamedArgs(naContext ctx, struct naCode* c, struct naHash* h) } } + +/* This is a C equivalent to NasalRefDescription() in +flightgear/src/Scripting/NasalSys_private.hxx. */ +static char* NasalRefDescription(naRef val) +{ + if (naIsNil(val)) return dosprintf("nil"); + else if (naIsNum(val)) return dosprintf("num: %f", naNumValue(val).num); + else if (naIsString(val)) return dosprintf("string: %s", naStr_data(val)); + else if (naIsScalar(val)) return dosprintf("scalar"); + else if (naIsVector(val)) return dosprintf("vector"); + else if (naIsHash(val)) return dosprintf("hash"); + else if (naIsFunc(val)) return dosprintf("func"); + else if (naIsCode(val)) return dosprintf("code"); + else if (naIsCCode(val)) return dosprintf("ccode"); + else if (naIsGhost(val)) return dosprintf("ghost"); + else return dosprintf("?"); +} + static struct Frame* setupFuncall(naContext ctx, int nargs, int mcall, int named) { naRef *args, func, code, obj = naNil(); @@ -336,7 +354,13 @@ static struct Frame* setupFuncall(naContext ctx, int nargs, int mcall, int named args = &ctx->opStack[opf]; func = ctx->opStack[--opf]; - if(!IS_FUNC(func)) ERR(ctx, "function/method call on uncallable object"); + if(!IS_FUNC(func)) { + char* func_description = NasalRefDescription(func); + char* description = dosprintf("function/method call on uncallable object: %s", func_description); + ERR(ctx, description); + naFree(description); + naFree(func_description); + } code = PTR(func).func->code; if(mcall) obj = ctx->opStack[--opf]; ctx->opFrame = opf; diff --git a/simgear/nasal/lib.c b/simgear/nasal/lib.c index 03ae65e0..fcfdf8a2 100644 --- a/simgear/nasal/lib.c +++ b/simgear/nasal/lib.c @@ -375,11 +375,7 @@ static naRef f_die(naContext c, naRef me, int argc, naRef* args) return naNil(); // never executes } -// Wrapper around vsnprintf that will allocate the required size -// by calling vsnprintf with NULL and 0 - and vsnsprintf will measure the -// required amount of characters which we then allocate and return -// Returned buffer should be freed by the caller. -static char* dosprintf(char* f, ...) +char* dosprintf(char* f, ...) { char* buf; diff --git a/simgear/nasal/nasal.h b/simgear/nasal/nasal.h index 6f3e3bfa..bacef686 100644 --- a/simgear/nasal/nasal.h +++ b/simgear/nasal/nasal.h @@ -152,6 +152,12 @@ void naRethrowError(naContext subc); int naMember_get(naContext c, naRef obj, naRef field, naRef* out); int naMember_cget(naContext c, naRef obj, const char* field, naRef* out); +// Wrapper around vsnprintf that will allocate the required size +// by calling vsnprintf with NULL and 0 - and vsnsprintf will measure the +// required amount of characters which we then allocate and return +// Returned buffer should be freed by the caller with naFree(). +char* dosprintf(char* f, ...); + // Returns a hash containing functions from the Nasal standard library // Useful for passing as a namespace to an initial function call naRef naInit_std(naContext c);