I wrote the rest of this post thinking you were talking about the first one, but right at the end I realized I wasn't so sure. :)
"Namely, making the lists that form the code/ast have reverse links, so you can mutate above the macro call level, instead of just insert arbitrary code in place."
I'll make an observation so you can see if it agrees with what you're thinking of: The expression "above the macro call level" will always be a function call or a special form, never a macro call. If it were a macro call, we'd be expanding that call instead of this one.
For these purposes, it would be fun to have a cons-cell-like data structure with three accessors: (car x), (cdr x), and (parent x). The parent of x is the most recent cons-with-parent to have been constructed or mutated to have x as its car. If this construction or mutation has never happened, the parent is nil.
Then we can have macros take cons-with-parent values as their argument lists, and your macro would look like this:
Unfortunately, if we call (list 1 2 (splice 3 4) 5), then when the splice macro calls (parent list), it'll only see ((splice 3 4) 5). If it calls (parent (parent list)), it'll see nil.
Suppose we have a more comprehensive alternative that lets us manipulate the entire surrounding expression. I'll formulate it without the need to use conses-with-parents or mutation:
; We're defining a macro called "splice".
; The original code we're replacing is expr.
; We affect 1 level of code, and our macro call is at location (i).
(mac-deep splice expr (i)
(let (before ((_ . args) . after)) (cut expr i)
(join before args after)))
If I were to implement an Arc-like language that supported this, it would have some amusingly disappointing consequences: