// File: /workspace/github_c_makefile_star2_O0/theandrew168[P]squeaky/src/mce.c
// Function: mce_eval
struct value*
mce_eval(struct vm* vm, struct value* exp, struct value* env)
{
tailcall:

    if (is_self_evaluating(exp)) {
        return exp;
    } else if (is_variable(exp)) {
        return env_lookup(vm, exp, env);
    } else if (is_quoted(exp)) {
        return text_of_quotation(exp);
    } else if (is_assignment(exp)) {
        return eval_assignment(vm, exp, env);
    } else if (is_definition(exp)) {
        return eval_definition(vm, exp, env);
    } else if (is_if(exp)) {
        exp = eval_if(vm, exp, env);
        goto tailcall;
    } else if (is_environment(exp)) {
        return env;
    } else if (is_load(exp)) {
        return load(vm, load_args(exp), env);
    } else if (is_gc(exp)) {
        vm_gc(vm, env);
        return vm_make_empty_list(vm);
    } else if (is_lambda(exp)) {
        // TODO: check for the three different lambda forms:
        // (lambda (x) (* x x))
        // (lambda x x)
        // (lambda (x . rest) (append x rest))
        return vm_make_lambda(vm, lambda_params(exp), lambda_body(exp), env);
    } else if (is_application(exp)) {
        // 'apply' is evalutaed inline for TCO
        struct value* proc = mce_eval(vm, operator(exp), env);
        struct value* args = list_of_values(vm, operands(exp), env);

        // handle builtin 'eval' specifically for TCO
        if (is_primitive_proc(proc) && proc->as.builtin == mce_builtin_eval) {
            ASSERT_ARITY("eval", args, 2);
            ASSERT_TYPE("eval", args, 1, VALUE_PAIR);
            env = eval_env(args);
            exp = eval_exp(args);
            goto tailcall;
        }

        // handle builtin 'apply' specifically for TCO
        if (is_primitive_proc(proc) && proc->as.builtin == mce_builtin_apply) {
            proc = apply_operator(args);
            args = apply_operands(args);
        }

        if (is_primitive_proc(proc)) {
            return proc->as.builtin(vm, args);
        } else if (is_compound_proc(proc)) {
            // evaluate the lambda's body in the current stack frame (for TCO)
            env = env_extend(vm, proc->as.lambda.params, args, proc->as.lambda.env);
            exp = proc->as.lambda.body;
            while (!is_last_exp(exp)) {
                mce_eval(vm, first_exp(exp), env);
                exp = rest_exps(exp);
            }
            exp = first_exp(exp);
            goto tailcall;
        } else {
            fprintf(stderr, "runtime error (invalid proc) at: TODO\n");
            exit(EXIT_FAILURE);
        }
    }

    fprintf(stderr, "runtime error (invalid expr) at: TODO\n");
    exit(EXIT_FAILURE);
}

