// File: /workspace/github_c_makefile_star2_O0/BernardTatin[P]s7sh/s7.c
// Function: op_expansion
static goto_t op_expansion(s7_scheme *sc)
                {
                    int64_t loc;
                    s7_pointer caller;

                    /* read-time macro expansion:
                     *   (define-macro (hi a) (format #t "hi...") `(+ ,a 1))
                     *   (define (ho b) (+ 1 (hi b)))
                     * here sc->value is: (ho b), (hi b), (+ 1 (hi b)), (define (ho b) (+ 1 (hi b)))
                     * but... first we can't tell for sure at this point that "hi" really is a macro
                     *   (letrec ((hi ... (hi...))) will be confused about the second hi,
                     *   or (call/cc (lambda (hi) (hi 1))) etc.
                     * second, figuring out that we're quoted is not easy -- we have to march all the
                     * way to the bottom of the stack looking for op_read_quote or op_read_vector
                     *    #(((hi)) 2) or '(((hi)))
                     * or op_read_list with args not equal (quote) or (macroexpand)
                     *    '(hi 3) or (macroexpand (hi 3) or (quote (hi 3))
                     * and those are only the problems I noticed!
                     *
                     * The hardest of these problems involve shadowing, so Rick asked for "define-expansion"
                     *   which is like define-macro, but the programmer guarantees that the macro
                     *   name will not be shadowed.
                     *
                     * to make expansion recognition fast here, define-expansion sets the T_EXPANSION
                     *   bit in the symbol as well as the value:
                     *   set_type(sc->code, T_EXPANSION | T_SYMBOL)
                     * but this can lead to confusion because the expansion name is now globally identified as an expansion.
                     *    (let () (define-expansion (ex1 a) `(+ ,a 1)) (display (ex1 3)))
                     *    (define (ex1 b) (* b 2)) (display (ex1 3))
                     * since this happens at the top level, the first line is evaluated, ex1 becomes an expansion.
                     * but the reader has no idea about lets and whatnot, so in the second line, ex1 is still an expansion
                     * to the reader, so it sees (define (+ b 1) ...) -- error!  To support tail-calls, there's no
                     * way in eval to see the let close, so we can't clear the expansion flag when the let is done.
                     * But we don't want define-expansion to mimic define-constant (via T_IMMUTABLE) because programs
                     * like lint need to cancel reader-cond (for example).  So, we allow an expansion to be redefined,
                     * and check here that the expander symbol still refers to an expansion.
                     *
                     * but in (define (ex1 b) b), the reader doesn't know we're in a define call (or it would be
                     *   a bother to notice), so to redefine an expansion, first (set! ex1 #f) or (define ex1 #f),
                     *   then (define (ex1 b) b).
                     *
                     * This is a mess!  Maybe we should insist that expansions are always global.
                     *
                     * run-time expansion and splicing into the code as in CL won't work in s7 because macros
                     *   are first-class objects.  For example (define (f m) (m 1)), call it with a macro, say `(+ ,arg 1),
                     *   and in CL-style, you'd now have the body (+ ,arg 1) or maybe even 2, now call f with a function,
                     *   or some other macro -- oops!
                     */

                    loc = s7_stack_top(sc) - 1;
                    if (is_pair(stack_args(sc->stack, loc)))
                        caller = car(stack_args(sc->stack, loc)); /* this can be garbage */
                    else caller = sc->F;
                    if ((loc >= 3) &&
                            (stack_op(sc->stack, loc) != OP_READ_QUOTE) &&             /* '(hi 1) for example */
                            (stack_op(sc->stack, loc) != OP_READ_VECTOR) &&            /* #(reader-cond) for example */
                            (caller != sc->quote_symbol) &&               /* (quote (hi 1)) */
                            (caller != sc->macroexpand_symbol) &&         /* (macroexpand (hi 1)) */
                            (caller != sc->define_expansion_symbol) &&    /* (define-expansion ...) being reloaded/redefined */
                            (caller != sc->define_expansion_star_symbol)) /* (define-expansion* ...) being reloaded/redefined */
                    {
                        s7_pointer symbol, slot;
                        /* we're playing fast and loose with sc->envir in the reader, so here we need a disaster check */
#if S7_DEBUGGING
                        if (unchecked_type(sc->envir) != T_LET) sc->envir = sc->nil;
#else
                        if (!is_let(sc->envir)) sc->envir = sc->nil;
#endif
                        symbol = car(sc->value);

                        if ((symbol_id(symbol) == 0) ||
                                (sc->envir == sc->nil))
                            slot = global_slot(symbol);
                        else slot = symbol_to_slot(sc, symbol);

                        if (is_slot(slot))
                            sc->code = slot_value(slot);
                        else sc->code = sc->undefined;
                        if ((!is_either_macro(sc->code)) || (!is_expansion(sc->code)))
                            clear_expansion(symbol);
                        else
                        {
                            /* call the reader macro */
                            sc->args = copy_list(sc, cdr(sc->value));
                            push_stack_no_code(sc, OP_EXPANSION, sc->nil);
                            new_frame(sc, closure_let(sc->code), sc->envir);
                            if (!is_macro_star(sc->code))
                                return(goto_apply_lambda);
                            apply_macro_star_1(sc);
                            return(goto_begin);
                            /* bacros don't seem to make sense here -- they are tied to the run-time environment,
                             *   procedures would need to evaluate their arguments in rootlet
                             */
                        }
                    }
                    return(fall_through);
                }

