Currently uLisp’s only tracing functionality is the (trace)
functions, and they only work on built-in functions, and for a maximum of however many can fit in the Tracing array (default is 3).
Without it, you just get a flat error message, with only the direct function that caused the error, and nothing that called the error function.
But with the addition of the new error-handling functions in 4.4, there is the ability to catch and re-throw a longjmp from an error call. I had the idea to add a catch-and-re-throw chunk in the main eval() function, so it would be able to iteratively create a stack trace as the C stack is unwound by the longjmps.
IIRC, @mgr also added a function (get-error)
to the error handling functions before they became part of uLisp. With this stack trace functionality, the get-error function could return the stack trace along with the message and offending object in a cons list.
I’m not sure how this would play in with macros and/or tail-call eliminations, but considering that there is an explicit block in eval() that handles tail calls, it would be able to take note of them there.
Something like this would probably end up being behind a #define guard, and probably omitted entirely from uLisp-nano, but I think it’s worth a try implementing.