// File: /workspace/github_c_makefile_star2_O0/voithos[P]awl/src/eval.c
// Function: awlval_call
awlval* awlval_call(awlenv* e, awlval* f, awlval* a) {
    /* calls a function if builtin, or evals a macro, else fills in the
     * corresponding parameters, and lets awlval_eval perform tail
     * call optimization
     */
    if (f->type == AWLVAL_BUILTIN) {
        return f->builtin(e, a);
    }

    int given = a->count;
    int total = f->formals->count;

    /* special case for macros */
    if (f->type == AWLVAL_MACRO) {
        for (int i = 0; i < a->count; i++) {
            /* wrap SExprs and Symbols in QExprs to avoid evaluation */
            if (a->cell[i]->type == AWLVAL_SEXPR) {
                awlval* q = awlval_qexpr();
                q = awlval_add(q, a->cell[i]);
                a->cell[i] = q;
            } else if (a->cell[i]->type == AWLVAL_SYM) {
                awlval* q = awlval_qexpr();
                q = awlval_add(q, a->cell[i]);
                a->cell[i] = q;
            }
        }
    }

    while (a->count) {
        if (f->formals->count == 0) {
            awlval_del(a);
            return awlval_err("%s passed too many arguments; got %i, expected %i",
                    awlval_type_name(f->type), given, total);
        }
        awlval* sym = awlval_pop(f->formals, 0);

        /* special case for variadic functions */
        if (streq(sym->sym, "&")) {
            if (f->formals->count != 1) {
                awlval_del(a);
                return awlval_err("function format invalid; symbol '&' not followed by single symbol");
            }

            awlval* nsym = awlval_pop(f->formals, 0);
            awlval* varargs = builtin_list(e, a);

            if (varargs->type == AWLVAL_ERR) {
                awlval_del(sym);
                awlval_del(nsym);
                return varargs;
            }

            awlenv_put(f->env, nsym, varargs);
            awlval_del(sym);
            awlval_del(nsym);
            break;
        }

        awlval* val = awlval_eval(e, awlval_pop(a, 0));
        if (val->type == AWLVAL_ERR) {
            awlval_del(sym);
            awlval_del(a);
            return val;
        }

        awlenv_put(f->env, sym, val);
        awlval_del(sym);
        awlval_del(val);
    }

    /* Special case for pure variadic function with no arguments */
    if (f->formals->count > 0 &&
            streq(f->formals->cell[0]->sym, "&")) {
        if (f->formals->count != 2) {
            return awlval_err("function format invalid; symbol '&' not followed by single symbol");
        }
        awlval_del(awlval_pop(f->formals, 0));
        awlval* sym = awlval_pop(f->formals, 0);
        awlval* val = awlval_qexpr();

        awlenv_put(f->env, sym, val);
        awlval_del(sym);
        awlval_del(val);
    }

    if (f->formals->count == 0) {
        f->called = true;
    }

    awlval_del(a);

    /* Handle macros -- they are called directly because their output must
     * be evaluated in the enclosing environment */
    if (f->type == AWLVAL_MACRO && f->called) {
        return awlval_eval_macro(f);
    } else {
        return awlval_copy(f);
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x80, %rsp
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq %rdx, -0x20(%rbp)
movq -0x18(%rbp), %rax
cmpl $0x7, (%rax)
jne 0x7d5b
movq -0x18(%rbp), %rax
movq 0x18(%rax), %rax
movq -0x10(%rbp), %rdi
movq -0x20(%rbp), %rsi
callq *%rax
movq %rax, -0x8(%rbp)
jmp 0x80eb
movq -0x20(%rbp), %rax
movl 0x4(%rax), %eax
movl %eax, -0x24(%rbp)
movq -0x18(%rbp), %rax
movq 0x20(%rax), %rax
movl 0x4(%rax), %eax
movl %eax, -0x28(%rbp)
movq -0x18(%rbp), %rax
cmpl $0x9, (%rax)
jne 0x7e4b
movl $0x0, -0x2c(%rbp)
movl -0x2c(%rbp), %eax
movq -0x20(%rbp), %rcx
cmpl 0x4(%rcx), %eax
jge 0x7e49
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rax
movslq -0x2c(%rbp), %rcx
movq (%rax,%rcx,8), %rax
cmpl $0xb, (%rax)
jne 0x7de8
callq 0x16c00
movq %rax, -0x38(%rbp)
movq -0x38(%rbp), %rdi
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rax
movslq -0x2c(%rbp), %rcx
movq (%rax,%rcx,8), %rsi
callq 0x16e70
movq %rax, -0x38(%rbp)
movq -0x38(%rbp), %rdx
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rax
movslq -0x2c(%rbp), %rcx
movq %rdx, (%rax,%rcx,8)
jmp 0x7e39
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rax
movslq -0x2c(%rbp), %rcx
movq (%rax,%rcx,8), %rax
cmpl $0x3, (%rax)
jne 0x7e37
callq 0x16c00
movq %rax, -0x40(%rbp)
movq -0x40(%rbp), %rdi
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rax
movslq -0x2c(%rbp), %rcx
movq (%rax,%rcx,8), %rsi
callq 0x16e70
movq %rax, -0x40(%rbp)
movq -0x40(%rbp), %rdx
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rax
movslq -0x2c(%rbp), %rcx
movq %rdx, (%rax,%rcx,8)
jmp 0x7e39
jmp 0x7e3b
movl -0x2c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x2c(%rbp)
jmp 0x7d87
jmp 0x7e4b
jmp 0x7e4d
movq -0x20(%rbp), %rax
cmpl $0x0, 0x4(%rax)
je 0x7fe7
movq -0x18(%rbp), %rax
movq 0x20(%rax), %rax
cmpl $0x0, 0x4(%rax)
jne 0x7e9d
movq -0x20(%rbp), %rdi
callq 0x16cf0
movq -0x18(%rbp), %rax
movl (%rax), %edi
callq 0x161a0
movq %rax, %rsi
movl -0x24(%rbp), %edx
movl -0x28(%rbp), %ecx
leaq 0x1281a(%rip), %rdi     # 0x1a6a7
movb $0x0, %al
callq 0x16600
movq %rax, -0x8(%rbp)
jmp 0x80eb
movq -0x18(%rbp), %rax
movq 0x20(%rax), %rdi
xorl %esi, %esi
callq 0x174b0
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rax
movq 0x18(%rax), %rdi
leaq 0x1281a(%rip), %rsi     # 0x1a6d9
callq 0x18d50
testb $0x1, %al
jne 0x7ecd
jmp 0x7f70
movq -0x18(%rbp), %rax
movq 0x20(%rax), %rax
cmpl $0x1, 0x4(%rax)
je 0x7efb
movq -0x20(%rbp), %rdi
callq 0x16cf0
leaq 0x127f0(%rip), %rdi     # 0x1a6db
movb $0x0, %al
callq 0x16600
movq %rax, -0x8(%rbp)
jmp 0x80eb
movq -0x18(%rbp), %rax
movq 0x20(%rax), %rdi
xorl %esi, %esi
callq 0x174b0
movq %rax, -0x50(%rbp)
movq -0x10(%rbp), %rdi
movq -0x20(%rbp), %rsi
callq 0x4210
movq %rax, -0x58(%rbp)
movq -0x58(%rbp), %rax
cmpl $0x2, (%rax)
jne 0x7f47
movq -0x48(%rbp), %rdi
callq 0x16cf0
movq -0x50(%rbp), %rdi
callq 0x16cf0
movq -0x58(%rbp), %rax
movq %rax, -0x8(%rbp)
jmp 0x80eb
movq -0x18(%rbp), %rax
movq 0x18(%rax), %rdi
movq -0x50(%rbp), %rsi
movq -0x58(%rbp), %rdx
callq 0x189b0
movq -0x48(%rbp), %rdi
callq 0x16cf0
movq -0x50(%rbp), %rdi
callq 0x16cf0
jmp 0x7fe7
movq -0x10(%rbp), %rax
movq %rax, -0x78(%rbp)
movq -0x20(%rbp), %rdi
xorl %esi, %esi
callq 0x174b0
movq -0x78(%rbp), %rdi
movq %rax, %rsi
callq 0x7770
movq %rax, -0x60(%rbp)
movq -0x60(%rbp), %rax
cmpl $0x2, (%rax)
jne 0x7fbb
movq -0x48(%rbp), %rdi
callq 0x16cf0
movq -0x20(%rbp), %rdi
callq 0x16cf0
movq -0x60(%rbp), %rax
movq %rax, -0x8(%rbp)
jmp 0x80eb
movq -0x18(%rbp), %rax
movq 0x18(%rax), %rdi
movq -0x48(%rbp), %rsi
movq -0x60(%rbp), %rdx
callq 0x189b0
movq -0x48(%rbp), %rdi
callq 0x16cf0
movq -0x60(%rbp), %rdi
callq 0x16cf0
jmp 0x7e4d
movq -0x18(%rbp), %rax
movq 0x20(%rax), %rax
cmpl $0x0, 0x4(%rax)
jle 0x809d
movq -0x18(%rbp), %rax
movq 0x20(%rax), %rax
movq 0x8(%rax), %rax
movq (%rax), %rax
movq 0x18(%rax), %rdi
leaq 0x126c6(%rip), %rsi     # 0x1a6d9
callq 0x18d50
testb $0x1, %al
jne 0x801e
jmp 0x809d
movq -0x18(%rbp), %rax
movq 0x20(%rax), %rax
cmpl $0x2, 0x4(%rax)
je 0x8043
leaq 0x126a8(%rip), %rdi     # 0x1a6db
movb $0x0, %al
callq 0x16600
movq %rax, -0x8(%rbp)
jmp 0x80eb
movq -0x18(%rbp), %rax
movq 0x20(%rax), %rdi
xorl %esi, %esi
callq 0x174b0
movq %rax, %rdi
callq 0x16cf0
movq -0x18(%rbp), %rax
movq 0x20(%rax), %rdi
xorl %esi, %esi
callq 0x174b0
movq %rax, -0x68(%rbp)
callq 0x16c00
movq %rax, -0x70(%rbp)
movq -0x18(%rbp), %rax
movq 0x18(%rax), %rdi
movq -0x68(%rbp), %rsi
movq -0x70(%rbp), %rdx
callq 0x189b0
movq -0x68(%rbp), %rdi
callq 0x16cf0
movq -0x70(%rbp), %rdi
callq 0x16cf0
movq -0x18(%rbp), %rax
movq 0x20(%rax), %rax
cmpl $0x0, 0x4(%rax)
jne 0x80b3
movq -0x18(%rbp), %rax
movb $0x1, 0x30(%rax)
movq -0x20(%rbp), %rdi
callq 0x16cf0
movq -0x18(%rbp), %rax
cmpl $0x9, (%rax)
jne 0x80de
movq -0x18(%rbp), %rax
testb $0x1, 0x30(%rax)
je 0x80de
movq -0x18(%rbp), %rdi
callq 0x8100
movq %rax, -0x8(%rbp)
jmp 0x80eb
movq -0x18(%rbp), %rdi
callq 0x171d0
movq %rax, -0x8(%rbp)
movq -0x8(%rbp), %rax
addq $0x80, %rsp
popq %rbp
retq
nopl (%rax,%rax)