Debugging layers
tratt.net
tratt.net
In the TXR language, the same thing is done by the function rlcp (and a few relatives). I don't remember what "rl" stands for: probably read-time location.
You can see rlcp and rl calls throughout this parser:
http://www.kylheku.com/cgit/txr/tree/parser.y
In the evaluation module, http://www.kylheku.com/cgit/txr/tree/eval.c you can see this code:
} else if ((macro = lookup_mac(menv, sym))) {
val mac_expand = expand_macro(form, macro, menv);
if (mac_expand == form)
return form;
form = rlcp_tree(mac_expand, form);
goto tail;
User-defined macros aren't expected to do rlcp diligently; so we compensate for their negligence with rlcp_tree(mac_expand, form). This basically liberally sprinkles the source location of the original form over the nodes of the macro-expansion. It works pretty well in practice, helping to relate errors in macro expansions to the original source. rlcp_tree respects nodes that already have source info; it gives it to those which don't have it.Source info is associated with tree nodes using a weak global hash table. When an object with source info attached goes away, the info goes away.
Trivial test:
macro-error-test.tl:
1: (defmacro mac (expr)
2: expr)
3: (mac (/ 1 0))
$ txr macro-error-test.tl
txr: unhandled exception of type numeric-error:
txr: possibly triggered at macro-error-test.tl:3 by form (/ 1 0)
txr: message: /: division by zero
If we change the example to this: 1: (defmacro mac (expr)
2: (copy expr))
3: (mac (/ 1 0))
the error is exactly the same. This time the expr coming out of the macro is a copy and so it has no source info. The macro expander adds it. This is less accurate: the line number of the macro call isn't necessarily that of the (/ 1 0). Here it happens to be because it's a one-liner expression.Example of an error during macro expansion:
1: (defmacro mac (expr)
2: (/ 1 0))
3: (mac foo)
$ txr macro-error-test-2.tl
txr: unhandled exception of type numeric-error:
txr: possibly triggered at macro-error-test-2.tl:2 by form (/ 1 0)
txr: during expansion at macro-error-test-2.tl:3 of form (mac (/ 1 0))
txr: message: /: division by zero