// File: silverneko[P]Lambda-calculus-interpreter/src/main.cpp
// Function: weakNormalForm(Expression const&, Context const&)
Object weakNormalForm(const Expression& expr, const Context& env){
  switch( expr.type ){
    case Expression::Constant:
      return makeNormalForm( expr );
      break;
    case Expression::Var:
      if( env.exist(expr.name) ){
        Object& res = env[expr.name];
        if( res.isNormalForm() )
          return res;
        if( res.isPrimitive() )
          return res;
        return res = weakNormalForm( res.expr(), res.env() );
      }else{
        return makeNormalForm( expr );
      }
      break;
    case Expression::Lambda:
      return Object(expr, env);
      break;
    case Expression::Ap:
      {
        const Expression& body = *expr.body;
        const Expression& arg = *expr.arg;
        Object callee(weakNormalForm(body, env));
        if( callee.callable() ){
          Object res = callee.call(arg, env);
          if( res.isNormalForm() )
            return res;
          if( res.isPrimitive() )
            return res;
          return weakNormalForm(res.expr(), res.env());
        }else{
          Expression expr2(Expression::Ap);
          expr2.body = new Expression(callee.expr());
          expr2.arg = new Expression(normalForm(arg, env).expr());
          return makeNormalForm( expr2 );
        }
      }
      break;
    case Expression::Nothing:
      cerr << "[Weak normal form] Unexpected expression type: " << expr.type << endl;
      exit(1);
  }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x2c0, %rsp            # imm = 0x2C0
movq %rdi, -0x260(%rbp)
movq %rdi, %rax
movq %rax, -0x258(%rbp)
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq -0x10(%rbp), %rax
movl (%rax), %eax
movq %rax, -0x250(%rbp)
subq $0x4, %rax
ja 0x4e50
movq -0x250(%rbp), %rax
leaq 0x1a6a7(%rip), %rcx     # 0x1f004
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq -0x260(%rbp), %rdi
movq -0x10(%rbp), %rsi
callq 0x48e0
jmp 0x4e52
movq -0x18(%rbp), %rdi
movq -0x10(%rbp), %rsi
addq $0x8, %rsi
callq 0x46b0
testb $0x1, %al
jne 0x4995
jmp 0x4a8a
movq -0x18(%rbp), %rdi
movq -0x10(%rbp), %rsi
addq $0x8, %rsi
callq 0x45d0
movq %rax, -0x20(%rbp)
movq -0x20(%rbp), %rdi
callq 0x114c0
testb $0x1, %al
jne 0x49b9
jmp 0x49ce
movq -0x260(%rbp), %rdi
movq -0x20(%rbp), %rsi
callq 0x11230
jmp 0x4e52
movq -0x20(%rbp), %rdi
callq 0x114e0
testb $0x1, %al
jne 0x49dd
jmp 0x49f2
movq -0x260(%rbp), %rdi
movq -0x20(%rbp), %rsi
callq 0x11230
jmp 0x4e52
movq -0x20(%rbp), %rdi
callq 0x11500
movq %rax, -0x278(%rbp)
movq -0x20(%rbp), %rdi
callq 0x11520
movq -0x278(%rbp), %rsi
movq %rax, %rdx
leaq -0x90(%rbp), %rdi
movq %rdi, -0x270(%rbp)
callq 0x4910
movq -0x270(%rbp), %rsi
movq -0x20(%rbp), %rdi
callq 0x11540
movq %rax, -0x268(%rbp)
jmp 0x4a41
movq -0x268(%rbp), %rsi
movq -0x260(%rbp), %rdi
callq 0x11230
jmp 0x4a56
leaq -0x90(%rbp), %rdi
callq 0x111d0
jmp 0x4e52
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x98(%rbp)
movl %eax, -0x9c(%rbp)
leaq -0x90(%rbp), %rdi
callq 0x111d0
jmp 0x4e62
movq -0x260(%rbp), %rdi
movq -0x10(%rbp), %rsi
callq 0x48e0
jmp 0x4e52
movq -0x260(%rbp), %rdi
movq -0x10(%rbp), %rsi
movq -0x18(%rbp), %rdx
callq 0x11150
jmp 0x4e52
movq -0x10(%rbp), %rax
movq 0x28(%rax), %rax
movq %rax, -0xa8(%rbp)
movq -0x10(%rbp), %rax
movq 0x30(%rax), %rax
movq %rax, -0xb0(%rbp)
movq -0xa8(%rbp), %rsi
movq -0x18(%rbp), %rdx
leaq -0x120(%rbp), %rdi
movq %rdi, -0x288(%rbp)
callq 0x4910
movq -0x288(%rbp), %rdi
callq 0x46e0
movb %al, -0x279(%rbp)
jmp 0x4b08
movb -0x279(%rbp), %al
testb $0x1, %al
jne 0x4b17
jmp 0x4c57
movq -0xb0(%rbp), %rdx
movq -0x18(%rbp), %rcx
leaq -0x190(%rbp), %rdi
leaq -0x120(%rbp), %rsi
callq 0x4730
jmp 0x4b37
leaq -0x190(%rbp), %rdi
callq 0x114c0
movb %al, -0x289(%rbp)
jmp 0x4b4b
movb -0x289(%rbp), %al
testb $0x1, %al
jne 0x4b57
jmp 0x4bb5
movq -0x260(%rbp), %rdi
leaq -0x190(%rbp), %rsi
callq 0x115b0
jmp 0x4b6c
movl $0x1, -0x194(%rbp)
jmp 0x4c46
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x98(%rbp)
movl %eax, -0x9c(%rbp)
jmp 0x4e08
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x98(%rbp)
movl %eax, -0x9c(%rbp)
leaq -0x190(%rbp), %rdi
callq 0x111d0
jmp 0x4e08
leaq -0x190(%rbp), %rdi
callq 0x114e0
movb %al, -0x28a(%rbp)
jmp 0x4bc9
movb -0x28a(%rbp), %al
testb $0x1, %al
jne 0x4bd5
jmp 0x4bf6
movq -0x260(%rbp), %rdi
leaq -0x190(%rbp), %rsi
callq 0x115b0
jmp 0x4bea
movl $0x1, -0x194(%rbp)
jmp 0x4c46
leaq -0x190(%rbp), %rdi
callq 0x11500
movq %rax, -0x298(%rbp)
jmp 0x4c0b
leaq -0x190(%rbp), %rdi
callq 0x11520
movq %rax, -0x2a0(%rbp)
jmp 0x4c20
movq -0x2a0(%rbp), %rdx
movq -0x298(%rbp), %rsi
movq -0x260(%rbp), %rdi
callq 0x4910
jmp 0x4c3c
movl $0x1, -0x194(%rbp)
leaq -0x190(%rbp), %rdi
callq 0x111d0
jmp 0x4dfa
leaq -0x1d0(%rbp), %rdi
movl $0x4, %esi
callq 0x11640
jmp 0x4c6a
movl $0x38, %edi
callq 0x3230
movq %rax, -0x2a8(%rbp)
jmp 0x4c7d
leaq -0x120(%rbp), %rdi
callq 0x11500
movq %rax, -0x2b0(%rbp)
jmp 0x4c92
movq -0x2b0(%rbp), %rsi
movq -0x2a8(%rbp), %rdi
callq 0x11680
jmp 0x4ca7
movq -0x2a8(%rbp), %rax
movq %rax, -0x1a8(%rbp)
movl $0x38, %edi
callq 0x3230
movq %rax, -0x2b8(%rbp)
jmp 0x4cc8
movb $0x1, -0x241(%rbp)
movq -0xb0(%rbp), %rsi
movq -0x18(%rbp), %rdx
leaq -0x240(%rbp), %rdi
callq 0x4e70
jmp 0x4ce8
leaq -0x240(%rbp), %rdi
callq 0x11500
movq %rax, -0x2c0(%rbp)
jmp 0x4cfd
movq -0x2c0(%rbp), %rsi
movq -0x2b8(%rbp), %rdi
callq 0x11680
jmp 0x4d12
movq -0x2b8(%rbp), %rax
movb $0x0, -0x241(%rbp)
movq %rax, -0x1a0(%rbp)
leaq -0x240(%rbp), %rdi
callq 0x111d0
movq -0x260(%rbp), %rdi
leaq -0x1d0(%rbp), %rsi
callq 0x48e0
jmp 0x4d48
movl $0x1, -0x194(%rbp)
leaq -0x1d0(%rbp), %rdi
callq 0x116e0
jmp 0x4dfa
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x98(%rbp)
movl %eax, -0x9c(%rbp)
jmp 0x4dec
movq -0x2a8(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x98(%rbp)
movl %eax, -0x9c(%rbp)
movl $0x38, %esi
callq 0x3240
jmp 0x4dec
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x98(%rbp)
movl %eax, -0x9c(%rbp)
jmp 0x4dce
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x98(%rbp)
movl %eax, -0x9c(%rbp)
leaq -0x240(%rbp), %rdi
callq 0x111d0
testb $0x1, -0x241(%rbp)
jne 0x4dd9
jmp 0x4dea
movq -0x2b8(%rbp), %rdi
movl $0x38, %esi
callq 0x3240
jmp 0x4dec
leaq -0x1d0(%rbp), %rdi
callq 0x116e0
jmp 0x4e08
leaq -0x120(%rbp), %rdi
callq 0x111d0
jmp 0x4e52
leaq -0x120(%rbp), %rdi
callq 0x111d0
jmp 0x4e62
movq 0x2b1d3(%rip), %rdi     # 0x2fff0
leaq 0x1a6f5(%rip), %rsi     # 0x1f519
callq 0x3220
movq %rax, %rdi
movq -0x10(%rbp), %rax
movl (%rax), %esi
callq 0x33b0
movq %rax, %rdi
movq 0x2b167(%rip), %rsi     # 0x2ffa8
callq 0x3260
movl $0x1, %edi
callq 0x32c0
ud2
movq -0x258(%rbp), %rax
addq $0x2c0, %rsp            # imm = 0x2C0
popq %rbp
retq
movq -0x98(%rbp), %rdi
callq 0x33c0
nop