// File: ridiculousfish[P]docopt_fish/docopt_matching.cpp
// Function: docopt_fish::match(docopt_fish::expression_t const&, docopt_fish::match_state_t, docopt_fish::match_context_t const&, std::vector<docopt_fish::match_state_t, std::allocator<docopt_fish::match_state_t>>*)
static void match(const expression_t &node, match_state_t state, const match_context_t &ctx,
                  match_state_list_t *resulting_states) {
    // Check to see if we have ellipsis. If so, we keep going as long as we can.
    bool has_ellipsis = node.opt_ellipsis.present;

    switch (node.production) {
        case 0: {
            // This is a simple clause which may have ellipsis, like foo...
            // If we have ellipsis, we match one time, and then construct a sequence of
            // 'intermediate state lists'.
            //  An intermediate state represents the result of matching N times. Each time
            //  we construct a new intermediate state, we append (copy) all of its states into the
            //  result; thus we may match one time, two times, three times...
            //  We stop when we get no more matches, which usually happens when we run out
            //  of positionals.
            assert(node.simple_clause.get() != nullptr);
            size_t prior_state_count = resulting_states->size();
            match(*node.simple_clause, state.move(), ctx, resulting_states);
            // Now we know that all states starting at state_count_before are newly added.
            // If we have ellipsis, go until we stop getting new states.
            if (has_ellipsis) {
                repeat_matching(*node.simple_clause, prior_state_count, ctx, resulting_states);
            }
            break;
        }

        case 1: {
            // This is a parenthesized clause which may have ellipsis, like (foo)...
            // Same algorithm as the simple clause above.
            size_t prior_state_count = resulting_states->size();
            assert(node.alternation_list.get() != nullptr);
            match(*node.alternation_list, state.move(), ctx, resulting_states);
            if (has_ellipsis) {
                repeat_matching(*node.alternation_list, prior_state_count, ctx, resulting_states);
            }
            break;
        }

        case 2: {
            // This is a square-bracketed clause which may have ellipsis, like [foo]...
            // Same algorithm as the simple clause above, except that we also append the
            // initial state as a not-taken branch.
            assert(node.alternation_list.get() != nullptr);
            resulting_states->push_back(state.copy());  // append the not-taken-branch
            size_t prior_state_count = resulting_states->size();
            match(*node.alternation_list, std::move(state), ctx, resulting_states);
            if (has_ellipsis) {
                repeat_matching(*node.alternation_list, prior_state_count, ctx, resulting_states);
            }
            break;
        }

        case 3: {
            // This is the [options] clause. It does not have ellipsis.
            assert(node.options_shortcut.present);
            if (!match_options(ctx.shortcut_options, &state, ctx)) {
                // No match, but matches are not required
                if (ctx.flags & flag_generate_suggestions) {
                    for (const option_t &opt : ctx.shortcut_options) {
                        state.suggested_next_arguments.insert(opt.best_name());
                    }
                }
            }
            resulting_states->push_back(state.move());
            break;
        }

        default:
            assert(0 && "unknown production");
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x260, %rsp            # imm = 0x260
movq %rsi, -0x210(%rbp)
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movq -0x8(%rbp), %rax
movb 0x58(%rax), %al
andb $0x1, %al
movb %al, -0x21(%rbp)
movq -0x8(%rbp), %rax
movzbl 0x61(%rax), %eax
movq %rax, -0x208(%rbp)
subq $0x3, %rax
ja 0x30af9
movq -0x208(%rbp), %rax
leaq 0x1bb4f(%rip), %rcx     # 0x4c1d4
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq -0x8(%rbp), %rdi
callq 0x2a020
cmpq $0x0, %rax
je 0x3069f
jmp 0x306be
leaq 0x1bc9f(%rip), %rdi     # 0x4c345
leaq 0x1bb86(%rip), %rsi     # 0x4c233
movl $0x1c6, %edx            # imm = 0x1C6
leaq 0x1bcb0(%rip), %rcx     # 0x4c369
callq 0x81e0
movq -0x20(%rbp), %rdi
callq 0x33300
movq %rax, -0x30(%rbp)
movq -0x8(%rbp), %rdi
callq 0x2df40
movq -0x210(%rbp), %rdi
movq %rax, -0x220(%rbp)
callq 0x32ae0
movq %rax, %rsi
leaq -0x90(%rbp), %rdi
movq %rdi, -0x218(%rbp)
callq 0x32af0
movq -0x220(%rbp), %rdi
movq -0x218(%rbp), %rsi
movq -0x18(%rbp), %rdx
movq -0x20(%rbp), %rcx
callq 0x30d90
jmp 0x3071a
leaq -0x90(%rbp), %rdi
callq 0x321f0
testb $0x1, -0x21(%rbp)
je 0x3076e
movq -0x8(%rbp), %rdi
callq 0x2df40
movq %rax, %rdi
movq -0x30(%rbp), %rsi
movq -0x18(%rbp), %rdx
movq -0x20(%rbp), %rcx
callq 0x30fb0
jmp 0x3076e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x98(%rbp)
movl %eax, -0x9c(%rbp)
leaq -0x90(%rbp), %rdi
callq 0x321f0
jmp 0x30b21
jmp 0x30b18
movq -0x20(%rbp), %rdi
callq 0x33300
movq %rax, -0xa8(%rbp)
movq -0x8(%rbp), %rdi
addq $0x20, %rdi
callq 0x2ec20
cmpq $0x0, %rax
je 0x30798
jmp 0x307b7
leaq 0x1bc36(%rip), %rdi     # 0x4c3d5
leaq 0x1ba8d(%rip), %rsi     # 0x4c233
movl $0x1d5, %edx            # imm = 0x1D5
leaq 0x1bbb7(%rip), %rcx     # 0x4c369
callq 0x81e0
movq -0x8(%rbp), %rdi
addq $0x20, %rdi
callq 0x2ec50
movq -0x210(%rbp), %rdi
movq %rax, -0x230(%rbp)
callq 0x32ae0
movq %rax, %rsi
leaq -0x108(%rbp), %rdi
movq %rdi, -0x228(%rbp)
callq 0x32af0
movq -0x230(%rbp), %rdi
movq -0x228(%rbp), %rsi
movq -0x18(%rbp), %rdx
movq -0x20(%rbp), %rcx
callq 0x301d0
jmp 0x3080a
leaq -0x108(%rbp), %rdi
callq 0x321f0
testb $0x1, -0x21(%rbp)
je 0x30865
movq -0x8(%rbp), %rdi
addq $0x20, %rdi
callq 0x2ec50
movq %rax, %rdi
movq -0xa8(%rbp), %rsi
movq -0x18(%rbp), %rdx
movq -0x20(%rbp), %rcx
callq 0x31160
jmp 0x30865
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x98(%rbp)
movl %eax, -0x9c(%rbp)
leaq -0x108(%rbp), %rdi
callq 0x321f0
jmp 0x30b21
jmp 0x30b18
movq -0x8(%rbp), %rdi
addq $0x20, %rdi
callq 0x2ec20
cmpq $0x0, %rax
je 0x3087f
jmp 0x3089e
leaq 0x1bb4f(%rip), %rdi     # 0x4c3d5
leaq 0x1b9a6(%rip), %rsi     # 0x4c233
movl $0x1e1, %edx            # imm = 0x1E1
leaq 0x1bad0(%rip), %rcx     # 0x4c369
callq 0x81e0
movq -0x210(%rbp), %rsi
movq -0x20(%rbp), %rax
movq %rax, -0x240(%rbp)
leaq -0x168(%rbp), %rdi
movq %rdi, -0x238(%rbp)
callq 0x32ab0
movq -0x240(%rbp), %rdi
movq -0x238(%rbp), %rsi
callq 0x32d70
jmp 0x308d8
leaq -0x168(%rbp), %rdi
callq 0x321f0
movq -0x20(%rbp), %rdi
callq 0x33300
movq %rax, -0x170(%rbp)
movq -0x8(%rbp), %rdi
addq $0x20, %rdi
callq 0x2ec50
movq -0x210(%rbp), %rsi
movq %rax, -0x250(%rbp)
leaq -0x1d0(%rbp), %rdi
movq %rdi, -0x248(%rbp)
callq 0x32af0
movq -0x250(%rbp), %rdi
movq -0x248(%rbp), %rsi
movq -0x18(%rbp), %rdx
movq -0x20(%rbp), %rcx
callq 0x301d0
jmp 0x3093f
leaq -0x1d0(%rbp), %rdi
callq 0x321f0
testb $0x1, -0x21(%rbp)
je 0x309bd
movq -0x8(%rbp), %rdi
addq $0x20, %rdi
callq 0x2ec50
movq %rax, %rdi
movq -0x170(%rbp), %rsi
movq -0x18(%rbp), %rdx
movq -0x20(%rbp), %rcx
callq 0x31160
jmp 0x309bd
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x98(%rbp)
movl %eax, -0x9c(%rbp)
leaq -0x168(%rbp), %rdi
callq 0x321f0
jmp 0x30b21
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x98(%rbp)
movl %eax, -0x9c(%rbp)
leaq -0x1d0(%rbp), %rdi
callq 0x321f0
jmp 0x30b21
jmp 0x30b18
movq -0x8(%rbp), %rax
testb $0x1, 0x60(%rax)
je 0x309ce
jmp 0x309ed
leaq 0x1ba27(%rip), %rdi     # 0x4c3fc
leaq 0x1b857(%rip), %rsi     # 0x4c233
movl $0x1ed, %edx            # imm = 0x1ED
leaq 0x1b981(%rip), %rcx     # 0x4c369
callq 0x81e0
movq -0x210(%rbp), %rsi
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rdi
movq -0x18(%rbp), %rdx
callq 0x31310
testb $0x1, %al
jne 0x30ad1
movq -0x18(%rbp), %rax
movl (%rax), %eax
andl $0x10000, %eax          # imm = 0x10000
cmpl $0x0, %eax
je 0x30acf
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x1d8(%rbp)
movq -0x1d8(%rbp), %rdi
callq 0x14c00
movq %rax, -0x1e0(%rbp)
movq -0x1d8(%rbp), %rdi
callq 0x14c30
movq %rax, -0x1e8(%rbp)
leaq -0x1e0(%rbp), %rdi
leaq -0x1e8(%rbp), %rsi
callq 0x14c60
testb $0x1, %al
jne 0x30a6f
jmp 0x30acd
leaq -0x1e0(%rbp), %rdi
callq 0xc8c0
movq %rax, %rcx
movq -0x210(%rbp), %rax
movq %rcx, -0x1f0(%rbp)
addq $0x28, %rax
movq %rax, -0x258(%rbp)
movq -0x1f0(%rbp), %rdi
callq 0x1f390
movq -0x258(%rbp), %rdi
movq %rax, %rsi
callq 0x18bd0
movq %rax, -0x200(%rbp)
movb %dl, -0x1f8(%rbp)
leaq -0x1e0(%rbp), %rdi
callq 0x14d30
jmp 0x30a56
jmp 0x30acf
jmp 0x30ad1
movq -0x210(%rbp), %rdi
movq -0x20(%rbp), %rax
movq %rax, -0x260(%rbp)
callq 0x32ae0
movq -0x260(%rbp), %rdi
movq %rax, %rsi
callq 0x32d70
jmp 0x30b18
leaq 0x1b91a(%rip), %rdi     # 0x4c41a
leaq 0x1b72c(%rip), %rsi     # 0x4c233
movl $0x1fb, %edx            # imm = 0x1FB
leaq 0x1b856(%rip), %rcx     # 0x4c369
callq 0x81e0
addq $0x260, %rsp            # imm = 0x260
popq %rbp
retq
movq -0x98(%rbp), %rdi
callq 0x85d0
nopl (%rax)