// File: /workspace/github_cpp_makefile_star2_O2/pfnet-research[P]pml/src/evaluator.cpp
// Function: evaluator::eval(std::shared_ptr<ast::expr_t>, environment_t<ast::expr_t> const&)
ptr<ast::expr_t> eval(ptr<ast::expr_t> e, environment_t const& env) {
    using namespace ast;
    switch (e->kind()) {
    case expr_kind_t::Let: {
        auto& let_expr = cast<let_expr_t>(*e);
        auto init = eval(let_expr.init, env);
        auto new_env = env.append(let_expr.name, init);
        return eval(let_expr.body, new_env);
        }
    case expr_kind_t::LetFun: {
        auto& letfun_expr = cast<letfun_expr_t>(*e);
        auto fun = make<ast::fun_expr_t>(letfun_expr.type, letfun_expr.init);
        auto new_env = env.append(letfun_expr.name, fun);
        return eval(letfun_expr.body, new_env);
        }
    case expr_kind_t::If: {
        auto& if_expr = cast<if_expr_t>(*e);
        auto cond_val = eval(if_expr.cond_expr, env);
        if (cond_val->kind() != ast::expr_kind_t::Bool) {
            std::cerr << "eval error: if-condition must be boolean " + ast::to_debug_string(*cond_val) << std::endl;
            assert(false);
            return nullptr;
        } else if (cast<bool_expr_t>(*cond_val).b == true) {
            return eval(if_expr.true_expr, env);
        } {
            return eval(if_expr.false_expr, env);
        }
        }
    case expr_kind_t::Eq:  case expr_kind_t::Neq:
    case expr_kind_t::Leq:  case expr_kind_t::Geq:
    case expr_kind_t::Add: case expr_kind_t::Sub:
    case expr_kind_t::Mul: case expr_kind_t::Div:
    case expr_kind_t::And: case expr_kind_t::Or: {
            auto& binop_expr = cast<binop_expr_t>(*e);
            return calc_int_binop(
                    *eval(binop_expr.lhs, env),
                    *eval(binop_expr.rhs, env),
                    e->kind());
        }
    case expr_kind_t::Neg: {
            auto val = eval(cast<neg_expr_t>(*e).inner, env);
            return make<bool_expr_t>(!cast<bool_expr_t>(*val).b);
        }
    case expr_kind_t::Int: case expr_kind_t::Bool: case expr_kind_t::Fun:
        return e;
    case expr_kind_t::Var:
        return env.lookup(cast<var_expr_t>(*e).name);
    case expr_kind_t::App: {
            auto const& app_expr = cast<app_expr_t>(*e);
            auto f_ = eval(app_expr.f, env);
            if (f_->kind() != ast::expr_kind_t::Fun)
                throw std::logic_error{"arienai"};
            auto f = cast<fun_expr_t>(*f_);
            if (f.type.args.size() != app_expr.args.size())
                throw std::logic_error{"arienai"};
            environment_t new_env = env;
            for (size_t i=0; i<app_expr.args.size(); ++i) {
                new_env = new_env.append(
                        f.type.args[i].name,
                        eval(app_expr.args[i], env));
            }
            return eval(f.body, new_env);
        }
    case expr_kind_t::Rand: {
            auto& rand_expr = cast<rand_expr_t>(*e);
            int start = rand_expr.start;
            int end = rand_expr.end;
            return make<int_expr_t>(std::rand() % (end - start + 1) + start);
        }
    case expr_kind_t::Typed:
        return eval(cast<typed_expr_t>(*e).expr, env);
    }
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x1c8, %rsp            # imm = 0x1C8
movq %rdx, %rbp
movq %rsi, %r15
movq %rdi, %r13
movq (%rsi), %rdi
movq (%rdi), %rax
callq *(%rax)
movl %eax, %eax
leaq 0x2b294(%rip), %rcx     # 0x36228
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq (%r15), %rdi
leaq 0x4ead1(%rip), %rsi     # 0x59a78
leaq 0x4ec6a(%rip), %rdx     # 0x59c18
xorl %ecx, %ecx
callq 0x9330
testq %rax, %rax
je 0xb691
movq %rax, %r12
leaq 0x8(%rax), %rsi
leaq 0x158(%rsp), %rbx
movq %rbx, %rdi
callq 0xbde0
leaq 0x50(%rsp), %rdi
movq %rbx, %rsi
movq %rbp, %rdx
callq 0xaf69
movq 0x50(%rsp), %rbx
addq $0x18, %r12
leaq 0x148(%rsp), %r14
movq %r14, %rdi
movq %r12, %rsi
callq 0xbde0
movq %rsp, %rdi
movq %r14, %rsi
movq %rbp, %rdx
callq 0xaf69
movq (%rsp), %r14
movq (%r15), %rdi
movq (%rdi), %rax
callq *(%rax)
movq %r13, %rdi
movq %rbx, %rsi
movq %r14, %rdx
movl %eax, %ecx
callq 0xac88
leaq 0x8(%rsp), %rdi
callq 0xa248
leaq 0x150(%rsp), %rdi
callq 0xa248
leaq 0x58(%rsp), %rdi
callq 0xa248
leaq 0x160(%rsp), %rdi
callq 0xa248
movq %r13, %rax
addq $0x1c8, %rsp            # imm = 0x1C8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movups (%r15), %xmm0
andq $0x0, 0x8(%r15)
movups %xmm0, (%r13)
andq $0x0, (%r15)
jmp 0xb059
movq (%r15), %rdi
leaq 0x4e9ec(%rip), %rsi     # 0x59a78
leaq 0x4ebe5(%rip), %rdx     # 0x59c78
xorl %ecx, %ecx
callq 0x9330
testq %rax, %rax
je 0xb691
movl 0x8(%rax), %ebx
movl 0xc(%rax), %ebp
callq 0x90b0
subl %ebx, %ebp
incl %ebp
cltd
idivl %ebp
addl %ebx, %edx
movq %rsp, %rsi
movl %edx, (%rsi)
leaq 0x50(%rsp), %rdi
callq 0xbc7c
leaq 0x58(%rsp), %rdi
movaps -0x8(%rdi), %xmm0
andq $0x0, (%rdi)
movups %xmm0, (%r13)
andq $0x0, -0x8(%rdi)
jmp 0xb054
movq (%r15), %rdi
leaq 0x4e98c(%rip), %rsi     # 0x59a78
leaq 0x4eb0d(%rip), %rdx     # 0x59c00
xorl %ecx, %ecx
callq 0x9330
testq %rax, %rax
je 0xb691
movq %rax, %rbx
leaq 0x190(%rsp), %r15
leaq 0x8(%rax), %rsi
leaq 0x188(%rsp), %r14
movq %r14, %rdi
callq 0xbde0
leaq 0x28(%rsp), %rdi
movq %r14, %rsi
movq %rbp, %rdx
callq 0xaf69
leaq 0x30(%rsp), %r15
leaq 0x190(%rsp), %rdi
callq 0xa248
movq -0x8(%r15), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0x12, %eax
jne 0xb696
movq 0x28(%rsp), %rdi
callq 0xb8eb
cmpb $0x1, 0x8(%rax)
jne 0xb655
addq $0x18, %rbx
leaq 0x178(%rsp), %r14
movq %r14, %rdi
movq %rbx, %rsi
callq 0xbde0
movq %r13, %rdi
movq %r14, %rsi
movq %rbp, %rdx
callq 0xaf69
leaq 0x180(%rsp), %rdi
jmp 0xb682
movq (%r15), %rdi
leaq 0x4e8d2(%rip), %rsi     # 0x59a78
leaq 0x4eab3(%rip), %rdx     # 0x59c60
xorl %ecx, %ecx
callq 0x9330
testq %rax, %rax
je 0xb691
movq %rax, %r12
leaq 0x130(%rsp), %r14
leaq 0x8(%rax), %rsi
leaq 0x128(%rsp), %rbx
movq %rbx, %rdi
callq 0xbde0
leaq 0xd8(%rsp), %rdi
movq %rbx, %rsi
movq %rbp, %rdx
callq 0xaf69
leaq 0xe0(%rsp), %rbx
leaq 0x130(%rsp), %rdi
callq 0xa248
movq -0x8(%rbx), %rdi
movq (%rdi), %rax
movq %rbx, 0x40(%rsp)
callq *(%rax)
cmpl $0x13, %eax
jne 0xb6ff
movq 0xd8(%rsp), %rdi
leaq 0x4e84e(%rip), %rsi     # 0x59a78
leaq 0x4e9b7(%rip), %rdx     # 0x59be8
xorl %ecx, %ecx
callq 0x9330
testq %rax, %rax
je 0xb731
leaq 0x50(%rsp), %rdi
movq %rax, %rsi
callq 0xba92
movq 0x60(%rsp), %rax
subq 0x58(%rsp), %rax
pushq $0x38
popq %rcx
cqto
idivq %rcx
movq 0x20(%r12), %rcx
subq 0x18(%r12), %rcx
sarq $0x4, %rcx
cmpq %rcx, %rax
jne 0xb736
movq %r13, 0xb8(%rsp)
movq %rsp, %rdi
movq %rbp, 0xc8(%rsp)
movq %rbp, %rsi
callq 0xc2ca
movq $0x0, 0x48(%rsp)
leaq 0x118(%rsp), %r15
leaq 0x28(%rsp), %rbx
movq %rsp, %rbp
xorl %ecx, %ecx
xorl %edx, %edx
movq %r12, 0xc0(%rsp)
movq 0x18(%r12), %rsi
movq 0x20(%r12), %rax
subq %rsi, %rax
sarq $0x4, %rax
cmpq %rax, %rdx
jae 0xb5fb
movq %rdx, 0xd0(%rsp)
movq 0x58(%rsp), %r14
movq %rcx, %r13
addq %rcx, %rsi
leaq 0x108(%rsp), %r12
movq %r12, %rdi
callq 0xbde0
movq %r15, %rdi
movq %r12, %rsi
movq 0xc8(%rsp), %rdx
callq 0xaf69
movq 0x48(%rsp), %r12
addq %r12, %r14
movq %rbx, %rdi
movq %rbp, %rsi
movq %r14, %rdx
movq %r15, %rcx
callq 0xb9a0
movq %rbp, %rdi
movq %rbx, %rsi
callq 0xc492
movq %rbx, %rdi
callq 0xbe14
leaq 0x120(%rsp), %rdi
callq 0xa248
leaq 0x110(%rsp), %rdi
callq 0xa248
movq 0xd0(%rsp), %rdx
incq %rdx
movq %r13, %rcx
addq $0x10, %rcx
addq $0x38, %r12
movq %r12, 0x48(%rsp)
movq 0xc0(%rsp), %r12
jmp 0xb2b7
movq (%r15), %rdi
leaq 0x4e6f9(%rip), %rsi     # 0x59a78
leaq 0x4e7ba(%rip), %rdx     # 0x59b40
xorl %ecx, %ecx
callq 0x9330
testq %rax, %rax
je 0xb691
movq %rax, %rbx
leaq 0x1c0(%rsp), %r15
leaq 0x28(%rax), %rsi
leaq 0x1b8(%rsp), %r14
movq %r14, %rdi
callq 0xbde0
movq %rsp, %rdi
movq %r14, %rsi
movq %rbp, %rdx
callq 0xaf69
leaq 0x1c0(%rsp), %rdi
callq 0xa248
leaq 0x8(%rbx), %rdx
leaq 0x50(%rsp), %rdi
movq %rsp, %rcx
movq %rbp, %rsi
callq 0xb9a0
addq $0x38, %rbx
leaq 0x1a8(%rsp), %r14
movq %r14, %rdi
movq %rbx, %rsi
callq 0xbde0
leaq 0x50(%rsp), %rdx
movq %r13, %rdi
movq %r14, %rsi
callq 0xaf69
leaq 0x1b0(%rsp), %rdi
jmp 0xb4b2
movq (%r15), %rdi
leaq 0x4e656(%rip), %rsi     # 0x59a78
leaq 0x4e72f(%rip), %rdx     # 0x59b58
xorl %ecx, %ecx
callq 0x9330
testq %rax, %rax
je 0xb691
movq %rax, %rbx
leaq 0x28(%rax), %rsi
leaq 0x78(%rax), %rdx
movq %rsp, %r14
movq %r14, %rdi
callq 0xbe82
leaq 0x8(%rbx), %r15
leaq 0x28(%rsp), %r12
movq %r12, %rdi
movq %r14, %rsi
callq 0xd3bc
leaq 0x50(%rsp), %rdi
movq %rbp, %rsi
movq %r15, %rdx
movq %r12, %rcx
callq 0xb9a0
leaq 0x30(%rsp), %rdi
callq 0xa248
addq $0x88, %rbx
leaq 0x198(%rsp), %r14
movq %r14, %rdi
movq %rbx, %rsi
callq 0xbde0
leaq 0x50(%rsp), %rdx
movq %r13, %rdi
movq %r14, %rsi
callq 0xaf69
leaq 0x1a0(%rsp), %rdi
callq 0xa248
leaq 0x50(%rsp), %rdi
callq 0xbe14
leaq 0x8(%rsp), %rdi
jmp 0xb054
movq (%r15), %rdi
leaq 0x4e5a3(%rip), %rsi     # 0x59a78
leaq 0x4e7b4(%rip), %rdx     # 0x59c90
xorl %ecx, %ecx
callq 0x9330
testq %rax, %rax
je 0xb691
addq $0x8, %rax
leaq 0xe8(%rsp), %rbx
movq %rbx, %rdi
movq %rax, %rsi
callq 0xbde0
movq %r13, %rdi
movq %rbx, %rsi
movq %rbp, %rdx
callq 0xaf69
leaq 0xf0(%rsp), %rdi
jmp 0xb054
movq (%r15), %rdi
leaq 0x4e550(%rip), %rsi     # 0x59a78
leaq 0x4e719(%rip), %rdx     # 0x59c48
xorl %ecx, %ecx
callq 0x9330
testq %rax, %rax
je 0xb691
addq $0x8, %rax
movq %r13, %rdi
movq %rbp, %rsi
movq %rax, %rdx
callq 0xba16
jmp 0xb059
movq (%r15), %rdi
leaq 0x4e518(%rip), %rsi     # 0x59a78
leaq 0x4e6c9(%rip), %rdx     # 0x59c30
xorl %ecx, %ecx
callq 0x9330
testq %rax, %rax
je 0xb691
leaq 0x140(%rsp), %r15
addq $0x8, %rax
leaq 0x138(%rsp), %rbx
movq %rbx, %rdi
movq %rax, %rsi
callq 0xbde0
leaq 0x50(%rsp), %rdi
movq %rbx, %rsi
movq %rbp, %rdx
callq 0xaf69
leaq 0x58(%rsp), %r15
leaq 0x140(%rsp), %rdi
callq 0xa248
movq -0x8(%r15), %rdi
callq 0xb8eb
movb 0x8(%rax), %al
xorb $0x1, %al
leaq 0x28(%rsp), %rsi
movb %al, (%rsi)
movq %rsp, %rdi
callq 0xbaf2
leaq 0x8(%rsp), %rdi
movaps -0x8(%rdi), %xmm0
andq $0x0, (%rdi)
movups %xmm0, (%r13)
andq $0x0, -0x8(%rdi)
callq 0xa248
leaq 0x58(%rsp), %rdi
jmp 0xb054
leaq 0xa8(%rsp), %rsi
leaq 0xf8(%rsp), %rbx
movq %rbx, %rdi
callq 0xbde0
movq %rsp, %rdx
movq 0xb8(%rsp), %r13
movq %r13, %rdi
movq %rbx, %rsi
callq 0xaf69
leaq 0x100(%rsp), %rdi
callq 0xa248
movq %rsp, %rdi
callq 0xbe14
leaq 0x50(%rsp), %rdi
callq 0xbace
leaq 0xe0(%rsp), %rdi
jmp 0xb054
addq $0x28, %rbx
leaq 0x168(%rsp), %r14
movq %r14, %rdi
movq %rbx, %rsi
callq 0xbde0
movq %r13, %rdi
movq %r14, %rsi
movq %rbp, %rdx
callq 0xaf69
leaq 0x170(%rsp), %rdi
callq 0xa248
leaq 0x30(%rsp), %rdi
jmp 0xb054
callq 0x9510
movq 0x28(%rsp), %rsi
movq %rsp, %rdi
callq 0xdaae
leaq 0x2ac6d(%rip), %rsi     # 0x36317
leaq 0x50(%rsp), %rdi
movq %rsp, %rdx
callq 0xb97b
movq 0x5092a(%rip), %rdi     # 0x5bfe8
leaq 0x50(%rsp), %rsi
callq 0x9290
movq %rax, %rdi
callq 0x9140
leaq 0x50(%rsp), %rdi
callq 0x9130
movq %rsp, %rdi
callq 0x9130
leaq 0x30dd6(%rip), %rdi     # 0x3c4bf
leaq 0x2ab9a(%rip), %rsi     # 0x3628a
leaq 0x2ac4a(%rip), %rcx     # 0x36341
pushq $0x43
popq %rdx
callq 0x91b0
pushq $0x10
popq %rdi
callq 0x9150
movq %rax, %r14
leaq 0x2ac7a(%rip), %rsi     # 0x3638b
movq %rax, %rdi
callq 0x93c0
movq 0x508b0(%rip), %rsi     # 0x5bfd0
movq 0x50871(%rip), %rdx     # 0x5bf98
movq %r14, %rdi
callq 0x94b0
jmp 0xb766
callq 0x9510
pushq $0x10
popq %rdi
callq 0x9150
movq %rax, %r14
leaq 0x2ac43(%rip), %rsi     # 0x3638b
movq %rax, %rdi
callq 0x93c0
movq 0x50879(%rip), %rsi     # 0x5bfd0
movq 0x5083a(%rip), %rdx     # 0x5bf98
movq %r14, %rdi
callq 0x94b0
movq %rax, %rbx
leaq 0x50(%rsp), %rdi
callq 0x9130
jmp 0xb778
movq %rax, %rbx
movq %rsp, %rdi
callq 0x9130
jmp 0xb868
jmp 0xb7de
movq %rax, %rbx
movq %r14, %rdi
callq 0x9210
jmp 0xb8cf
movq %rax, %rbx
leaq 0x170(%rsp), %rdi
jmp 0xb7af
movq %rax, %rbx
leaq 0x180(%rsp), %rdi
callq 0xa248
jmp 0xb868
movq %rax, %rbx
movq %r14, %rdi
callq 0x9210
jmp 0xb8d9
jmp 0xb865
movq %rax, %rbx
leaq 0x100(%rsp), %rdi
jmp 0xb8c2
movq %rax, %rbx
jmp 0xb8cf
movq %rax, %rbx
leaq 0x1b0(%rsp), %rdi
callq 0xa248
leaq 0x50(%rsp), %rdi
callq 0xbe14
jmp 0xb821
movq %rax, %rbx
leaq 0x1a0(%rsp), %rdi
callq 0xa248
leaq 0x50(%rsp), %rdi
callq 0xbe14
jmp 0xb847
movq %rax, %rbx
leaq 0x8(%rsp), %r15
jmp 0xb868
jmp 0xb865
movq %rax, %rbx
leaq 0xf0(%rsp), %rdi
jmp 0xb8de
movq %rax, %rbx
leaq 0x30(%rsp), %rdi
callq 0xa248
leaq 0x8(%rsp), %rdi
jmp 0xb8de
jmp 0xb865
movq %r14, 0x40(%rsp)
jmp 0xb85e
jmp 0xb865
jmp 0xb85e
movq %rax, %rbx
jmp 0xb8d9
jmp 0xb865
movq %rax, %rbx
movq %r15, %rdi
jmp 0xb8de
movq %rax, %rbx
jmp 0xb884
movq %rax, %rbx
jmp 0xb89b
movq %rax, %rbx
leaq 0x8(%rsp), %rdi
callq 0xa248
leaq 0x150(%rsp), %rdi
callq 0xa248
leaq 0x58(%rsp), %rdi
callq 0xa248
leaq 0x160(%rsp), %rdi
jmp 0xb8de
movq %rax, %rbx
leaq 0x120(%rsp), %rdi
callq 0xa248
jmp 0xb8ba
movq %rax, %rbx
leaq 0x110(%rsp), %rdi
callq 0xa248
movq %rsp, %rdi
callq 0xbe14
leaq 0x50(%rsp), %rdi
callq 0xbace
movq 0x40(%rsp), %rdi
callq 0xa248
movq %rbx, %rdi
callq 0x94d0