// File: cphinton42[P]hinton-language/src/parse.cpp
// Function: parse_statement(Parsing_Context*, Token**)
internal AST *parse_statement(Parsing_Context *ctx, Token **current_ptr)
{
    Token *current = *current_ptr;
    Token *start_section = current;
    AST *result = nullptr;
    defer {
        *current_ptr = current;
    };
    
    bool require_semicolon = false;
    
    u32 line_number = current->line_number;
    u32 line_offset = current->line_offset;
    
    if(current->type == Token_Type::key_for)
    {
        ++current;
        Token *start = current;
        
        Ident_AST *induction_var = nullptr;
        Ident_AST *index_var = nullptr;
        bool by_pointer = false;
        
        if(current->type == Token_Type::ref)
        {
            // expr or named identifier by pointer
            by_pointer = true;
            ++current;
        }
        if(current->type == Token_Type::ident)
        {
            bool must_use_names = false;
            Token *first_ident = current;
            Token *second_ident = nullptr;
            ++current;
            
            if(current->type == Token_Type::comma)
            {
                must_use_names = true;
                ++current;
                if(current->type == Token_Type::ident)
                {
                    second_ident = current;
                    ++current;
                }
                else
                {
                    report_error(ctx, start_section, current, "Expected identifier to name index variable");
                    return nullptr;
                }
            }
            
            if(current->type == Token_Type::colon)
            {
                ++current;
                
                assert(first_ident);
                
                // TODO: move allocation to prevent memory leak
                induction_var = pool_alloc(Ident_AST, ctx->ast_pool);
                *induction_var = make_ident_ast(*first_ident);
                
                if(second_ident)
                {
                    index_var = pool_alloc(Ident_AST, ctx->ast_pool);
                    *index_var = make_ident_ast(*second_ident);
                }
            }
            else if(must_use_names)
            {
                report_error(ctx, start_section, current, "Expected ':' to separate variable names from range expression");
                return nullptr;
            }
            else
            {
                // Not names, just a range expr.
                current = start;
            }
        }
        
        Expr_AST *low_range_expr = nullptr;
        Expr_AST *high_range_expr = nullptr;
        
        low_range_expr = parse_expr(ctx, &current);
        if(!low_range_expr)
        {
            return nullptr;
        }
        if(current->type == Token_Type::double_dot)
        {
            if(index_var)
            {
                report_error(ctx, start_section, current, "There is only one variable to be named when iterating over a numerical range");
                return nullptr;
            }
            if(by_pointer)
            {
                report_error(ctx, start_section, current, "Cannot iterate over numerical range by pointer");
                return nullptr;
            }
            
            ++current;
            high_range_expr = parse_expr(ctx, &current);
            if(!high_range_expr)
            {
                return nullptr;
            }
        }
        
        Block_AST *body = parse_statement_block(ctx, &current);
        if(!body)
        {
            return nullptr;
        }
        
        For_AST *for_ast = construct_ast(ctx->ast_pool, For_AST, line_number, line_offset);
        if(by_pointer)
        {
            for_ast->flags |= FOR_FLAG_BY_POINTER;
        }
        
        if(!induction_var)
        {
            induction_var = construct_ast(ctx->ast_pool, Ident_AST, 0, 0);
            induction_var->flags |= AST_FLAG_SYNTHETIC;
            induction_var->ident = str_lit("it");
            induction_var->scope_index = 0;
            induction_var->scope = nullptr;
        }
        
        for_ast->induction_var = induction_var;
        for_ast->body = body;
        if(high_range_expr)
        {
            for_ast->low_expr = low_range_expr;
            for_ast->high_expr = high_range_expr;
        }
        else
        {
            if(!index_var)
            {
                index_var = construct_ast(ctx->ast_pool, Ident_AST, 0, 0);
                index_var->flags |= AST_FLAG_SYNTHETIC;
                index_var->ident = str_lit("it_index");
                index_var->scope_index = 0;
                index_var->scope = nullptr;
            }
            
            for_ast->flags |= FOR_FLAG_OVER_ARRAY;
            for_ast->index_var = index_var;
            for_ast->array_expr = low_range_expr;
        }
        
        result = for_ast;
    }
    else if(current->type == Token_Type::key_if)
    {
        ++current;
        Expr_AST *expr = parse_expr(ctx, &current);
        if(!expr)
        {
            return nullptr;
        }
        Block_AST *then_block = parse_statement_block(ctx, &current);
        if(!then_block)
        {
            return nullptr;
        }
        
        Block_AST *else_block = nullptr;
        
        if(current->type == Token_Type::key_else)
        {
            ++current;
            else_block = parse_statement_block(ctx, &current);
            if(!else_block)
            {
                return nullptr;
            }
        }
        
        If_AST *if_ast = construct_ast(ctx->ast_pool, If_AST, line_number, line_offset);
        if_ast->guard = expr;
        if_ast->then_block = then_block;
        if_ast->else_block = else_block;
        
        result = if_ast;
    }
    else if(current->type == Token_Type::key_while)
    {
        ++current;
        Expr_AST *expr = parse_expr(ctx, &current);
        if(!expr)
        {
            return nullptr;
        }
        Block_AST *body = parse_statement_block(ctx, &current);
        
        While_AST *while_ast = construct_ast(ctx->ast_pool, While_AST, line_number, line_offset);
        while_ast->guard = expr;
        while_ast->body = body;
        
        result = while_ast;
    }
    else if(current->type == Token_Type::key_return)
    {
        require_semicolon = true;
        ++current;
        Expr_AST *expr = parse_expr(ctx, &current);
        if(!expr)
        {
            return nullptr;
        }
        
        Return_AST *return_ast = construct_ast(ctx->ast_pool, Return_AST, line_number, line_offset);
        return_ast->function = nullptr;
        return_ast->expr = expr;
        
        result = return_ast;
    }
    else if(current->type == Token_Type::open_brace)
    {
        result = parse_statement_block(ctx, &current);
    }
    else
    {
        // Expect an expression, declaration, or assignment (e.g. =,+=)
        
        if(current->type == Token_Type::ident)
        {
            Token *at_ident = current;
            ++current;
            if(current->type == Token_Type::colon ||
               current->type == Token_Type::colon_eq ||
               current->type == Token_Type::double_colon)
            {
                // Expect a declaration
                current = at_ident;
                Decl_AST *decl = parse_decl(ctx, &current, Decl_Type::Statement);
                if(!decl)
                {
                    return nullptr;
                }
                result = decl;
            }
            else
            {
                // Expect an expression or assignment
                current = at_ident;
                
                Expr_AST *expr = parse_expr(ctx, &current);
                if(!expr)
                {
                    return nullptr;
                }
                
                if(current->type == Token_Type::equal ||
                   current->type == Token_Type::mul_eq ||
                   current->type == Token_Type::add_eq ||
                   current->type == Token_Type::sub_eq ||
                   current->type == Token_Type::div_eq)
                {
                    // expect an assignment, 'expr' should be the l-value (checked later)
                    
                    Assign_Operator assign_type;
                    switch(current->type)
                    {
                        case Token_Type::equal: {
                            assign_type = Assign_Operator::equal;
                        } break;
                        case Token_Type::mul_eq: {
                            assign_type = Assign_Operator::mul_eq;
                        } break;
                        case Token_Type::add_eq: {
                            assign_type = Assign_Operator::add_eq;
                        } break;
                        case Token_Type::sub_eq: {
                            assign_type = Assign_Operator::sub_eq;
                        } break;
                        case Token_Type::div_eq: {
                            assign_type = Assign_Operator::div_eq;
                        } break;
                        default: {
                            // The guard above prevents these
                            assert(false);
                        } break;
                    }
                    
                    ++current;
                    Expr_AST *rhs = parse_expr(ctx, &current);
                    if(!rhs)
                    {
                        return nullptr;
                    }
                    
                    Assign_AST *assign = construct_ast(ctx->ast_pool, Assign_AST, line_number, line_offset);
                    
                    assign->assign_type = assign_type;
                    assign->lhs = expr;
                    assign->rhs = rhs;
                    
                    result = assign;
                }
                else
                {
                    result = expr;
                }
                
                require_semicolon = true;
            }
        }
        else
        {
            // Expect an expression;
            Expr_AST *expr = parse_expr(ctx, &current);
            if(!expr)
            {
                return nullptr;
            }
            result = expr;
            require_semicolon = true;
        }
    }
    
    if(require_semicolon)
    {
        if(current->type == Token_Type::semicolon)
        {
            ++current;
        }
        else
        {
            report_error(ctx, start_section, current, "Expected ';'");
        }
    }
    
    return result;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x300, %rsp            # imm = 0x300
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq -0x18(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x20(%rbp)
movq -0x20(%rbp), %rax
movq %rax, -0x28(%rbp)
movq $0x0, -0x30(%rbp)
leaq -0x18(%rbp), %rax
movq %rax, -0x50(%rbp)
leaq -0x20(%rbp), %rax
movq %rax, -0x48(%rbp)
leaq -0x40(%rbp), %rdi
xorl %esi, %esi
leaq -0x50(%rbp), %rdx
callq 0x15e10
movb $0x0, -0x51(%rbp)
movq -0x20(%rbp), %rax
movl 0x8(%rax), %eax
movl %eax, -0x58(%rbp)
movq -0x20(%rbp), %rax
movl 0xc(%rax), %eax
movl %eax, -0x5c(%rbp)
movq -0x20(%rbp), %rax
cmpq $0xc, (%rax)
jne 0x15699
movq -0x20(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x20(%rbp)
movq -0x20(%rbp), %rax
movq %rax, -0x68(%rbp)
movq $0x0, -0x70(%rbp)
movq $0x0, -0x78(%rbp)
movb $0x0, -0x79(%rbp)
movq -0x20(%rbp), %rax
cmpq $0x36, (%rax)
jne 0x150a5
movb $0x1, -0x79(%rbp)
movq -0x20(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x20(%rbp)
movq -0x20(%rbp), %rax
cmpq $0x0, (%rax)
jne 0x152fb
movb $0x0, -0x7a(%rbp)
movq -0x20(%rbp), %rax
movq %rax, -0x88(%rbp)
movq $0x0, -0x90(%rbp)
movq -0x20(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x20(%rbp)
movq -0x20(%rbp), %rax
cmpq $0x20, (%rax)
jne 0x1516d
movb $0x1, -0x7a(%rbp)
movq -0x20(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x20(%rbp)
movq -0x20(%rbp), %rax
cmpq $0x0, (%rax)
jne 0x1511a
movq -0x20(%rbp), %rax
movq %rax, -0x90(%rbp)
movq -0x20(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x20(%rbp)
jmp 0x1516b
movq -0x10(%rbp), %rdi
movq -0x28(%rbp), %rsi
movq -0x20(%rbp), %rdx
leaq 0x5f4e(%rip), %rcx      # 0x1b07b
callq 0xc650
jmp 0x15134
movq $0x0, -0x8(%rbp)
movl $0x1, -0xa0(%rbp)
jmp 0x15d80
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x98(%rbp)
movl %eax, -0x9c(%rbp)
leaq -0x40(%rbp), %rdi
callq 0x15e40
jmp 0x15d96
jmp 0x1516d
movq -0x20(%rbp), %rax
cmpq $0x22, (%rax)
jne 0x152b8
movq -0x20(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x20(%rbp)
cmpq $0x0, -0x88(%rbp)
je 0x15193
jmp 0x151b2
leaq 0x5f0c(%rip), %rdi      # 0x1b0a6
leaq 0x5cf8(%rip), %rsi      # 0x1ae99
movl $0x426, %edx            # imm = 0x426
leaq 0x5f05(%rip), %rcx      # 0x1b0b2
callq 0x3080
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rdi
movl $0x40, %esi
callq 0xcd80
movq %rax, -0x228(%rbp)
jmp 0x151cd
movq -0x228(%rbp), %rax
movq %rax, -0x70(%rbp)
movq -0x88(%rbp), %rax
movups (%rax), %xmm0
movups 0x10(%rax), %xmm1
movaps %xmm1, -0xf0(%rbp)
movaps %xmm0, -0x100(%rbp)
movaps -0x100(%rbp), %xmm0
movaps -0xf0(%rbp), %xmm1
movq %rsp, %rax
movups %xmm1, 0x10(%rax)
movups %xmm0, (%rax)
leaq -0xe0(%rbp), %rdi
callq 0x12d10
jmp 0x1521a
movq -0x70(%rbp), %rdi
leaq -0xe0(%rbp), %rsi
movl $0x40, %edx
callq 0x30a0
cmpq $0x0, -0x90(%rbp)
je 0x152b6
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rdi
movl $0x40, %esi
callq 0xcd80
movq %rax, -0x230(%rbp)
jmp 0x15254
movq -0x230(%rbp), %rax
movq %rax, -0x78(%rbp)
movq -0x90(%rbp), %rax
movups (%rax), %xmm0
movups 0x10(%rax), %xmm1
movaps %xmm1, -0x150(%rbp)
movaps %xmm0, -0x160(%rbp)
movaps -0x160(%rbp), %xmm0
movaps -0x150(%rbp), %xmm1
movq %rsp, %rax
movups %xmm1, 0x10(%rax)
movups %xmm0, (%rax)
leaq -0x140(%rbp), %rdi
callq 0x12d10
jmp 0x152a1
movq -0x78(%rbp), %rdi
leaq -0x140(%rbp), %rsi
movl $0x40, %edx
callq 0x30a0
jmp 0x152f9
testb $0x1, -0x7a(%rbp)
je 0x152ef
movq -0x10(%rbp), %rdi
movq -0x28(%rbp), %rsi
movq -0x20(%rbp), %rdx
leaq 0x5e13(%rip), %rcx      # 0x1b0e4
callq 0xc650
jmp 0x152d8
movq $0x0, -0x8(%rbp)
movl $0x1, -0xa0(%rbp)
jmp 0x15d80
movq -0x68(%rbp), %rax
movq %rax, -0x20(%rbp)
jmp 0x152f9
jmp 0x152fb
movq $0x0, -0x168(%rbp)
movq $0x0, -0x170(%rbp)
movq -0x10(%rbp), %rdi
leaq -0x20(%rbp), %rsi
movl $0x7, %edx
callq 0x12390
movq %rax, -0x238(%rbp)
jmp 0x1532c
movq -0x238(%rbp), %rax
movq %rax, -0x168(%rbp)
cmpq $0x0, -0x168(%rbp)
jne 0x1535b
movq $0x0, -0x8(%rbp)
movl $0x1, -0xa0(%rbp)
jmp 0x15d80
movq -0x20(%rbp), %rax
cmpq $0x26, (%rax)
jne 0x15430
cmpq $0x0, -0x78(%rbp)
je 0x153a1
movq -0x10(%rbp), %rdi
movq -0x28(%rbp), %rsi
movq -0x20(%rbp), %rdx
leaq 0x5d9f(%rip), %rcx      # 0x1b122
callq 0xc650
jmp 0x1538a
movq $0x0, -0x8(%rbp)
movl $0x1, -0xa0(%rbp)
jmp 0x15d80
testb $0x1, -0x79(%rbp)
je 0x153d8
movq -0x10(%rbp), %rdi
movq -0x28(%rbp), %rsi
movq -0x20(%rbp), %rdx
leaq 0x5db5(%rip), %rcx      # 0x1b16f
callq 0xc650
jmp 0x153c1
movq $0x0, -0x8(%rbp)
movl $0x1, -0xa0(%rbp)
jmp 0x15d80
movq -0x20(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x20(%rbp)
movq -0x10(%rbp), %rdi
leaq -0x20(%rbp), %rsi
movl $0x7, %edx
callq 0x12390
movq %rax, -0x240(%rbp)
jmp 0x153ff
movq -0x240(%rbp), %rax
movq %rax, -0x170(%rbp)
cmpq $0x0, -0x170(%rbp)
jne 0x1542e
movq $0x0, -0x8(%rbp)
movl $0x1, -0xa0(%rbp)
jmp 0x15d80
jmp 0x15430
movq -0x10(%rbp), %rdi
leaq -0x20(%rbp), %rsi
callq 0x14890
movq %rax, -0x248(%rbp)
jmp 0x15446
movq -0x248(%rbp), %rax
movq %rax, -0x178(%rbp)
cmpq $0x0, -0x178(%rbp)
jne 0x15475
movq $0x0, -0x8(%rbp)
movl $0x1, -0xa0(%rbp)
jmp 0x15d80
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rdi
movl $0x30, %esi
callq 0xcd80
movq %rax, -0x250(%rbp)
jmp 0x15490
movq -0x250(%rbp), %rdi
movl -0x58(%rbp), %eax
movl %eax, %edx
movl -0x5c(%rbp), %eax
movl %eax, %ecx
movl $0x3, %esi
callq 0x3c10
movq %rax, -0x180(%rbp)
testb $0x1, -0x79(%rbp)
je 0x154ca
movq -0x180(%rbp), %rax
movzwl 0x2(%rax), %ecx
orl $0x4, %ecx
movw %cx, 0x2(%rax)
cmpq $0x0, -0x70(%rbp)
jne 0x15566
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rdi
movl $0x40, %esi
callq 0xcd80
movq %rax, -0x258(%rbp)
jmp 0x154f0
movq -0x258(%rbp), %rdi
movl $0x7, %esi
xorl %eax, %eax
movl %eax, %ecx
movq %rcx, %rdx
callq 0x3c10
movq %rax, -0x70(%rbp)
movq -0x70(%rbp), %rax
movzwl 0x2(%rax), %ecx
orl $0x1, %ecx
movw %cx, 0x2(%rax)
movq $0x2, -0x190(%rbp)
leaq 0x5c71(%rip), %rax      # 0x1b19e
movq %rax, -0x188(%rbp)
movq -0x70(%rbp), %rax
movq -0x190(%rbp), %rcx
movq %rcx, 0x20(%rax)
movq -0x188(%rbp), %rcx
movq %rcx, 0x28(%rax)
movq -0x70(%rbp), %rax
movq $0x0, 0x30(%rax)
movq -0x70(%rbp), %rax
movq $0x0, 0x38(%rax)
movq -0x70(%rbp), %rcx
movq -0x180(%rbp), %rax
movq %rcx, 0x10(%rax)
movq -0x178(%rbp), %rcx
movq -0x180(%rbp), %rax
movq %rcx, 0x28(%rax)
cmpq $0x0, -0x170(%rbp)
je 0x155ba
movq -0x168(%rbp), %rcx
movq -0x180(%rbp), %rax
movq %rcx, 0x18(%rax)
movq -0x170(%rbp), %rcx
movq -0x180(%rbp), %rax
movq %rcx, 0x20(%rax)
jmp 0x15689
cmpq $0x0, -0x78(%rbp)
jne 0x15656
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rdi
movl $0x40, %esi
callq 0xcd80
movq %rax, -0x260(%rbp)
jmp 0x155e0
movq -0x260(%rbp), %rdi
movl $0x7, %esi
xorl %eax, %eax
movl %eax, %ecx
movq %rcx, %rdx
callq 0x3c10
movq %rax, -0x78(%rbp)
movq -0x78(%rbp), %rax
movzwl 0x2(%rax), %ecx
orl $0x1, %ecx
movw %cx, 0x2(%rax)
movq $0x8, -0x1a0(%rbp)
leaq 0x5b84(%rip), %rax      # 0x1b1a1
movq %rax, -0x198(%rbp)
movq -0x78(%rbp), %rax
movq -0x1a0(%rbp), %rcx
movq %rcx, 0x20(%rax)
movq -0x198(%rbp), %rcx
movq %rcx, 0x28(%rax)
movq -0x78(%rbp), %rax
movq $0x0, 0x30(%rax)
movq -0x78(%rbp), %rax
movq $0x0, 0x38(%rax)
movq -0x180(%rbp), %rax
movzwl 0x2(%rax), %ecx
orl $0x8, %ecx
movw %cx, 0x2(%rax)
movq -0x78(%rbp), %rcx
movq -0x180(%rbp), %rax
movq %rcx, 0x18(%rax)
movq -0x168(%rbp), %rcx
movq -0x180(%rbp), %rax
movq %rcx, 0x20(%rax)
movq -0x180(%rbp), %rax
movq %rax, -0x30(%rbp)
jmp 0x15d32
movq -0x20(%rbp), %rax
cmpq $0xd, (%rax)
jne 0x1582d
movq -0x20(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x20(%rbp)
movq -0x10(%rbp), %rdi
leaq -0x20(%rbp), %rsi
movl $0x7, %edx
callq 0x12390
movq %rax, -0x268(%rbp)
jmp 0x156ce
movq -0x268(%rbp), %rax
movq %rax, -0x1a8(%rbp)
cmpq $0x0, -0x1a8(%rbp)
jne 0x156fd
movq $0x0, -0x8(%rbp)
movl $0x1, -0xa0(%rbp)
jmp 0x15d80
movq -0x10(%rbp), %rdi
leaq -0x20(%rbp), %rsi
callq 0x14890
movq %rax, -0x270(%rbp)
jmp 0x15713
movq -0x270(%rbp), %rax
movq %rax, -0x1b0(%rbp)
cmpq $0x0, -0x1b0(%rbp)
jne 0x15742
movq $0x0, -0x8(%rbp)
movl $0x1, -0xa0(%rbp)
jmp 0x15d80
movq $0x0, -0x1b8(%rbp)
movq -0x20(%rbp), %rax
cmpq $0x7, (%rax)
jne 0x157aa
movq -0x20(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x20(%rbp)
movq -0x10(%rbp), %rdi
leaq -0x20(%rbp), %rsi
callq 0x14890
movq %rax, -0x278(%rbp)
jmp 0x15779
movq -0x278(%rbp), %rax
movq %rax, -0x1b8(%rbp)
cmpq $0x0, -0x1b8(%rbp)
jne 0x157a8
movq $0x0, -0x8(%rbp)
movl $0x1, -0xa0(%rbp)
jmp 0x15d80
jmp 0x157aa
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rdi
movl $0x28, %esi
callq 0xcd80
movq %rax, -0x280(%rbp)
jmp 0x157c5
movq -0x280(%rbp), %rdi
movl -0x58(%rbp), %eax
movl %eax, %edx
movl -0x5c(%rbp), %eax
movl %eax, %ecx
movl $0x4, %esi
callq 0x3c10
movq %rax, -0x1c0(%rbp)
movq -0x1a8(%rbp), %rcx
movq -0x1c0(%rbp), %rax
movq %rcx, 0x10(%rax)
movq -0x1b0(%rbp), %rcx
movq -0x1c0(%rbp), %rax
movq %rcx, 0x18(%rax)
movq -0x1b8(%rbp), %rcx
movq -0x1c0(%rbp), %rax
movq %rcx, 0x20(%rax)
movq -0x1c0(%rbp), %rax
movq %rax, -0x30(%rbp)
jmp 0x15d30
movq -0x20(%rbp), %rax
cmpq $0x1e, (%rax)
jne 0x15926
movq -0x20(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x20(%rbp)
movq -0x10(%rbp), %rdi
leaq -0x20(%rbp), %rsi
movl $0x7, %edx
callq 0x12390
movq %rax, -0x288(%rbp)
jmp 0x15862
movq -0x288(%rbp), %rax
movq %rax, -0x1c8(%rbp)
cmpq $0x0, -0x1c8(%rbp)
jne 0x15891
movq $0x0, -0x8(%rbp)
movl $0x1, -0xa0(%rbp)
jmp 0x15d80
movq -0x10(%rbp), %rdi
leaq -0x20(%rbp), %rsi
callq 0x14890
movq %rax, -0x290(%rbp)
jmp 0x158a7
movq -0x290(%rbp), %rax
movq %rax, -0x1d0(%rbp)
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rdi
movl $0x20, %esi
callq 0xcd80
movq %rax, -0x298(%rbp)
jmp 0x158d0
movq -0x298(%rbp), %rdi
movl -0x58(%rbp), %eax
movl %eax, %edx
movl -0x5c(%rbp), %eax
movl %eax, %ecx
movl $0x2, %esi
callq 0x3c10
movq %rax, -0x1d8(%rbp)
movq -0x1c8(%rbp), %rcx
movq -0x1d8(%rbp), %rax
movq %rcx, 0x10(%rax)
movq -0x1d0(%rbp), %rcx
movq -0x1d8(%rbp), %rax
movq %rcx, 0x18(%rax)
movq -0x1d8(%rbp), %rax
movq %rax, -0x30(%rbp)
jmp 0x15d2e
movq -0x20(%rbp), %rax
cmpq $0x1c, (%rax)
jne 0x159fc
movb $0x1, -0x51(%rbp)
movq -0x20(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x20(%rbp)
movq -0x10(%rbp), %rdi
leaq -0x20(%rbp), %rsi
movl $0x7, %edx
callq 0x12390
movq %rax, -0x2a0(%rbp)
jmp 0x1595f
movq -0x2a0(%rbp), %rax
movq %rax, -0x1e0(%rbp)
cmpq $0x0, -0x1e0(%rbp)
jne 0x1598e
movq $0x0, -0x8(%rbp)
movl $0x1, -0xa0(%rbp)
jmp 0x15d80
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rdi
movl $0x20, %esi
callq 0xcd80
movq %rax, -0x2a8(%rbp)
jmp 0x159a9
movq -0x2a8(%rbp), %rdi
movl -0x58(%rbp), %eax
movl %eax, %edx
movl -0x5c(%rbp), %eax
movl %eax, %ecx
movl $0x6, %esi
callq 0x3c10
movq %rax, -0x1e8(%rbp)
movq -0x1e8(%rbp), %rax
movq $0x0, 0x10(%rax)
movq -0x1e0(%rbp), %rcx
movq -0x1e8(%rbp), %rax
movq %rcx, 0x18(%rax)
movq -0x1e8(%rbp), %rax
movq %rax, -0x30(%rbp)
jmp 0x15d2c
movq -0x20(%rbp), %rax
cmpq $0x2c, (%rax)
jne 0x15a2c
movq -0x10(%rbp), %rdi
leaq -0x20(%rbp), %rsi
callq 0x14890
movq %rax, -0x2b0(%rbp)
jmp 0x15a1c
movq -0x2b0(%rbp), %rax
movq %rax, -0x30(%rbp)
jmp 0x15d2a
movq -0x20(%rbp), %rax
cmpq $0x0, (%rax)
jne 0x15cd2
movq -0x20(%rbp), %rax
movq %rax, -0x1f0(%rbp)
movq -0x20(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x20(%rbp)
movq -0x20(%rbp), %rax
cmpq $0x22, (%rax)
je 0x15a6f
movq -0x20(%rbp), %rax
cmpq $0x23, (%rax)
je 0x15a6f
movq -0x20(%rbp), %rax
cmpq $0x24, (%rax)
jne 0x15ad1
movq -0x1f0(%rbp), %rax
movq %rax, -0x20(%rbp)
movq -0x10(%rbp), %rdi
leaq -0x20(%rbp), %rsi
xorl %edx, %edx
callq 0xc870
movq %rax, -0x2b8(%rbp)
jmp 0x15a92
movq -0x2b8(%rbp), %rax
movq %rax, -0x1f8(%rbp)
cmpq $0x0, -0x1f8(%rbp)
jne 0x15ac1
movq $0x0, -0x8(%rbp)
movl $0x1, -0xa0(%rbp)
jmp 0x15d80
movq -0x1f8(%rbp), %rax
movq %rax, -0x30(%rbp)
jmp 0x15cd0
movq -0x1f0(%rbp), %rax
movq %rax, -0x20(%rbp)
movq -0x10(%rbp), %rdi
leaq -0x20(%rbp), %rsi
movl $0x7, %edx
callq 0x12390
movq %rax, -0x2c0(%rbp)
jmp 0x15af7
movq -0x2c0(%rbp), %rax
movq %rax, -0x200(%rbp)
cmpq $0x0, -0x200(%rbp)
jne 0x15b26
movq $0x0, -0x8(%rbp)
movl $0x1, -0xa0(%rbp)
jmp 0x15d80
movq -0x20(%rbp), %rax
cmpq $0x3b, (%rax)
je 0x15b5c
movq -0x20(%rbp), %rax
cmpq $0x3d, (%rax)
je 0x15b5c
movq -0x20(%rbp), %rax
cmpq $0x3e, (%rax)
je 0x15b5c
movq -0x20(%rbp), %rax
cmpq $0x3f, (%rax)
je 0x15b5c
movq -0x20(%rbp), %rax
cmpq $0x40, (%rax)
jne 0x15cc1
movq -0x20(%rbp), %rax
movq (%rax), %rax
addq $-0x3b, %rax
movq %rax, -0x2c8(%rbp)
subq $0x5, %rax
ja 0x15bcc
movq -0x2c8(%rbp), %rax
leaq 0x3cde(%rip), %rcx      # 0x19860
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq $0x0, -0x208(%rbp)
jmp 0x15beb
movq $0x1, -0x208(%rbp)
jmp 0x15beb
movq $0x2, -0x208(%rbp)
jmp 0x15beb
movq $0x3, -0x208(%rbp)
jmp 0x15beb
movq $0x4, -0x208(%rbp)
jmp 0x15beb
leaq 0x424f(%rip), %rdi      # 0x19e22
leaq 0x52bf(%rip), %rsi      # 0x1ae99
movl $0x50a, %edx            # imm = 0x50A
leaq 0x54cc(%rip), %rcx      # 0x1b0b2
callq 0x3080
movq -0x20(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x20(%rbp)
movq -0x10(%rbp), %rdi
leaq -0x20(%rbp), %rsi
movl $0x7, %edx
callq 0x12390
movq %rax, -0x2d0(%rbp)
jmp 0x15c12
movq -0x2d0(%rbp), %rax
movq %rax, -0x210(%rbp)
cmpq $0x0, -0x210(%rbp)
jne 0x15c41
movq $0x0, -0x8(%rbp)
movl $0x1, -0xa0(%rbp)
jmp 0x15d80
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rdi
movl $0x28, %esi
callq 0xcd80
movq %rax, -0x2d8(%rbp)
jmp 0x15c5c
movq -0x2d8(%rbp), %rdi
movl -0x58(%rbp), %eax
movl %eax, %edx
movl -0x5c(%rbp), %eax
movl %eax, %ecx
movl $0x5, %esi
callq 0x3c10
movq %rax, -0x218(%rbp)
movq -0x208(%rbp), %rcx
movq -0x218(%rbp), %rax
movq %rcx, 0x10(%rax)
movq -0x200(%rbp), %rcx
movq -0x218(%rbp), %rax
movq %rcx, 0x18(%rax)
movq -0x210(%rbp), %rcx
movq -0x218(%rbp), %rax
movq %rcx, 0x20(%rax)
movq -0x218(%rbp), %rax
movq %rax, -0x30(%rbp)
jmp 0x15ccc
movq -0x200(%rbp), %rax
movq %rax, -0x30(%rbp)
movb $0x1, -0x51(%rbp)
jmp 0x15d28
movq -0x10(%rbp), %rdi
leaq -0x20(%rbp), %rsi
movl $0x7, %edx
callq 0x12390
movq %rax, -0x2e0(%rbp)
jmp 0x15ced
movq -0x2e0(%rbp), %rax
movq %rax, -0x220(%rbp)
cmpq $0x0, -0x220(%rbp)
jne 0x15d19
movq $0x0, -0x8(%rbp)
movl $0x1, -0xa0(%rbp)
jmp 0x15d80
movq -0x220(%rbp), %rax
movq %rax, -0x30(%rbp)
movb $0x1, -0x51(%rbp)
jmp 0x15d2a
jmp 0x15d2c
jmp 0x15d2e
jmp 0x15d30
jmp 0x15d32
testb $0x1, -0x51(%rbp)
je 0x15d6e
movq -0x20(%rbp), %rax
cmpq $0x21, (%rax)
jne 0x15d50
movq -0x20(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x20(%rbp)
jmp 0x15d6c
movq -0x10(%rbp), %rdi
movq -0x28(%rbp), %rsi
movq -0x20(%rbp), %rdx
leaq 0x50c5(%rip), %rcx      # 0x1ae28
callq 0xc650
jmp 0x15d6a
jmp 0x15d6c
jmp 0x15d6e
movq -0x30(%rbp), %rax
movq %rax, -0x8(%rbp)
movl $0x1, -0xa0(%rbp)
leaq -0x40(%rbp), %rdi
callq 0x15e40
movq -0x8(%rbp), %rax
addq $0x300, %rsp            # imm = 0x300
popq %rbp
retq
movq -0x98(%rbp), %rdi
callq 0x3100
nopw %cs:(%rax,%rax)