// File: ghallak[P]regex-to-dfa/src/RegexTree.cpp
// Function: RegexTree::BuildTree(std::basic_string_view<char, std::char_traits<char>>, bool)
std::unique_ptr<RegexTree::Node> RegexTree::BuildTree(std::string_view regex,
                                                      bool star) {
  if (regex.length() == 1 || (regex.front() == '\\' && regex.length() == 2)) {
    auto leaf = std::make_unique<LeafNode>(
        leaves.size(), regex.length() == 1 ? regex[0] : regex[1]);
    leaves.emplace_back(leaf.get());
    return leaf;
  }

  // ...|...
  int open_parens = 0;
  for (std::size_t i = 0; i < regex.length(); ++i) {
    // don't consider "\(" or "\)" as regex parens
    if (regex[i] == '\\') {
      ++i;
      continue;
    }

    open_parens += regex[i] == '(';
    open_parens -= regex[i] == ')';
    if (regex[i] == '|' && open_parens == 0) {
      return std::make_unique<UnionNode>(BuildTree(regex.substr(0, i)),
                                         BuildTree(regex.substr(i + 1)));
    }
  }

  // TODO: support escaping `*`, `(`, `)`, and `|` with `\`
  switch (regex.back()) {
    case '*': {
      return BuildTree(regex.substr(0, regex.length() - 1), true);
    }
    case ')': {
      const auto open_paren_idx = [&] {
        int close_parens = 1;
        for (std::size_t i = regex.length() - 2; i >= 0; --i) {
          close_parens += regex[i] == ')';
          close_parens -= regex[i] == '(';
          if (close_parens == 0) return i;
        }
        // unbalanced parens
        throw std::exception();
      }();

      // (...)
      if (open_paren_idx == 0) {
        if (star) {
          return std::make_unique<StarNode>(
              BuildTree(regex.substr(1, regex.length() - 2)));
        } else {
          return BuildTree(regex.substr(1, regex.length() - 2));
        }
      }
      // ...(...)
      else {
        auto left = BuildTree(regex.substr(0, open_paren_idx));
        auto right = [&]() -> std::unique_ptr<Node> {
          if (star) {
            return std::make_unique<StarNode>(
                BuildTree(regex.substr(open_paren_idx)));
          } else {
            return BuildTree(regex.substr(open_paren_idx));
          }
        }();
        return std::make_unique<ConcatNode>(std::move(left), std::move(right));
      }
    }
    default: {
      // ...
      auto left = BuildTree(regex.substr(0, regex.length() - 1));
      auto right = [&]() -> std::unique_ptr<Node> {
        if (star) {
          return std::make_unique<StarNode>(
              BuildTree(regex.substr(regex.length() - 1)));
        } else {
          return BuildTree(regex.substr(regex.length() - 1));
        }
      }();
      return std::make_unique<ConcatNode>(std::move(left), std::move(right));
    }
  }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x1f0, %rsp            # imm = 0x1F0
movq %rdi, -0x180(%rbp)
movb %r8b, %al
movq %rdi, %r8
movq %r8, -0x178(%rbp)
movq %rdi, -0x8(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x10(%rbp)
movq %rsi, -0x20(%rbp)
andb $0x1, %al
movb %al, -0x21(%rbp)
movq -0x20(%rbp), %rax
movq %rax, -0x170(%rbp)
leaq -0x18(%rbp), %rdi
callq 0xd5d0
cmpq $0x1, %rax
je 0xc266
leaq -0x18(%rbp), %rdi
callq 0xd5f0
movsbl (%rax), %eax
cmpl $0x5c, %eax
jne 0xc325
leaq -0x18(%rbp), %rdi
callq 0xd5d0
cmpq $0x2, %rax
jne 0xc325
movq -0x170(%rbp), %rdi
callq 0x5d70
movq %rax, -0x38(%rbp)
leaq -0x18(%rbp), %rdi
callq 0xd5d0
cmpq $0x1, %rax
jne 0xc29b
leaq -0x18(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0xd6a0
movq %rax, -0x188(%rbp)
jmp 0xc2b0
leaq -0x18(%rbp), %rdi
movl $0x1, %esi
callq 0xd6a0
movq %rax, -0x188(%rbp)
movq -0x188(%rbp), %rdx
leaq -0x30(%rbp), %rdi
movq %rdi, -0x190(%rbp)
leaq -0x38(%rbp), %rsi
callq 0xd610
movq -0x190(%rbp), %rdi
callq 0xd750
movq -0x170(%rbp), %rdi
movq %rax, -0x40(%rbp)
leaq -0x40(%rbp), %rsi
callq 0xd6d0
jmp 0xc2ed
movq -0x180(%rbp), %rdi
leaq -0x30(%rbp), %rsi
callq 0xd780
leaq -0x30(%rbp), %rdi
callq 0xd7d0
jmp 0xc943
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
leaq -0x30(%rbp), %rdi
callq 0xd7d0
jmp 0xc953
movl $0x0, -0x50(%rbp)
movq $0x0, -0x58(%rbp)
movq -0x58(%rbp), %rax
movq %rax, -0x198(%rbp)
leaq -0x18(%rbp), %rdi
callq 0xd5d0
movq %rax, %rcx
movq -0x198(%rbp), %rax
cmpq %rcx, %rax
jae 0xc51d
movq -0x58(%rbp), %rsi
leaq -0x18(%rbp), %rdi
callq 0xd6a0
movsbl (%rax), %eax
cmpl $0x5c, %eax
jne 0xc381
movq -0x58(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x58(%rbp)
jmp 0xc50c
movq -0x58(%rbp), %rsi
leaq -0x18(%rbp), %rdi
callq 0xd6a0
movsbl (%rax), %eax
cmpl $0x28, %eax
sete %al
andb $0x1, %al
movzbl %al, %eax
addl -0x50(%rbp), %eax
movl %eax, -0x50(%rbp)
movq -0x58(%rbp), %rsi
leaq -0x18(%rbp), %rdi
callq 0xd6a0
movsbl (%rax), %eax
cmpl $0x29, %eax
sete %al
andb $0x1, %al
movzbl %al, %ecx
movl -0x50(%rbp), %eax
subl %ecx, %eax
movl %eax, -0x50(%rbp)
movq -0x58(%rbp), %rsi
leaq -0x18(%rbp), %rdi
callq 0xd6a0
movsbl (%rax), %eax
cmpl $0x7c, %eax
jne 0xc50a
cmpl $0x0, -0x50(%rbp)
jne 0xc50a
movq -0x58(%rbp), %rdx
xorl %eax, %eax
movl %eax, -0x1b4(%rbp)
movl %eax, %esi
leaq -0x18(%rbp), %rdi
movq %rdi, -0x1b0(%rbp)
callq 0xd910
movq -0x170(%rbp), %rsi
movl -0x1b4(%rbp), %r8d
movq %rax, -0x78(%rbp)
movq %rdx, -0x70(%rbp)
movq -0x78(%rbp), %rdx
movq -0x70(%rbp), %rcx
leaq -0x68(%rbp), %rdi
callq 0xc1f0
movq -0x1b0(%rbp), %rdi
movq -0x58(%rbp), %rsi
incq %rsi
movq $-0x1, %rdx
callq 0xd910
movq %rdx, -0x1a8(%rbp)
movq %rax, -0x1a0(%rbp)
jmp 0xc457
movq -0x170(%rbp), %rsi
movq -0x1a8(%rbp), %rax
movq -0x1a0(%rbp), %rcx
movq %rcx, -0x90(%rbp)
movq %rax, -0x88(%rbp)
movq -0x90(%rbp), %rdx
movq -0x88(%rbp), %rcx
leaq -0x80(%rbp), %rdi
xorl %r8d, %r8d
callq 0xc1f0
jmp 0xc496
leaq -0x60(%rbp), %rdi
leaq -0x68(%rbp), %rsi
leaq -0x80(%rbp), %rdx
callq 0xd830
jmp 0xc4a9
movq -0x180(%rbp), %rdi
leaq -0x60(%rbp), %rsi
callq 0xd9a0
leaq -0x60(%rbp), %rdi
callq 0xd9f0
leaq -0x80(%rbp), %rdi
callq 0xb880
leaq -0x68(%rbp), %rdi
callq 0xb880
jmp 0xc943
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
jmp 0xc4fc
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
leaq -0x80(%rbp), %rdi
callq 0xb880
leaq -0x68(%rbp), %rdi
callq 0xb880
jmp 0xc953
jmp 0xc50c
movq -0x58(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x58(%rbp)
jmp 0xc334
leaq -0x18(%rbp), %rdi
callq 0xda50
movsbl (%rax), %eax
movl %eax, -0x1b8(%rbp)
subl $0x29, %eax
je 0xc59e
jmp 0xc536
movl -0x1b8(%rbp), %eax
subl $0x2a, %eax
jne 0xc81c
jmp 0xc547
leaq -0x18(%rbp), %rdi
callq 0xd5d0
movq %rax, %rdx
subq $0x1, %rdx
leaq -0x18(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0xd910
movq -0x180(%rbp), %rdi
movq -0x170(%rbp), %rsi
movq %rax, -0xa0(%rbp)
movq %rdx, -0x98(%rbp)
movq -0xa0(%rbp), %rdx
movq -0x98(%rbp), %rcx
movl $0x1, %r8d
callq 0xc1f0
jmp 0xc943
leaq -0x18(%rbp), %rax
movq %rax, -0xb0(%rbp)
leaq -0xb0(%rbp), %rdi
callq 0xc960
movq %rax, -0xa8(%rbp)
cmpq $0x0, -0xa8(%rbp)
jne 0xc6ec
testb $0x1, -0x21(%rbp)
je 0xc697
leaq -0x18(%rbp), %rdi
movq %rdi, -0x1c8(%rbp)
callq 0xd5d0
movq -0x1c8(%rbp), %rdi
movq %rax, %rdx
addq $-0x2, %rdx
movl $0x1, %esi
callq 0xd910
movq -0x170(%rbp), %rsi
movq %rax, -0xd0(%rbp)
movq %rdx, -0xc8(%rbp)
movq -0xd0(%rbp), %rdx
movq -0xc8(%rbp), %rcx
leaq -0xc0(%rbp), %rdi
movq %rdi, -0x1c0(%rbp)
xorl %r8d, %r8d
callq 0xc1f0
movq -0x1c0(%rbp), %rsi
leaq -0xb8(%rbp), %rdi
callq 0xda80
jmp 0xc64a
movq -0x180(%rbp), %rdi
leaq -0xb8(%rbp), %rsi
callq 0xdb30
leaq -0xb8(%rbp), %rdi
callq 0xdb80
leaq -0xc0(%rbp), %rdi
callq 0xb880
jmp 0xc943
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
leaq -0xc0(%rbp), %rdi
callq 0xb880
jmp 0xc953
leaq -0x18(%rbp), %rdi
callq 0xd5d0
movq %rax, %rdx
subq $0x2, %rdx
leaq -0x18(%rbp), %rdi
movl $0x1, %esi
callq 0xd910
movq -0x180(%rbp), %rdi
movq -0x170(%rbp), %rsi
movq %rax, -0xe0(%rbp)
movq %rdx, -0xd8(%rbp)
movq -0xe0(%rbp), %rdx
movq -0xd8(%rbp), %rcx
xorl %r8d, %r8d
callq 0xc1f0
jmp 0xc943
movq -0xa8(%rbp), %rdx
xorl %eax, %eax
movl %eax, -0x1d4(%rbp)
movl %eax, %esi
leaq -0x18(%rbp), %rdi
movq %rdi, -0x1d0(%rbp)
callq 0xd910
movl -0x1d4(%rbp), %r8d
movq -0x170(%rbp), %rsi
movq %rax, -0xf8(%rbp)
movq %rdx, -0xf0(%rbp)
movq -0xf8(%rbp), %rdx
movq -0xf0(%rbp), %rcx
leaq -0xe8(%rbp), %rdi
callq 0xc1f0
movq -0x170(%rbp), %rcx
movq -0x1d0(%rbp), %rax
leaq -0x21(%rbp), %rdx
movq %rdx, -0x120(%rbp)
movq %rcx, -0x118(%rbp)
movq %rax, -0x110(%rbp)
leaq -0xa8(%rbp), %rax
movq %rax, -0x108(%rbp)
leaq -0x100(%rbp), %rdi
leaq -0x120(%rbp), %rsi
callq 0xca30
jmp 0xc78d
leaq -0x128(%rbp), %rdi
leaq -0xe8(%rbp), %rsi
leaq -0x100(%rbp), %rdx
callq 0xdbe0
jmp 0xc7a9
movq -0x180(%rbp), %rdi
leaq -0x128(%rbp), %rsi
callq 0xdcc0
leaq -0x128(%rbp), %rdi
callq 0xdd10
leaq -0x100(%rbp), %rdi
callq 0xb880
leaq -0xe8(%rbp), %rdi
callq 0xb880
jmp 0xc943
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
jmp 0xc80b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
leaq -0x100(%rbp), %rdi
callq 0xb880
leaq -0xe8(%rbp), %rdi
callq 0xb880
jmp 0xc953
leaq -0x18(%rbp), %rdi
movq %rdi, -0x1e0(%rbp)
callq 0xd5d0
movq -0x1e0(%rbp), %rdi
movq %rax, %rdx
decq %rdx
xorl %eax, %eax
movl %eax, -0x1e4(%rbp)
movl %eax, %esi
callq 0xd910
movl -0x1e4(%rbp), %r8d
movq -0x170(%rbp), %rsi
movq %rax, -0x140(%rbp)
movq %rdx, -0x138(%rbp)
movq -0x140(%rbp), %rdx
movq -0x138(%rbp), %rcx
leaq -0x130(%rbp), %rdi
callq 0xc1f0
movq -0x170(%rbp), %rcx
movq -0x1e0(%rbp), %rax
leaq -0x21(%rbp), %rdx
movq %rdx, -0x160(%rbp)
movq %rcx, -0x158(%rbp)
movq %rax, -0x150(%rbp)
leaq -0x148(%rbp), %rdi
leaq -0x160(%rbp), %rsi
callq 0xcb50
jmp 0xc8ba
leaq -0x168(%rbp), %rdi
leaq -0x130(%rbp), %rsi
leaq -0x148(%rbp), %rdx
callq 0xdbe0
jmp 0xc8d6
movq -0x180(%rbp), %rdi
leaq -0x168(%rbp), %rsi
callq 0xdcc0
leaq -0x168(%rbp), %rdi
callq 0xdd10
leaq -0x148(%rbp), %rdi
callq 0xb880
leaq -0x130(%rbp), %rdi
callq 0xb880
jmp 0xc943
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
jmp 0xc935
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
leaq -0x148(%rbp), %rdi
callq 0xb880
leaq -0x130(%rbp), %rdi
callq 0xb880
jmp 0xc953
movq -0x178(%rbp), %rax
addq $0x1f0, %rsp            # imm = 0x1F0
popq %rbp
retq
movq -0x48(%rbp), %rdi
callq 0x2240
nopl (%rax)