// Assembly:
subq $0x38, %rsp
movq %rdi, 0x28(%rsp)
movq 0x28(%rsp), %rax
movq 0x50(%rax), %rax
movq 0x28(%rsp), %rcx
movq 0x48(%rcx), %rcx
subq %rcx, %rax
sarq $0x3, %rax
subq $0x1, %rax
movq %rax, 0x20(%rsp)
movq 0x28(%rsp), %rax
movq 0x38(%rax), %rax
movq 0x10(%rax), %rax
movq 0x20(%rsp), %rcx
subq $0x1, %rcx
movq (%rax,%rcx,8), %rax
movzbl (%rax), %eax
cmpl $0x1, %eax
jne 0x1599e2
movq 0x28(%rsp), %rax
movq 0x38(%rax), %rax
movq 0x10(%rax), %rax
movq 0x20(%rsp), %rcx
subq $0x1, %rcx
movq (%rax,%rcx,8), %rax
movq 0x8(%rax), %rax
movq %rax, 0x18(%rsp)
jmp 0x1599f3
movq 0x28(%rsp), %rax
movq 0x120(%rax), %rax
movq %rax, 0x18(%rsp)
cmpq $0x3, 0x20(%rsp)
jl 0x159ce3
movq 0x28(%rsp), %rax
movq 0x38(%rax), %rax
movq 0x10(%rax), %rax
movq 0x20(%rsp), %rcx
movq (%rax,%rcx,8), %rax
cmpq $0x1d4, %rax            # imm = 0x1D4
je 0x159ce3
movq 0x28(%rsp), %rax
movq 0x38(%rax), %rax
movq 0x10(%rax), %rax
movq 0x20(%rsp), %rcx
movq (%rax,%rcx,8), %rax
cmpq $0x1d8, %rax            # imm = 0x1D8
je 0x159ce3
movq 0x18(%rsp), %rax
movq 0x28(%rsp), %rcx
cmpq 0x17b0(%rcx), %rax
je 0x159ce3
movq 0x18(%rsp), %rax
movq 0x28(%rsp), %rcx
cmpq 0x17c0(%rcx), %rax
je 0x159ce3
movq 0x18(%rsp), %rax
movq 0x28(%rsp), %rcx
cmpq 0x17c8(%rcx), %rax
je 0x159ce3
movq 0x18(%rsp), %rax
movq 0x28(%rsp), %rcx
cmpq 0x17d0(%rcx), %rax
je 0x159ce3
movq 0x28(%rsp), %rax
movq 0x8(%rax), %rax
movzbl (%rax), %eax
cmpl $0x1c, %eax
je 0x159ac5
movq 0x28(%rsp), %rax
movq 0x110(%rax), %rcx
movq 0x28(%rsp), %rax
movq %rcx, 0x8(%rax)
movq 0x28(%rsp), %rax
movq 0x20(%rax), %rax
movq 0x8(%rax), %rax
movq %rax, 0x10(%rsp)
movq 0x10(%rsp), %rax
cmpq $0x0, 0x20(%rax)
je 0x159afa
movq 0x28(%rsp), %rax
movq 0x8(%rax), %rax
movq 0x28(%rsp), %rcx
cmpq 0x110(%rcx), %rax
jne 0x159b0a
movq 0x10(%rsp), %rax
movq 0x10(%rax), %rax
movq %rax, 0x8(%rsp)
jmp 0x159b1e
movq 0x28(%rsp), %rdi
movq 0x10(%rsp), %rsi
callq 0xfc80
movq %rax, 0x8(%rsp)
movq 0x8(%rsp), %rax
movzbl (%rax), %eax
cmpl $0x20, %eax
jne 0x159b3e
movq 0x8(%rsp), %rax
movq 0x10(%rax), %rcx
movq 0x28(%rsp), %rax
movq %rcx, (%rax)
jmp 0x159b52
movq 0x28(%rsp), %rax
movq 0x128(%rax), %rcx
movq 0x28(%rsp), %rax
movq %rcx, (%rax)
movq 0x28(%rsp), %rax
movq (%rax), %rax
movzbl (%rax), %eax
cmpl $0x2a, %eax
je 0x159b72
movq 0x28(%rsp), %rax
movq (%rax), %rax
movzbl (%rax), %eax
cmpl $0x2b, %eax
jne 0x159b87
movq 0x28(%rsp), %rax
movq (%rax), %rax
movzwl (%rax), %eax
andl $0x4000, %eax           # imm = 0x4000
cmpl $0x0, %eax
jne 0x159b9d
movq 0x10(%rsp), %rax
movzwl (%rax), %ecx
andl $0xffffbfff, %ecx       # imm = 0xFFFFBFFF
movw %cx, (%rax)
jmp 0x159ce1
movq 0x28(%rsp), %rdi
movq 0x28(%rsp), %rax
movq 0x20(%rax), %rax
movq 0x10(%rax), %rsi
callq 0x44270
movq %rax, %rcx
movq 0x28(%rsp), %rax
movq %rcx, 0x10(%rax)
movq 0x28(%rsp), %rax
movq 0x8(%rax), %rcx
movq 0x28(%rsp), %rax
movq 0x50(%rax), %rax
movq %rcx, 0x8(%rax)
movq 0x28(%rsp), %rax
movq 0x110(%rax), %rcx
movq 0x28(%rsp), %rax
movq 0x50(%rax), %rax
movq %rcx, 0x10(%rax)
movq 0x28(%rsp), %rax
movq 0x50(%rax), %rax
movl $0x1f7, %ecx            # imm = 0x1F7
movq %rcx, 0x18(%rax)
movq 0x28(%rsp), %rax
movq 0x50(%rax), %rcx
addq $0x20, %rcx
movq %rcx, 0x50(%rax)
jmp 0x159c14
jmp 0x159c16
movq 0x28(%rsp), %rax
movq 0x90(%rax), %rax
movq 0x28(%rsp), %rcx
cmpq 0x98(%rcx), %rax
ja 0x159c3a
movq 0x28(%rsp), %rdi
callq 0xc670
movq 0x28(%rsp), %rcx
movq 0x90(%rcx), %rax
movq %rax, %rdx
addq $-0x8, %rdx
movq %rdx, 0x90(%rcx)
movq -0x8(%rax), %rax
movq %rax, (%rsp)
movq (%rsp), %rax
movq $0x20001c, (%rax)       # imm = 0x20001C
movq 0x28(%rsp), %rax
movq 0x250(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x250(%rax)
movq (%rsp), %rax
movq %rcx, 0x18(%rax)
movq (%rsp), %rax
movq $0x0, 0x8(%rax)
movq 0x28(%rsp), %rax
movq (%rax), %rax
movq 0x18(%rax), %rcx
movq (%rsp), %rax
movq %rcx, 0x10(%rax)
movq (%rsp), %rcx
movq 0x28(%rsp), %rax
movq %rcx, 0x8(%rax)
movq 0x28(%rsp), %rax
movq (%rax), %rax
movzbl (%rax), %eax
cmpl $0x2b, %eax
je 0x159ccd
movl $0x6, 0x34(%rsp)
jmp 0x159ceb
movq 0x28(%rsp), %rdi
callq 0x16e8d0
movl $0x1, 0x34(%rsp)
jmp 0x159ceb
jmp 0x159ce3
movl $0x2, 0x34(%rsp)
movl 0x34(%rsp), %eax
addq $0x38, %rsp
retq
nopw %cs:(%rax,%rax)