// File: /workspace/github_c_makefile_star2_O0/jiribenes[P]scheme/src/vm.c
// Function: eval
value_t eval(vm_t *vm, env_t *env, value_t val) {
    if (IS_VAL(val) || IS_STRING(val) || IS_PROCEDURE(val) || IS_VECTOR(val) ||
        IS_ENV(val)) {
        // These values are self evaluating
        return val;
    } else if (IS_SYMBOL(val)) {
        // This is a variable
        symbol_t *sym = AS_SYMBOL(val);
        value_t result = find(env, sym);
        if (IS_UNDEFINED(result)) {
            error_runtime(vm, "|eval: Can't eval %s - symbol not bound!",
                          sym->name);
        }
        return result;
    } else if (IS_CONS(val)) {
        // It's a function application
        value_t expanded = expand(vm, env, val);

        if (!IS_EQ(expanded, val)) {
            // macros encountered and expanded, now eval the expanded value
            return eval(vm, env, expanded);
        }

        cons_t *cons = AS_CONS(val);
        value_t fn = eval(vm, env, cons->car);
        value_t args = cons->cdr;

        if (!IS_PROCEDURE(fn)) {
            error_runtime(vm, "|eval: Car of eval'd cons is not a procedure!");
        }
        return apply(vm, env, fn, args);
    }

    // This should be an assert
    error_runtime(vm, "|eval: Cannot eval - unknown value type!");
    return NIL_VAL;
}

// Assembly:
subq $0x58, %rsp
movq %rdi, 0x48(%rsp)
movq %rsi, 0x40(%rsp)
movq %rdx, 0x38(%rsp)
movabsq $-0x4000000000000, %rax # imm = 0xFFFC000000000000
andq 0x38(%rsp), %rax
movabsq $-0x4000000000000, %rcx # imm = 0xFFFC000000000000
cmpq %rcx, %rax
jne 0x8642
movq 0x38(%rsp), %rdi
movl $0x1, %esi
callq 0x7e80
testb $0x1, %al
jne 0x8642
movq 0x38(%rsp), %rdi
movl $0x3, %esi
callq 0x7e80
testb $0x1, %al
jne 0x8642
movq 0x38(%rsp), %rdi
movl $0x4, %esi
callq 0x7e80
testb $0x1, %al
jne 0x8642
movq 0x38(%rsp), %rdi
movl $0x6, %esi
callq 0x7e80
testb $0x1, %al
jne 0x8642
movq 0x38(%rsp), %rdi
movl $0x7, %esi
callq 0x7e80
testb $0x1, %al
jne 0x8642
jmp 0x8651
movq 0x38(%rsp), %rax
movq %rax, 0x50(%rsp)
jmp 0x87e7
movq 0x38(%rsp), %rdi
movl $0x2, %esi
callq 0x7e80
testb $0x1, %al
jne 0x8666
jmp 0x86ca
movabsq $0x3ffffffffffff, %rax  # imm = 0x3FFFFFFFFFFFF
andq 0x38(%rsp), %rax
movq %rax, 0x30(%rsp)
movq 0x40(%rsp), %rdi
movq 0x30(%rsp), %rsi
callq 0x8300
movq %rax, 0x28(%rsp)
movabsq $0x7ffc000000000004, %rax # imm = 0x7FFC000000000004
cmpq %rax, 0x28(%rsp)
jne 0x86bb
movq 0x48(%rsp), %rdi
movq 0x30(%rsp), %rdx
addq $0x20, %rdx
leaq 0x24e2(%rip), %rsi      # 0xab96
movb $0x0, %al
callq 0x73a0
movq 0x28(%rsp), %rax
movq %rax, 0x50(%rsp)
jmp 0x87e7
movq 0x38(%rsp), %rdi
xorl %esi, %esi
callq 0x7e80
testb $0x1, %al
jne 0x86df
jmp 0x87c1
movq 0x48(%rsp), %rdi
movq 0x40(%rsp), %rsi
movq 0x38(%rsp), %rdx
callq 0x8800
movq %rax, 0x20(%rsp)
movq 0x20(%rsp), %rdi
movq 0x38(%rsp), %rsi
callq 0x8940
testb $0x1, %al
jne 0x8729
movq 0x48(%rsp), %rdi
movq 0x40(%rsp), %rsi
movq 0x20(%rsp), %rdx
callq 0x85b0
movq %rax, 0x50(%rsp)
jmp 0x87e7
movabsq $0x3ffffffffffff, %rax  # imm = 0x3FFFFFFFFFFFF
andq 0x38(%rsp), %rax
movq %rax, 0x18(%rsp)
movq 0x48(%rsp), %rdi
movq 0x40(%rsp), %rsi
movq 0x18(%rsp), %rax
movq 0x10(%rax), %rdx
callq 0x85b0
movq %rax, 0x10(%rsp)
movq 0x18(%rsp), %rax
movq 0x18(%rax), %rax
movq %rax, 0x8(%rsp)
movq 0x10(%rsp), %rdi
movl $0x3, %esi
callq 0x7e80
testb $0x1, %al
jne 0x87a1
movq 0x10(%rsp), %rdi
movl $0x4, %esi
callq 0x7e80
testb $0x1, %al
jne 0x87a1
movq 0x48(%rsp), %rdi
leaq 0x2425(%rip), %rsi      # 0xabbf
movb $0x0, %al
callq 0x73a0
movq 0x48(%rsp), %rdi
movq 0x40(%rsp), %rsi
movq 0x10(%rsp), %rdx
movq 0x8(%rsp), %rcx
callq 0x7f70
movq %rax, 0x50(%rsp)
jmp 0x87e7
jmp 0x87c3
jmp 0x87c5
movq 0x48(%rsp), %rdi
leaq 0x241c(%rip), %rsi      # 0xabed
movb $0x0, %al
callq 0x73a0
movabsq $0x7ffc000000000001, %rax # imm = 0x7FFC000000000001
movq %rax, 0x50(%rsp)
movq 0x50(%rsp), %rax
addq $0x58, %rsp
retq
nopw %cs:(%rax,%rax)