// File: /workspace/github_cpp_makefile_star2_O3/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
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x58, %rsp
movq %rdi, %r14
leaq 0x8(%rsp), %rbx
movq %rbx, %rdi
movq %r14, %rsi
callq 0xbe76
movl (%rbx), %eax
decl %eax
cmpl $0x5, %eax
ja 0xc7fe
leaq 0x31f9(%rip), %rcx      # 0xf698
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movl $0x38, %edi
callq 0x31c0
movq %rax, %rbx
movl $0x1, (%rax)
leaq 0x8(%rax), %rdi
addq $0x18, %rax
movq %rax, 0x8(%rbx)
movq $0x0, 0x10(%rbx)
movb $0x0, 0x18(%rbx)
xorps %xmm0, %xmm0
movups %xmm0, 0x28(%rbx)
leaq 0x10(%rsp), %rsi
callq 0x30f0
jmp 0xc800
leaq 0x30(%rsp), %rdi
movq %r14, %rsi
callq 0xbe76
leaq 0x38(%rsp), %rbx
movl -0x8(%rbx), %eax
leaq 0x10(%rsp), %r15
movl %eax, -0x8(%r15)
movq %r15, %rdi
movq %rbx, %rsi
callq 0x3210
movq (%rbx), %rdi
leaq 0x48(%rsp), %rax
cmpq %rax, %rdi
je 0xc52c
movq 0x48(%rsp), %rsi
incq %rsi
callq 0x31d0
cmpl $0x2, 0x8(%rsp)
jne 0xc82d
movl $0x38, %edi
callq 0x31c0
movq %rax, %rbx
movl $0x3, (%rax)
leaq 0x8(%rax), %rdi
addq $0x18, %rax
movq %rax, 0x8(%rbx)
movq $0x0, 0x10(%rbx)
movb $0x0, 0x18(%rbx)
xorps %xmm0, %xmm0
movups %xmm0, 0x28(%rbx)
movq %r15, %rsi
callq 0x30f0
movq %r14, %rdi
callq 0xc36a
movq %rbx, %rcx
addq $0x28, %rcx
movq %rax, (%rcx)
jmp 0xc800
leaq 0x10(%rsp), %r15
leaq 0x3538(%rip), %rsi      # 0xfacc
movq %r15, %rdi
callq 0x3070
testl %eax, %eax
je 0xc6b2
leaq 0x3525(%rip), %rsi      # 0xfad0
movq %r15, %rdi
callq 0x3070
testl %eax, %eax
je 0xc7ea
movl $0x38, %edi
callq 0x31c0
movq %rax, %rbx
movl $0x2, (%rax)
leaq 0x8(%rax), %rdi
addq $0x18, %rax
movq %rax, 0x8(%rbx)
movq $0x0, 0x10(%rbx)
movb $0x0, 0x18(%rbx)
xorps %xmm0, %xmm0
movups %xmm0, 0x28(%rbx)
leaq 0x10(%rsp), %r14
movq %r14, %rsi
callq 0x30f0
movq 0x10(%rsp), %rax
cmpb $0x27, (%rax)
jne 0xc6a2
movsbl 0x1(%rax), %eax
jmp 0xc6aa
movq %r14, %rdi
callq 0xc36a
movq %rax, %rbx
leaq 0x30(%rsp), %rdi
movq %r14, %rsi
callq 0xbe76
leaq 0x38(%rsp), %r14
movl -0x8(%r14), %eax
leaq 0x10(%rsp), %rdi
movl %eax, -0x8(%rdi)
movq %r14, %rsi
callq 0x3210
movq (%r14), %rdi
leaq 0x48(%rsp), %rax
cmpq %rax, %rdi
je 0xc65c
movq 0x48(%rsp), %rsi
incq %rsi
callq 0x31d0
cmpl $0x6, 0x8(%rsp)
je 0xc800
movq 0x8982(%rip), %rdi      # 0x14ff0
leaq 0x3480(%rip), %rsi      # 0xfaf5
movl $0x18, %edx
callq 0x31f0
movq 0x10(%rsp), %rsi
movq 0x18(%rsp), %rdx
movq 0x8960(%rip), %rdi      # 0x14ff0
callq 0x31f0
movq %rax, %rdi
callq 0x30d0
jmp 0xc8d3
movq %r14, %rdi
callq 0xdb4a
movl %eax, 0x4(%rbx)
jmp 0xc800
leaq 0x30(%rsp), %rdi
movq %r14, %rsi
callq 0xbe76
leaq 0x38(%rsp), %rbx
movl -0x8(%rbx), %eax
movl %eax, 0x8(%rsp)
movq %r15, %rdi
movq %rbx, %rsi
callq 0x3210
movq (%rbx), %rdi
leaq 0x48(%rsp), %r13
cmpq %r13, %rdi
je 0xc6f0
movq 0x48(%rsp), %rsi
incq %rsi
callq 0x31d0
cmpl $0x2, 0x8(%rsp)
jne 0xc89d
movl $0x38, %edi
callq 0x31c0
movq %rax, %rbx
movl $0x4, (%rax)
addq $0x18, %rax
movq %rax, 0x8(%rbx)
movq $0x0, 0x10(%rbx)
movb $0x0, 0x18(%rbx)
xorps %xmm0, %xmm0
movups %xmm0, 0x28(%rbx)
movl $0x38, %edi
callq 0x31c0
movq %rbx, %rbp
addq $0x28, %rbp
movl $0x3, (%rax)
leaq 0x8(%rax), %rdi
movq %rax, %rcx
addq $0x18, %rcx
movq %rcx, 0x8(%rax)
movq $0x0, 0x10(%rax)
movb $0x0, 0x18(%rax)
xorps %xmm0, %xmm0
movups %xmm0, 0x28(%rax)
movq %rax, (%rbp)
movq %r15, %rsi
callq 0x30f0
movq %r14, %rdi
callq 0xc36a
movq %rax, 0x30(%rbx)
leaq 0x30(%rsp), %rdi
movq %r14, %rsi
callq 0xbe76
leaq 0x38(%rsp), %r12
movl -0x8(%r12), %eax
movl %eax, 0x8(%rsp)
movq %r15, %rdi
movq %r12, %rsi
callq 0x3210
movq (%r12), %rdi
cmpq %r13, %rdi
je 0xc7b6
movq 0x48(%rsp), %rsi
incq %rsi
callq 0x31d0
cmpl $0x3, 0x8(%rsp)
jne 0xc865
leaq 0x3308(%rip), %rsi      # 0xfad0
movq %r15, %rdi
callq 0x3070
testl %eax, %eax
jne 0xc865
movq %r14, %rdi
callq 0xc36a
movq (%rbp), %rcx
movq %rax, 0x28(%rcx)
jmp 0xc800
cmpl $0x7, 0x8(%rsp)
je 0xc7fe
leaq 0x8(%rsp), %rsi
movq %r14, %rdi
callq 0xdb08
xorl %ebx, %ebx
leaq 0x20(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0xc81b
movq 0x20(%rsp), %rsi
incq %rsi
callq 0x31d0
movq %rbx, %rax
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x87bc(%rip), %rdi      # 0x14ff0
leaq 0x3270(%rip), %rsi      # 0xfaab
movl $0x20, %edx
callq 0x31f0
movq 0x10(%rsp), %rsi
movq 0x18(%rsp), %rdx
movq 0x879a(%rip), %rdi      # 0x14ff0
callq 0x31f0
movq %rax, %rdi
callq 0x30d0
jmp 0xc8d3
movq 0x8784(%rip), %rdi      # 0x14ff0
leaq 0x3260(%rip), %rsi      # 0xfad3
movl $0x21, %edx
callq 0x31f0
movq 0x10(%rsp), %rsi
movq 0x18(%rsp), %rdx
movq 0x8762(%rip), %rdi      # 0x14ff0
callq 0x31f0
movq %rax, %rdi
callq 0x30d0
jmp 0xc8d3
movq 0x874c(%rip), %rdi      # 0x14ff0
leaq 0x3200(%rip), %rsi      # 0xfaab
movl $0x20, %edx
callq 0x31f0
movq 0x10(%rsp), %rsi
movq 0x18(%rsp), %rdx
movq 0x872a(%rip), %rdi      # 0x14ff0
callq 0x31f0
movq %rax, %rdi
callq 0x30d0
movl $0x1, %edi
callq 0x3200
jmp 0xc8e5
jmp 0xc8e5
jmp 0xc8e5
jmp 0xc8e5
movq %rax, %rbx
leaq 0x20(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0xc903
movq 0x20(%rsp), %rsi
incq %rsi
callq 0x31d0
movq %rbx, %rdi
callq 0x32d0
nop