|
From: Donal K. F. <don...@ma...> - 2018-01-09 15:10:11
|
On 08/01/2018 19:28, Kevin Kenny wrote:
> I'd really like to have a way to emit code for the "wrong # args' case
> without trying to call a proc, since wherever the arg check happens, it
> won't be inside the quadcode, giving me problems if an invocation with
> possible wrong args happens and I want to inline the target procedure.
> Moreover, I think that the current behaviour is likely a time bomb - I'm
> sure that the specialized procedure with the wrong arg list is useless -
> and it may be sitting there waiting to tickle other bugs, since it
> likely also contains incorrect code.
Exceptions are thrown by preparing them with initException and jumping
to the relevant exception handler. The initException configures the
exception within the Tcl interpreter, and produces a FAIL that can be
discarded (it's useful when dealing with code that only *may* throw an
exception, such as when compiling the finally clause of a [try]).
The arguments that are useful here are:
initException TGT MSG OPT CODE LVL
MSG is the error message. OPT is the options dictionary *without* the
-code or -level options, and the -errorinfo option will be initialised
from the message if it is absent. CODE is the Tcl return code, and LVL
is the level. For wrong#args, you'd use:
initException {temp TGTID} \
{literal {wrong # args: should be ...}} \
{literal {-errorcode {TCL WRONGARGS}}} \
{literal 1} \
{literal 0}
You also need to get the @debug-related pseudoopcodes right because the
information they contain is used to fill in the error information. So
long as this throw happens when the right one is current, it will all
work out right. (If not, it's a bug that I must fix; I think I chased
all those bits down.) By right one, I mean that if we know the number of
arguments that an invoke *should* take, we can replace the invoke with a
version that checks the count and throws, otherwise doing a real invoke;
substituting the plain invoke opcode like that will put the throw in the
correct place; it's still part of the expansion of what was an
INST_INVOKE_STK1, INST_INVOKE_STK4 or INST_INVOKE_EXPANDED in the
original bytecode, and of the same Tcl command implementation.
The result type of the initException above is FAIL STRING because the
type of the first input is STRING, but we know because we're not using 0
0 that this is a definite failure so we don't need to use a jumpMaybe to
test. (All that side of things gets important with non-constant
arguments, which can't be analysed so easily.)
The exception handling is just the usual stuff; the jumpMaybe opcode
does nothing complicated.
Donal.
|