// 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 $0x2, (%rax)
je 0x679b
movq -0x18(%rbp), %rax
cmpl $0x3, (%rax)
je 0x679b
movq -0x18(%rbp), %rax
cmpl $0x4, (%rax)
je 0x679b
movq -0x18(%rbp), %rax
cmpl $0x5, (%rax)
jne 0x67a8
movq -0x18(%rbp), %rax
movq %rax, -0x8(%rbp)
jmp 0x6c4b
movq -0x18(%rbp), %rax
cmpl $0x6, (%rax)
jne 0x67cb
movq -0x10(%rbp), %rdi
movq -0x18(%rbp), %rsi
movq -0x20(%rbp), %rdx
callq 0x5f10
movq %rax, -0x8(%rbp)
jmp 0x6c4b
movq -0x18(%rbp), %rdi
leaq 0x44ac(%rip), %rsi      # 0xac82
callq 0x6c60
testb $0x1, %al
jne 0x67e1
jmp 0x67f3
movq -0x18(%rbp), %rdi
callq 0x6cb0
movq %rax, -0x8(%rbp)
jmp 0x6c4b
movq -0x18(%rbp), %rdi
leaq 0x418f(%rip), %rsi      # 0xa98d
callq 0x6c60
testb $0x1, %al
jne 0x6809
jmp 0x6823
movq -0x10(%rbp), %rdi
movq -0x18(%rbp), %rsi
movq -0x20(%rbp), %rdx
callq 0x6cf0
movq %rax, -0x8(%rbp)
jmp 0x6c4b
movq -0x18(%rbp), %rdi
leaq 0x3e58(%rip), %rsi      # 0xa686
callq 0x6c60
testb $0x1, %al
jne 0x6839
jmp 0x6853
movq -0x10(%rbp), %rdi
movq -0x18(%rbp), %rsi
movq -0x20(%rbp), %rdx
callq 0x6d70
movq %rax, -0x8(%rbp)
jmp 0x6c4b
movq -0x18(%rbp), %rdi
leaq 0x4134(%rip), %rsi      # 0xa992
callq 0x6c60
testb $0x1, %al
jne 0x6869
jmp 0x6883
movq -0x10(%rbp), %rdi
movq -0x18(%rbp), %rsi
movq -0x20(%rbp), %rdx
callq 0x6ec0
movq %rax, -0x18(%rbp)
jmp 0x6777
movq -0x18(%rbp), %rdi
leaq 0x4107(%rip), %rsi      # 0xa995
callq 0x6c60
testb $0x1, %al
jne 0x68c1
movq -0x18(%rbp), %rdi
leaq 0x410d(%rip), %rsi      # 0xa9af
callq 0x6c60
testb $0x1, %al
jne 0x68c1
movq -0x18(%rbp), %rdi
leaq 0x410a(%rip), %rsi      # 0xa9c0
callq 0x6c60
testb $0x1, %al
jne 0x68c1
jmp 0x68ce
movq -0x20(%rbp), %rax
movq %rax, -0x8(%rbp)
jmp 0x6c4b
movq -0x18(%rbp), %rdi
leaq 0x3917(%rip), %rsi      # 0xa1f0
callq 0x6c60
testb $0x1, %al
jne 0x68e4
jmp 0x690e
movq -0x10(%rbp), %rax
movq %rax, -0x38(%rbp)
movq -0x18(%rbp), %rdi
callq 0x6620
movq -0x38(%rbp), %rdi
movq %rax, %rsi
movq -0x20(%rbp), %rdx
callq 0x6f90
movq %rax, -0x8(%rbp)
jmp 0x6c4b
movq -0x18(%rbp), %rdi
leaq 0x40bf(%rip), %rsi      # 0xa9d8
callq 0x6c60
testb $0x1, %al
jne 0x6924
jmp 0x6943
movq -0x10(%rbp), %rdi
movq -0x20(%rbp), %rsi
callq 0x8bf0
movq -0x10(%rbp), %rdi
callq 0x8dc0
movq %rax, -0x8(%rbp)
jmp 0x6c4b
movq -0x18(%rbp), %rdi
leaq 0x408d(%rip), %rsi      # 0xa9db
callq 0x6c60
testb $0x1, %al
jne 0x6959
jmp 0x69a4
movq -0x10(%rbp), %rax
movq %rax, -0x48(%rbp)
movq -0x18(%rbp), %rdi
callq 0x6620
movq %rax, %rdi
callq 0x6710
movq %rax, -0x40(%rbp)
movq -0x18(%rbp), %rdi
callq 0x6620
movq %rax, %rdi
callq 0x6620
movq -0x48(%rbp), %rdi
movq -0x40(%rbp), %rsi
movq %rax, %rdx
movq -0x20(%rbp), %rcx
callq 0x91f0
movq %rax, -0x8(%rbp)
jmp 0x6c4b
movq -0x18(%rbp), %rax
cmpl $0x7, (%rax)
jne 0x6c15
movq -0x10(%rbp), %rax
movq %rax, -0x58(%rbp)
movq -0x18(%rbp), %rdi
callq 0x6710
movq -0x58(%rbp), %rdi
movq %rax, %rsi
movq -0x20(%rbp), %rdx
callq 0x6760
movq %rax, -0x28(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0x50(%rbp)
movq -0x18(%rbp), %rdi
callq 0x6620
movq -0x50(%rbp), %rdi
movq %rax, %rsi
movq -0x20(%rbp), %rdx
callq 0x7120
movq %rax, -0x30(%rbp)
movq -0x28(%rbp), %rax
cmpl $0x8, (%rax)
jne 0x6b08
movq -0x28(%rbp), %rax
leaq 0x7ad(%rip), %rcx       # 0x71c0
cmpq %rcx, 0x10(%rax)
jne 0x6b08
movq -0x30(%rbp), %rdi
callq 0x65c0
cmpq $0x2, %rax
je 0x6a6e
movq 0x75ad(%rip), %rax      # 0xdfe0
movq (%rax), %rax
movq %rax, -0x60(%rbp)
movq -0x30(%rbp), %rdi
callq 0x65c0
movq -0x60(%rbp), %rdi
movq %rax, %r8
leaq 0x37b3(%rip), %rsi      # 0xa204
leaq 0x365a(%rip), %rdx      # 0xa0b2
movl $0x2, %ecx
movb $0x0, %al
callq 0x1200
movl $0x1, %edi
callq 0x11a0
movq -0x30(%rbp), %rdi
movl $0x1, %esi
callq 0x6670
cmpl $0x7, (%rax)
je 0x6ae1
movq 0x7558(%rip), %rax      # 0xdfe0
movq (%rax), %rax
movq %rax, -0x70(%rbp)
movl $0x7, %edi
callq 0x86d0
movq %rax, -0x68(%rbp)
movq -0x30(%rbp), %rdi
movl $0x1, %esi
callq 0x6670
movl (%rax), %edi
callq 0x86d0
movq -0x70(%rbp), %rdi
movq -0x68(%rbp), %r8
movq %rax, %r9
leaq 0x37bf(%rip), %rsi      # 0xa283
leaq 0x35e7(%rip), %rdx      # 0xa0b2
movl $0x1, %ecx
movb $0x0, %al
callq 0x1200
movl $0x1, %edi
callq 0x11a0
movq -0x30(%rbp), %rdi
callq 0x6620
movq %rax, %rdi
callq 0x6710
movq %rax, -0x20(%rbp)
movq -0x30(%rbp), %rdi
callq 0x6710
movq %rax, -0x18(%rbp)
jmp 0x6777
movq -0x28(%rbp), %rax
cmpl $0x8, (%rax)
jne 0x6b3c
movq -0x28(%rbp), %rax
leaq 0x6e4(%rip), %rcx       # 0x7200
cmpq %rcx, 0x10(%rax)
jne 0x6b3c
movq -0x30(%rbp), %rdi
callq 0x6710
movq %rax, -0x28(%rbp)
movq -0x30(%rbp), %rdi
callq 0x6620
movq %rax, -0x30(%rbp)
movq -0x28(%rbp), %rax
cmpl $0x8, (%rax)
jne 0x6b60
movq -0x28(%rbp), %rax
movq 0x10(%rax), %rax
movq -0x10(%rbp), %rdi
movq -0x30(%rbp), %rsi
callq *%rax
movq %rax, -0x8(%rbp)
jmp 0x6c4b
movq -0x28(%rbp), %rax
cmpl $0x9, (%rax)
jne 0x6bf3
movq -0x10(%rbp), %rdi
movq -0x28(%rbp), %rax
movq 0x10(%rax), %rsi
movq -0x30(%rbp), %rdx
movq -0x28(%rbp), %rax
movq 0x20(%rax), %rcx
callq 0x5e70
movq %rax, -0x20(%rbp)
movq -0x28(%rbp), %rax
movq 0x18(%rax), %rax
movq %rax, -0x18(%rbp)
movq -0x18(%rbp), %rdi
callq 0x6620
cmpl $0x1, (%rax)
sete %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x6bb1
jmp 0x6be1
movq -0x10(%rbp), %rax
movq %rax, -0x78(%rbp)
movq -0x18(%rbp), %rdi
callq 0x6710
movq -0x78(%rbp), %rdi
movq %rax, %rsi
movq -0x20(%rbp), %rdx
callq 0x6760
movq -0x18(%rbp), %rdi
callq 0x6620
movq %rax, -0x18(%rbp)
jmp 0x6b9a
movq -0x18(%rbp), %rdi
callq 0x6710
movq %rax, -0x18(%rbp)
jmp 0x6777
movq 0x73e6(%rip), %rax      # 0xdfe0
movq (%rax), %rdi
leaq 0x3dde(%rip), %rsi      # 0xa9e2
movb $0x0, %al
callq 0x1200
movl $0x1, %edi
callq 0x11a0
jmp 0x6c17
jmp 0x6c19
jmp 0x6c1b
jmp 0x6c1d
jmp 0x6c1f
jmp 0x6c21
jmp 0x6c23
jmp 0x6c25
jmp 0x6c27
jmp 0x6c29
movq 0x73b0(%rip), %rax      # 0xdfe0
movq (%rax), %rdi
leaq 0x3dcf(%rip), %rsi      # 0xaa09
movb $0x0, %al
callq 0x1200
movl $0x1, %edi
callq 0x11a0
movq -0x8(%rbp), %rax
addq $0x80, %rsp
popq %rbp
retq
nopl (%rax,%rax)