// File: silverneko[P]Lambda-calculus-interpreter/src/ExpressionParser.cpp
// Function: parseExpressionTail(Scanner&)
Expression * parseExpressionTail(Scanner &scanner){
  Token token = scanner.getToken();
  Expression * expr(nullptr);
  switch(token.type){
    case Token::Lambda:
      token = scanner.getToken();
      if(token.type != Token::Identifier){
        cerr << "[Parse] Expected an identifier: " << token.name << endl;
        exit(1);
      }
      expr = new Expression(Expression::Lambda);
      expr->name = token.name;
      expr->body = parseExpression(scanner);
      return expr;

    case Token::Identifier:
      expr = new Expression(Expression::Var);
      expr->name = token.name;
      return expr;

    case Token::Keyword:
      if(token.name == "let"){
        token = scanner.getToken();
        if(token.type != Token::Identifier){
          cerr << "[Parse] Expected an identifier: " << token.name << endl;
          exit(1);
        }
        expr = new Expression(Expression::Ap);
        expr->body = new Expression(Expression::Lambda);
        expr->body->name = token.name;
        expr->arg = parseExpression(scanner);
        token = scanner.getToken();
        if(token.type != Token::Keyword || token.name != "in"){
          cerr << "[Parse] Expected a keyword `in`: " << token.name << endl;
          exit(1);
        }
        expr->body->body = parseExpression(scanner);
        return expr;
      }else if(token.name == "in"){
        scanner.ungetToken(token);
        return nullptr;
      }

    case Token::Constant:
      expr = new Expression(Expression::Constant);
      expr->name = token.name;
      if(token.name[0] == '\''){
        // character literal
        expr->val = (int)token.name[1];
      }else{
        expr->val = stringTo<int>(token.name);
      }
      return expr;

    case Token::LeftBracket:
      expr = parseExpression(scanner);
      token = scanner.getToken();
      if(token.type != Token::RightBracket){
        cerr << "[Parse] Expected a `)`: " << token.name << endl;
        exit(1);
      }
      return expr;

    case Token::RightBracket:
      scanner.ungetToken(token);
      return nullptr;

    case Token::EndOfFile:
    default:
      return nullptr;
  }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x1b0, %rsp            # imm = 0x1B0
movq %rdi, -0x10(%rbp)
movq -0x10(%rbp), %rsi
leaq -0x38(%rbp), %rdi
callq 0x157e0
movq $0x0, -0x40(%rbp)
movl -0x38(%rbp), %eax
decl %eax
movl %eax, %ecx
movq %rcx, -0xf8(%rbp)
subl $0x6, %eax
ja 0x1651a
movq -0xf8(%rbp), %rax
leaq 0x98f3(%rip), %rcx      # 0x1f7dc
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq -0x10(%rbp), %rsi
leaq -0x68(%rbp), %rdi
callq 0x157e0
jmp 0x15f01
leaq -0x38(%rbp), %rdi
leaq -0x68(%rbp), %rsi
callq 0x1c8a0
leaq -0x68(%rbp), %rdi
callq 0x11de0
cmpl $0x2, -0x38(%rbp)
je 0x15f82
movq 0x1a0cc(%rip), %rdi     # 0x2fff0
leaq 0x9ddf(%rip), %rsi      # 0x1fd0a
callq 0x3220
movq %rax, -0x100(%rbp)
jmp 0x15f39
movq -0x100(%rbp), %rdi
leaq -0x30(%rbp), %rsi
callq 0x31d0
movq %rax, -0x108(%rbp)
jmp 0x15f52
movq -0x108(%rbp), %rdi
movq 0x1a048(%rip), %rsi     # 0x2ffa8
callq 0x3260
jmp 0x15f67
movl $0x1, %edi
callq 0x32c0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
jmp 0x1653f
movl $0x38, %edi
callq 0x3230
movq %rax, -0x110(%rbp)
jmp 0x15f95
movq -0x110(%rbp), %rdi
movl $0x3, %esi
callq 0x11640
jmp 0x15fa8
movq -0x110(%rbp), %rax
movq %rax, -0x40(%rbp)
leaq -0x30(%rbp), %rsi
movq -0x40(%rbp), %rdi
addq $0x8, %rdi
callq 0x3030
jmp 0x15fc6
movq -0x10(%rbp), %rdi
callq 0x15d70
movq %rax, -0x118(%rbp)
jmp 0x15fd8
movq -0x118(%rbp), %rcx
movq -0x40(%rbp), %rax
movq %rcx, 0x28(%rax)
movq -0x40(%rbp), %rax
movq %rax, -0x8(%rbp)
movl $0x1, -0x78(%rbp)
jmp 0x16529
movq -0x110(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
movl $0x38, %esi
callq 0x3240
jmp 0x1653f
movl $0x38, %edi
callq 0x3230
movq %rax, -0x120(%rbp)
jmp 0x16030
movq -0x120(%rbp), %rdi
movl $0x1, %esi
callq 0x11640
jmp 0x16043
movq -0x120(%rbp), %rax
movq %rax, -0x40(%rbp)
leaq -0x30(%rbp), %rsi
movq -0x40(%rbp), %rdi
addq $0x8, %rdi
callq 0x3030
jmp 0x16061
movq -0x40(%rbp), %rax
movq %rax, -0x8(%rbp)
movl $0x1, -0x78(%rbp)
jmp 0x16529
movq -0x120(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
movl $0x38, %esi
callq 0x3240
jmp 0x1653f
leaq -0x30(%rbp), %rdi
leaq 0x9c89(%rip), %rsi      # 0x1fd2b
callq 0x1c8e0
movb %al, -0x121(%rbp)
jmp 0x160af
movb -0x121(%rbp), %al
testb $0x1, %al
jne 0x160be
jmp 0x16310
movq -0x10(%rbp), %rsi
leaq -0xa0(%rbp), %rdi
callq 0x157e0
jmp 0x160d0
leaq -0x38(%rbp), %rdi
leaq -0xa0(%rbp), %rsi
callq 0x1c8a0
leaq -0xa0(%rbp), %rdi
callq 0x11de0
cmpl $0x2, -0x38(%rbp)
je 0x16146
movq 0x19ef7(%rip), %rdi     # 0x2fff0
leaq 0x9c0a(%rip), %rsi      # 0x1fd0a
callq 0x3220
movq %rax, -0x130(%rbp)
jmp 0x1610e
movq -0x130(%rbp), %rdi
leaq -0x30(%rbp), %rsi
callq 0x31d0
movq %rax, -0x138(%rbp)
jmp 0x16127
movq -0x138(%rbp), %rdi
movq 0x19e73(%rip), %rsi     # 0x2ffa8
callq 0x3260
jmp 0x1613c
movl $0x1, %edi
callq 0x32c0
movl $0x38, %edi
callq 0x3230
movq %rax, -0x140(%rbp)
jmp 0x16159
movq -0x140(%rbp), %rdi
movl $0x4, %esi
callq 0x11640
jmp 0x1616c
movq -0x140(%rbp), %rax
movq %rax, -0x40(%rbp)
movl $0x38, %edi
callq 0x3230
movq %rax, -0x148(%rbp)
jmp 0x1618a
movq -0x148(%rbp), %rdi
movl $0x3, %esi
callq 0x11640
jmp 0x1619d
movq -0x148(%rbp), %rcx
movq -0x40(%rbp), %rax
movq %rcx, 0x28(%rax)
leaq -0x30(%rbp), %rsi
movq -0x40(%rbp), %rax
movq 0x28(%rax), %rdi
addq $0x8, %rdi
callq 0x3030
jmp 0x161c3
movq -0x10(%rbp), %rdi
callq 0x15d70
movq %rax, -0x150(%rbp)
jmp 0x161d5
movq -0x150(%rbp), %rcx
movq -0x40(%rbp), %rax
movq %rcx, 0x30(%rax)
movq -0x10(%rbp), %rsi
leaq -0xc8(%rbp), %rdi
callq 0x157e0
jmp 0x161f6
leaq -0x38(%rbp), %rdi
leaq -0xc8(%rbp), %rsi
callq 0x1c8a0
leaq -0xc8(%rbp), %rdi
callq 0x11de0
cmpl $0x3, -0x38(%rbp)
jne 0x1623f
leaq -0x30(%rbp), %rdi
leaq 0x9b0c(%rip), %rsi      # 0x1fd2f
callq 0x1c910
movb %al, -0x151(%rbp)
jmp 0x16230
movb -0x151(%rbp), %al
testb $0x1, %al
jne 0x1623f
jmp 0x162d7
movq 0x19daa(%rip), %rdi     # 0x2fff0
leaq 0x9ae5(%rip), %rsi      # 0x1fd32
callq 0x3220
movq %rax, -0x160(%rbp)
jmp 0x1625b
movq -0x160(%rbp), %rdi
leaq -0x30(%rbp), %rsi
callq 0x31d0
movq %rax, -0x168(%rbp)
jmp 0x16274
movq -0x168(%rbp), %rdi
movq 0x19d26(%rip), %rsi     # 0x2ffa8
callq 0x3260
jmp 0x16289
movl $0x1, %edi
callq 0x32c0
movq -0x140(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
movl $0x38, %esi
callq 0x3240
jmp 0x1653f
movq -0x148(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
movl $0x38, %esi
callq 0x3240
jmp 0x1653f
movq -0x10(%rbp), %rdi
callq 0x15d70
movq %rax, -0x170(%rbp)
jmp 0x162e9
movq -0x170(%rbp), %rcx
movq -0x40(%rbp), %rax
movq 0x28(%rax), %rax
movq %rcx, 0x28(%rax)
movq -0x40(%rbp), %rax
movq %rax, -0x8(%rbp)
movl $0x1, -0x78(%rbp)
jmp 0x16529
leaq -0x30(%rbp), %rdi
leaq 0x9a14(%rip), %rsi      # 0x1fd2f
callq 0x1c8e0
movb %al, -0x171(%rbp)
jmp 0x16328
movb -0x171(%rbp), %al
testb $0x1, %al
jne 0x16334
jmp 0x16357
movq -0x10(%rbp), %rdi
leaq -0x38(%rbp), %rsi
callq 0x159b0
jmp 0x16343
movq $0x0, -0x8(%rbp)
movl $0x1, -0x78(%rbp)
jmp 0x16529
jmp 0x16359
jmp 0x1635b
movl $0x38, %edi
callq 0x3230
movq %rax, -0x180(%rbp)
jmp 0x1636e
movq -0x180(%rbp), %rdi
movl $0x2, %esi
callq 0x11640
jmp 0x16381
movq -0x180(%rbp), %rax
movq %rax, -0x40(%rbp)
leaq -0x30(%rbp), %rsi
movq -0x40(%rbp), %rdi
addq $0x8, %rdi
callq 0x3030
jmp 0x1639f
leaq -0x30(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x3430
movq %rax, -0x188(%rbp)
jmp 0x163b5
movq -0x188(%rbp), %rax
movsbl (%rax), %eax
cmpl $0x27, %eax
jne 0x16410
leaq -0x30(%rbp), %rdi
movl $0x1, %esi
callq 0x3430
movq %rax, -0x190(%rbp)
jmp 0x163db
movq -0x190(%rbp), %rax
movsbl (%rax), %ecx
movq -0x40(%rbp), %rax
movl %ecx, 0x4(%rax)
jmp 0x1642e
movq -0x180(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
movl $0x38, %esi
callq 0x3240
jmp 0x1653f
leaq -0x30(%rbp), %rdi
callq 0x1c940
movl %eax, -0x194(%rbp)
jmp 0x16421
movl -0x194(%rbp), %ecx
movq -0x40(%rbp), %rax
movl %ecx, 0x4(%rax)
movq -0x40(%rbp), %rax
movq %rax, -0x8(%rbp)
movl $0x1, -0x78(%rbp)
jmp 0x16529
movq -0x10(%rbp), %rdi
callq 0x15d70
movq %rax, -0x1a0(%rbp)
jmp 0x16454
movq -0x1a0(%rbp), %rax
movq %rax, -0x40(%rbp)
movq -0x10(%rbp), %rsi
leaq -0xf0(%rbp), %rdi
callq 0x157e0
jmp 0x16471
leaq -0x38(%rbp), %rdi
leaq -0xf0(%rbp), %rsi
callq 0x1c8a0
leaq -0xf0(%rbp), %rdi
callq 0x11de0
cmpl $0x6, -0x38(%rbp)
je 0x164e7
movq 0x19b56(%rip), %rdi     # 0x2fff0
leaq 0x98b3(%rip), %rsi      # 0x1fd54
callq 0x3220
movq %rax, -0x1a8(%rbp)
jmp 0x164af
movq -0x1a8(%rbp), %rdi
leaq -0x30(%rbp), %rsi
callq 0x31d0
movq %rax, -0x1b0(%rbp)
jmp 0x164c8
movq -0x1b0(%rbp), %rdi
movq 0x19ad2(%rip), %rsi     # 0x2ffa8
callq 0x3260
jmp 0x164dd
movl $0x1, %edi
callq 0x32c0
movq -0x40(%rbp), %rax
movq %rax, -0x8(%rbp)
movl $0x1, -0x78(%rbp)
jmp 0x16529
movq -0x10(%rbp), %rdi
leaq -0x38(%rbp), %rsi
callq 0x159b0
jmp 0x16507
movq $0x0, -0x8(%rbp)
movl $0x1, -0x78(%rbp)
jmp 0x16529
jmp 0x1651a
movq $0x0, -0x8(%rbp)
movl $0x1, -0x78(%rbp)
leaq -0x38(%rbp), %rdi
callq 0x11de0
movq -0x8(%rbp), %rax
addq $0x1b0, %rsp            # imm = 0x1B0
popq %rbp
retq
leaq -0x38(%rbp), %rdi
callq 0x11de0
movq -0x70(%rbp), %rdi
callq 0x33c0
nopw %cs:(%rax,%rax)