Skip to content

Regular expressions

A pattern compiled from a bytes literal is matched natively over a byte buffer. The compiler reads the pattern with CPython's own parser and writes a matcher function for it, and a function that searches with it lowers like any other.

Run it

The input is 50,000 generated lines of name = value pairs, words, and hex numbers. The line starting with # is a timing; it differs between machines and between the two runs below.

python  patterns.ppy
ppy run patterns.ppy
ppy emit ir patterns.ppy
ppy emit c patterns.ppy

What it prints

python patterns.ppy

989986 bytes
119454 7 25007528 7143
True False
# four passes: 78.8 ms

ppy run patterns.ppy

989986 bytes
119454 7 25007528 7143
True False
# four passes: 9.7 ms

ppy emit ir patterns.ppy

1480 lines
ppyir 1
module @patterns
dialect core 1
dialect regex 1

func @patterns_count_words(%text: buffer<u8> {ownership = "borrowed", ppy.kind = "view"}) -> i64 attrs {effects = ["alloc", "may_raise", "read_memory"], ppy.abi = "ppy", ppy.qualname = "patterns.count_words", ppy.releases_gil = true, ppy.symbol = "ppy_patterns_count_words"} loc("examples/43_regex/patterns.ppy":15:0) {
^entry:
    %0 = core.const 0 : i64 loc("examples/43_regex/patterns.ppy":16:4)
    %n_addr = core.alloca : ptr<i64, stack>
    core.store %0, %n_addr
    %1 = core.const 0 : i64 loc("examples/43_regex/patterns.ppy":17:4)
    %pos_addr = core.alloca : ptr<i64, stack>
    core.store %1, %pos_addr
    %m_found_addr = core.alloca : ptr<bool, stack>
    %m_spans = core.alloca {count = 2} : ptr<i64, stack>
    %2 = core.const 0 : i64
    %3 = core.const 1 : i64
    %4 = core.const 1 : i64
    %5 = core.const 1 : i64
    core.br ^while.head1 loc("examples/43_regex/patterns.ppy":18:4)
^while.head1:
    %6 = core.load %pos_addr : i64 loc("examples/43_regex/patterns.ppy":19:8)
    %7 = core.buffer_len %text : index
    %8 = core.cast %7 : i64
    %9, %10, %11 = core.call %text, %6, %8 {callee = @ppy.regex.0} : bool, i64, i64
    core.store %9, %m_found_addr loc("examples/43_regex/patterns.ppy":19:8)
    %12 = core.ptr_offset %m_spans, %2 : ptr<i64, stack>
    core.store %10, %12
    %13 = core.ptr_offset %m_spans, %3 : ptr<i64, stack>
    core.store %11, %13
    %14 = core.load %m_found_addr : bool loc("examples/43_regex/patterns.ppy":20:8)
    %15 = core.const false : bool
    %16 = core.cmp.eq %14, %15 : bool
    core.cond_br %16, ^then4, ^else5
^then4:
    %17 = core.load %n_addr : i64 loc("examples/43_regex/patterns.ppy":21:12)
    core.ret %17
^else5:
    %18 = core.load %n_addr : i64 loc("examples/43_regex/patterns.ppy":22:8)
    %19 = core.add %18, %4 {overflow = "python"} : i64
    core.store %19, %n_addr
    %20 = core.ptr_offset %m_spans, %5 : ptr<i64, stack> loc("examples/43_regex/patterns.ppy":23:8)
    %21 = core.load %20 : i64
    core.store %21, %pos_addr
    core.br ^while.head1
}

func @patterns_longest_word(%text: buffer<u8> {ownership = "borrowed", ppy.kind = "view"}) -> i64 attrs {effects = ["alloc", "may_raise", "read_memory"], ppy.abi = "ppy", ppy.qualname = "patterns.longest_word", ppy.releases_gil = true, ppy.symbol = "ppy_patterns_longest_word"} loc("examples/43_regex/patterns.ppy":26:0) {
^entry:
    %0 = core.const 0 : i64 loc("examples/43_regex/patterns.ppy":27:4)
    %best_addr = core.alloca : ptr<i64, stack>
    core.store %0, %best_addr
    %1 = core.const 0 : i64 loc("examples/43_regex/patterns.ppy":28:4)
    %pos_addr = core.alloca : ptr<i64, stack>
    core.store %1, %pos_addr
    %m_found_addr = core.alloca : ptr<bool, stack>
    %m_spans = core.alloca {count = 2} : ptr<i64, stack>
    %2 = core.const 0 : i64
    %3 = core.const 1 : i64
    %4 = core.const 0 : i64
    %5 = core.const 1 : i64
    %start_addr = core.alloca : ptr<i64, stack>
    %end_addr = core.alloca : ptr<i64, stack>
    core.br ^while.head1 loc("examples/43_regex/patterns.ppy":29:4)
^while.head1:
    %6 = core.load %pos_addr : i64 loc("examples/43_regex/patterns.ppy":29:4)
    %7 = core.buffer_len %text : index
    %8 = core.cast %7 : i64
    %9 = core.cmp.lt %6, %8 : bool
    core.cond_br %9, ^while.body2, ^while.end3
^while.body2:
    %10 = core.load %pos_addr : i64 loc("examples/43_regex/patterns.ppy":30:8)
    %11 = core.buffer_len %text : index
    %12 = core.cast %11 : i64
    %13, %14, %15 = core.call %text, %10, %12 {callee = @ppy.regex.0} : bool, i64, i64
    core.store %13, %m_found_addr loc("examples/43_regex/patterns.ppy":30:8)
    %16 = core.ptr_offset %m_spans, %2 : ptr<i64, stack>
    core.store %14, %16
    %17 = core.ptr_offset %m_spans, %3 : ptr<i64, stack>
    core.store %15, %17
    %18 = core.load %m_found_addr : bool loc("examples/43_regex/patterns.ppy":31:8)
    %19 = core.const true : bool
    %20 = core.xor %18, %19 : bool
    core.cond_br %20, ^then4, ^else5
^while.end3:
    %21 = core.load %best_addr : i64 loc("examples/43_regex/patterns.ppy":36:4)
    core.ret %21
^then4:
    core.br ^while.end3 loc("examples/43_regex/patterns.ppy":32:12)
^else5:
    %22 = core.ptr_offset %m_spans, %4 : ptr<i64, stack> loc("examples/43_regex/patterns.ppy":33:8)
    %23 = core.load %22 : i64
    %24 = core.ptr_offset %m_spans, %5 : ptr<i64, stack>
    %25 = core.load %24 : i64
    core.store %23, %start_addr
    core.store %25, %end_addr
    %26 = core.load %best_addr : i64 loc("examples/43_regex/patterns.ppy":34:8)
    %27 = core.load %end_addr : i64
    %28 = core.load %start_addr : i64
    %29 = core.sub %27, %28 {overflow = "python"} : i64
    %30 = core.cmp.gt %29, %26 : bool
    %31 = core.select %30, %29, %26 : i64
    core.store %31, %best_addr
    %32 = core.load %end_addr : i64 loc("examples/43_regex/patterns.ppy":35:8)
    core.store %32, %pos_addr
    core.br ^while.head1
}

func @patterns_sum_values(%text: buffer<u8> {ownership = "borrowed", ppy.kind = "view"}) -> i64 attrs {effects = ["alloc", "may_raise", "read_memory"], ppy.abi = "ppy", ppy.qualname = "patterns.sum_values", ppy.releases_gil = true, ppy.symbol = "ppy_patterns_sum_values"} loc("examples/43_regex/patterns.ppy":39:0) {
^entry:
    %0 = core.const 0 : i64 loc("examples/43_regex/patterns.ppy":40:4)
    %total_addr = core.alloca : ptr<i64, stack>
    core.store %0, %total_addr
    %1 = core.const 0 : i64 loc("examples/43_regex/patterns.ppy":41:4)
    %pos_addr = core.alloca : ptr<i64, stack>
    core.store %1, %pos_addr
    %m_found_addr = core.alloca : ptr<bool, stack>
    %m_spans = core.alloca {count = 6} : ptr<i64, stack>
    %2 = core.const 0 : i64
    %3 = core.const 1 : i64
    %4 = core.const 2 : i64
    %5 = core.const 3 : i64
    %6 = core.const 4 : i64
    %7 = core.const 5 : i64
    %8 = core.const 0 : i64
    %value_addr = core.alloca : ptr<i64, stack>
    %9 = core.const 4 : i64
    %10 = core.const 5 : i64
    %11 = core.const 1 : i64
    %i_addr = core.alloca : ptr<i64, stack>
    %12 = core.const 10 : i64
    %13 = core.const 48 : i64
    %14 = core.const 1 : i64
    core.br ^while.head1 loc("examples/43_regex/patterns.ppy":42:4)
^while.head1:
    %15 = core.load %pos_addr : i64 loc("examples/43_regex/patterns.ppy":43:8)
    %16 = core.buffer_len %text : index
    %17 = core.cast %16 : i64
    %18, %19, %20, %21, %22, %23, %24 = core.call %text, %15, %17 {callee = @ppy.regex.1} : bool, i64, i64, i64, i64, i64, i64
    core.store %18, %m_found_addr loc("examples/43_regex/patterns.ppy":43:8)
    %25 = core.ptr_offset %m_spans, %2 : ptr<i64, stack>
    core.store %19, %25
    %26 = core.ptr_offset %m_spans, %3 : ptr<i64, stack>
    core.store %20, %26
    %27 = core.ptr_offset %m_spans, %4 : ptr<i64, stack>
    core.store %21, %27
    %28 = core.ptr_offset %m_spans, %5 : ptr<i64, stack>
    core.store %22, %28
    %29 = core.ptr_offset %m_spans, %6 : ptr<i64, stack>
    core.store %23, %29
    %30 = core.ptr_offset %m_spans, %7 : ptr<i64, stack>
    core.store %24, %30
    %31 = core.load %m_found_addr : bool loc("examples/43_regex/patterns.ppy":44:8)
    %32 = core.const false : bool
    %33 = core.cmp.eq %31, %32 : bool
    core.cond_br %33, ^then4, ^else5
^then4:
    %34 = core.load %total_addr : i64 loc("examples/43_regex/patterns.ppy":45:12)
    core.ret %34
^else5:
    core.store %8, %value_addr loc("examples/43_regex/patterns.ppy":46:8)
    %35 = core.ptr_offset %m_spans, %9 : ptr<i64, stack> loc("examples/43_regex/patterns.ppy":47:8)
    %36 = core.load %35 : i64
    %37 = core.ptr_offset %m_spans, %10 : ptr<i64, stack>
    %38 = core.load %37 : i64
    %39 = core.const 1 : i64
    %40 = core.sub %38, %39 {overflow = "wrap"} : i64
    %41 = core.const 0 : i64
    %42 = core.buffer_len %text : index
    %43 = core.cast %42 : i64
    %44 = core.cmp.ge %36, %41 : bool
    %45 = core.cmp.lt %40, %43 : bool
    %46 = core.and %44, %45 : bool
    core.guard %46 {kind = "bounds", message = "hoisted bounds check"}
    core.store %36, %i_addr loc("examples/43_regex/patterns.ppy":47:8)
    core.br ^for.head9
^for.head9:
    %47 = core.load %i_addr : i64 loc("examples/43_regex/patterns.ppy":47:8)
    %48 = core.cmp.lt %47, %38 : bool
    core.cond_br %48, ^for.body10, ^for.end12
^for.body10:
    %49 = core.load %value_addr : i64 loc("examples/43_regex/patterns.ppy":48:12)
    %50 = core.mul %49, %12 {overflow = "python"} : i64
    %51 = core.load %i_addr : i64
    %52 = core.buffer_load %text, %51 : u8
    %53 = core.cast %52 : i64
    %54 = core.sub %53, %13 {overflow = "python"} : i64
    %55 = core.add %50, %54 {overflow = "python"} : i64
    core.store %55, %value_addr
    %56 = core.load %i_addr : i64
    %57 = core.add %56, %11 {overflow = "python"} : i64
    core.store %57, %i_addr
    core.br ^for.head9
^for.end12:
    %58 = core.load %total_addr : i64 loc("examples/43_regex/patterns.ppy":49:8)
    %59 = core.load %value_addr : i64
    %60 = core.add %58, %59 {overflow = "python"} : i64
    core.store %60, %total_addr
    %61 = core.ptr_offset %m_spans, %14 : ptr<i64, stack> loc("examples/43_regex/patterns.ppy":50:8)
    %62 = core.load %61 : i64
    core.store %62, %pos_addr
    core.br ^while.head1
}

func @patterns_count_hex(%text: buffer<u8> {ownership = "borrowed", ppy.kind = "view"}) -> i64 attrs {effects = ["alloc", "may_raise", "read_memory"], ppy.abi = "ppy", ppy.qualname = "patterns.count_hex", ppy.releases_gil = true, ppy.symbol = "ppy_patterns_count_hex"} loc("examples/43_regex/patterns.ppy":53:0) {
^entry:
    %0 = core.const 0 : i64 loc("examples/43_regex/patterns.ppy":54:4)
    %n_addr = core.alloca : ptr<i64, stack>
    core.store %0, %n_addr
    %1 = core.const 0 : i64 loc("examples/43_regex/patterns.ppy":55:4)
    %pos_addr = core.alloca : ptr<i64, stack>
    core.store %1, %pos_addr
    %m_found_addr = core.alloca : ptr<bool, stack>
    %m_spans = core.alloca {count = 2} : ptr<i64, stack>
    %2 = core.const 0 : i64
    %3 = core.const 1 : i64
    %4 = core.const 1 : i64
    %5 = core.const 1 : i64
    core.br ^while.head1 loc("examples/43_regex/patterns.ppy":56:4)
^while.head1:
    %6 = core.load %pos_addr : i64 loc("examples/43_regex/patterns.ppy":57:8)
    %7 = core.buffer_len %text : index
    %8 = core.cast %7 : i64
    %9, %10, %11 = core.call %text, %6, %8 {callee = @ppy.regex.2} : bool, i64, i64
    core.store %9, %m_found_addr loc("examples/43_regex/patterns.ppy":57:8)
    %12 = core.ptr_offset %m_spans, %2 : ptr<i64, stack>
    core.store %10, %12
    %13 = core.ptr_offset %m_spans, %3 : ptr<i64, stack>
    core.store %11, %13
    %14 = core.load %m_found_addr : bool loc("examples/43_regex/patterns.ppy":58:8)
    %15 = core.const false : bool
    %16 = core.cmp.eq %14, %15 : bool
    core.cond_br %16, ^then4, ^else5
^then4:
    %17 = core.load %n_addr : i64 loc("examples/43_regex/patterns.ppy":59:12)
    core.ret %17
^else5:
    %18 = core.load %n_addr : i64 loc("examples/43_regex/patterns.ppy":60:8)
    %19 = core.add %18, %4 {overflow = "python"} : i64
    core.store %19, %n_addr
    %20 = core.ptr_offset %m_spans, %5 : ptr<i64, stack> loc("examples/43_regex/patterns.ppy":61:8)
    %21 = core.load %20 : i64
    core.store %21, %pos_addr
    core.br ^while.head1
}

func @patterns_is_identifier(%text: buffer<u8> {ownership = "borrowed", ppy.kind = "view"}) -> bool attrs {effects = ["alloc", "may_raise", "read_memory"], ppy.abi = "ppy", ppy.qualname = "patterns.is_identifier", ppy.releases_gil = true, ppy.symbol = "ppy_patterns_is_identifier"} loc("examples/43_regex/patterns.ppy":64:0) {
^entry:
    %0 = core.const 0 : i64 loc("examples/43_regex/patterns.ppy":65:4)
    %1 = core.buffer_len %text : index
    %2 = core.cast %1 : i64
    %3, %4, %5 = core.call %text, %0, %2 {callee = @ppy.regex.3} : bool, i64, i64
    core.ret %3 loc("examples/43_regex/patterns.ppy":65:4)
}

private func @ppy.regex.0(%buf: buffer<u8>, %pos: i64, %endpos: i64) -> (bool, i64, i64) attrs {ppy.regex = "[A-Za-z]+", ppy.synthesized = "regex.search"} {
^entry:
    %1 = core.buffer_len %buf : index
    %2 = core.cast %1 : i64
    %3 = core.const 0 : i64
    %4 = core.cmp.lt %endpos, %3 : bool
    %5 = core.select %4, %3, %endpos : i64
    %6 = core.cmp.gt %5, %2 : bool
    %7 = core.select %6, %2, %5 : i64
    %8 = core.cmp.lt %pos, %3 : bool
    %9 = core.select %8, %3, %pos : i64
    %10 = core.cmp.gt %9, %2 : bool
    %11 = core.select %10, %2, %9 : i64
    %p = core.alloca : ptr<i64, stack>
    %sp = core.alloca : ptr<i64, stack>
    %start = core.alloca : ptr<i64, stack>
    %stack = core.alloca {count = 12288} : ptr<i64, stack>
    %caps = core.alloca {count = 2} : ptr<i64, stack>
    %12 = core.const 0 : i64
    %13 = core.cmp.gt %11, %7 : bool
    core.cond_br %13, ^notfound4, ^attempt1(%11)
^attempt1(%s: i64):
    core.store %s, %p
    core.store %s, %start
    core.store %12, %sp
    %14 = core.const -1 : i64
    %15 = core.const 0 : i64
    %16 = core.ptr_offset %caps, %15 : ptr<i64, stack>
    core.store %14, %16
    %17 = core.const 1 : i64
    %18 = core.ptr_offset %caps, %17 : ptr<i64, stack>
    core.store %14, %18
    %19 = core.const 0 : i64
    %20 = core.ptr_offset %caps, %19 : ptr<i64, stack>
    core.store %s, %20
    %21 = core.load %p : i64
    %22 = core.const 1 : i64
    %23 = core.add %21, %22 {overflow = "proven"} : i64
    %24 = core.cmp.le %23, %7 : bool
    core.cond_br %24, ^fits7, ^fail2
^fail2:
    %25 = core.load %sp : i64
    %26 = core.const 0 : i64
    %27 = core.cmp.eq %25, %26 : bool
    core.cond_br %27, ^exhausted3, ^pop17
^exhausted3:
    %28 = core.load %start : i64
    %29 = core.const 1 : i64
    %30 = core.add %28, %29 {overflow = "proven"} : i64
    %31 = core.cmp.gt %30, %7 : bool
    core.cond_br %31, ^notfound4, ^attempt1(%30)
^notfound4:
    %32 = core.const false : bool
    %33 = core.const -1 : i64
    %34 = core.const -1 : i64
    core.ret %32, %33, %34
^fits7:
    core.br ^scan8(%21)
^scan8(%q: i64):
    %35 = core.cmp.lt %q, %7 : bool
    core.cond_br %35, ^bound9, ^scanned11(%q)
^bound9:
    %36 = core.buffer_load %buf, %q : u8
    %37 = core.cast %36 : i64
    %38 = core.const 65 : i64
    %39 = core.cmp.ge %37, %38 : bool
    %40 = core.const 90 : i64
    %41 = core.cmp.le %37, %40 : bool
    %42 = core.and %39, %41 : bool
    %43 = core.const 97 : i64
    %44 = core.cmp.ge %37, %43 : bool
    %45 = core.const 122 : i64
    %46 = core.cmp.le %37, %45 : bool
    %47 = core.and %44, %46 : bool
    %48 = core.or %42, %47 : bool
    %49 = core.const 1 : i64
    %50 = core.add %q, %49 {overflow = "proven"} : i64
    core.cond_br %48, ^scan8(%50), ^scanned11(%q)
^scanned11(%0: i64):
    %51 = core.const 1 : i64
    %52 = core.add %21, %51 {overflow = "proven"} : i64
    %53 = core.cmp.lt %0, %52 : bool
    core.cond_br %53, ^fail2, ^enough13
^exit12:
    %54 = core.load %p : i64
    %55 = core.const 1 : i64
    %56 = core.ptr_offset %caps, %55 : ptr<i64, stack>
    core.store %54, %56
    %57 = core.const true : bool
    %58 = core.const 0 : i64
    %59 = core.ptr_offset %caps, %58 : ptr<i64, stack>
    %60 = core.load %59 : i64
    %61 = core.const 1 : i64
    %62 = core.ptr_offset %caps, %61 : ptr<i64, stack>
    %63 = core.load %62 : i64
    core.ret %57, %60, %63
^enough13:
    core.store %0, %p
    %64 = core.cmp.gt %0, %52 : bool
    core.cond_br %64, ^keep15, ^exit12
^giveback14(%held: i64):
    %65 = core.load %p : i64
    %66 = core.const 1 : i64
    %67 = core.sub %65, %66 {overflow = "proven"} : i64
    core.store %67, %p
    %68 = core.cmp.gt %67, %held : bool
    core.cond_br %68, ^keep16, ^exit12
^keep15:
    %69 = core.load %sp : i64
    %70 = core.const 4096 : i64
    %71 = core.cmp.lt %69, %70 : bool
    core.guard %71 {kind = "range", label = "regex.stack.ok"}
    %72 = core.const 3 : i64
    %73 = core.mul %69, %72 {overflow = "proven"} : i64
    %74 = core.ptr_offset %stack, %73 : ptr<i64, stack>
    %75 = core.const 0 : i64
    %76 = core.load %p : i64
    %77 = core.const 0 : i64
    %78 = core.ptr_offset %74, %77 : ptr<i64, stack>
    core.store %75, %78
    %79 = core.const 1 : i64
    %80 = core.ptr_offset %74, %79 : ptr<i64, stack>
    core.store %76, %80
    %81 = core.const 2 : i64
    %82 = core.ptr_offset %74, %81 : ptr<i64, stack>
    core.store %52, %82
    %83 = core.const 1 : i64
    %84 = core.add %69, %83 {overflow = "proven"} : i64
    core.store %84, %sp
    core.br ^exit12
^keep16:
    %85 = core.load %sp : i64
    %86 = core.const 4096 : i64
    %87 = core.cmp.lt %85, %86 : bool
    core.guard %87 {kind = "range", label = "regex.stack.ok"}
    %88 = core.const 3 : i64
    %89 = core.mul %85, %88 {overflow = "proven"} : i64
    %90 = core.ptr_offset %stack, %89 : ptr<i64, stack>
    %91 = core.const 0 : i64
    %92 = core.load %p : i64
    %93 = core.const 0 : i64
    %94 = core.ptr_offset %90, %93 : ptr<i64, stack>
    core.store %91, %94
    %95 = core.const 1 : i64
    %96 = core.ptr_offset %90, %95 : ptr<i64, stack>
    core.store %92, %96
    %97 = core.const 2 : i64
    %98 = core.ptr_offset %90, %97 : ptr<i64, stack>
    core.store %held, %98
    %99 = core.const 1 : i64
    %100 = core.add %85, %99 {overflow = "proven"} : i64
    core.store %100, %sp
    core.br ^exit12
^pop17:
    %101 = core.const 1 : i64
    %102 = core.sub %25, %101 {overflow = "proven"} : i64
    core.store %102, %sp
    %103 = core.const 3 : i64
    %104 = core.mul %102, %103 {overflow = "proven"} : i64
    %105 = core.ptr_offset %stack, %104 : ptr<i64, stack>
    %106 = core.const 0 : i64
    %107 = core.ptr_offset %105, %106 : ptr<i64, stack>
    %108 = core.load %107 : i64
    %109 = core.const 1 : i64
    %110 = core.ptr_offset %105, %109 : ptr<i64, stack>
    %111 = core.load %110 : i64
    core.store %111, %p
    %112 = core.const 2 : i64
    %113 = core.ptr_offset %105, %112 : ptr<i64, stack>
    %114 = core.load %113 : i64
    %115 = core.const 0 : i64
    %116 = core.cmp.eq %108, %115 : bool
    core.cond_br %116, ^giveback14(%114), ^dispatch18
^dispatch18:
    core.unreachable
}

private func @ppy.regex.1(%buf: buffer<u8>, %pos: i64, %endpos: i64) -> (bool, i64, i64, i64, i64, i64, i64) attrs {ppy.regex = "(?P<key>\\w+)\\s*=\\s*(\\d+)", ppy.synthesized = "regex.search"} {
^entry:
    %14 = core.buffer_len %buf : index
    %15 = core.cast %14 : i64
    %16 = core.const 0 : i64
    %17 = core.cmp.lt %endpos, %16 : bool
    %18 = core.select %17, %16, %endpos : i64
    %19 = core.cmp.gt %18, %15 : bool
    %20 = core.select %19, %15, %18 : i64
    %21 = core.cmp.lt %pos, %16 : bool
    %22 = core.select %21, %16, %pos : i64
    %23 = core.cmp.gt %22, %15 : bool
    %24 = core.select %23, %15, %22 : i64
    %p = core.alloca : ptr<i64, stack>
    %sp = core.alloca : ptr<i64, stack>
    %start = core.alloca : ptr<i64, stack>
    %stack = core.alloca {count = 12288} : ptr<i64, stack>
    %caps = core.alloca {count = 6} : ptr<i64, stack>
    %25 = core.const 0 : i64
    %26 = core.cmp.gt %24, %20 : bool
    core.cond_br %26, ^notfound4, ^attempt1(%24)
^attempt1(%s: i64):
    core.store %s, %p
    core.store %s, %start
    core.store %25, %sp
    %27 = core.const -1 : i64
    %28 = core.const 0 : i64
    %29 = core.ptr_offset %caps, %28 : ptr<i64, stack>
    core.store %27, %29
    %30 = core.const 1 : i64
    %31 = core.ptr_offset %caps, %30 : ptr<i64, stack>
    core.store %27, %31
    %32 = core.const 2 : i64
    %33 = core.ptr_offset %caps, %32 : ptr<i64, stack>
    core.store %27, %33
    %34 = core.const 3 : i64
    %35 = core.ptr_offset %caps, %34 : ptr<i64, stack>
    core.store %27, %35
    %36 = core.const 4 : i64
    %37 = core.ptr_offset %caps, %36 : ptr<i64, stack>
    core.store %27, %37
    %38 = core.const 5 : i64
    %39 = core.ptr_offset %caps, %38 : ptr<i64, stack>
    core.store %27, %39
    %40 = core.const 0 : i64
    %41 = core.ptr_offset %caps, %40 : ptr<i64, stack>
    core.store %s, %41
    %42 = core.const 2 : i64
    %43 = core.ptr_offset %caps, %42 : ptr<i64, stack>
    %44 = core.load %43 : i64
    %45 = core.load %sp : i64
    %46 = core.const 4096 : i64
    %47 = core.cmp.lt %45, %46 : bool
    core.guard %47 {kind = "range", label = "regex.stack.ok"}
    %48 = core.const 3 : i64
    %49 = core.mul %45, %48 {overflow = "proven"} : i64
    %50 = core.ptr_offset %stack, %49 : ptr<i64, stack>
    %51 = core.const 0 : i64
    %52 = core.load %p : i64
    %53 = core.const 0 : i64
    %54 = core.ptr_offset %50, %53 : ptr<i64, stack>
    core.store %51, %54
    %55 = core.const 1 : i64
    %56 = core.ptr_offset %50, %55 : ptr<i64, stack>
    core.store %52, %56
    %57 = core.const 2 : i64
    %58 = core.ptr_offset %50, %57 : ptr<i64, stack>
    core.store %44, %58
    %59 = core.const 1 : i64
    %60 = core.add %45, %59 {overflow = "proven"} : i64
    core.store %60, %sp
    %61 = core.load %p : i64
    %62 = core.const 2 : i64
    %63 = core.ptr_offset %caps, %62 : ptr<i64, stack>
    core.store %61, %63
    %64 = core.load %p : i64
    %65 = core.const 1 : i64
    %66 = core.add %64, %65 {overflow = "proven"} : i64
    %67 = core.cmp.le %66, %20 : bool
    core.cond_br %67, ^fits8, ^fail2
^fail2:
    %68 = core.load %sp : i64
    %69 = core.const 0 : i64
    %70 = core.cmp.eq %68, %69 : bool
    core.cond_br %70, ^exhausted3, ^pop53
^exhausted3:
    %71 = core.load %start : i64
    %72 = core.const 1 : i64
    %73 = core.add %71, %72 {overflow = "proven"} : i64
    %74 = core.cmp.gt %73, %20 : bool
    core.cond_br %74, ^notfound4, ^attempt1(%73)
^notfound4:
    %75 = core.const false : bool
    %76 = core.const -1 : i64
    %77 = core.const -1 : i64
    %78 = core.const -1 : i64
    %79 = core.const -1 : i64
    %80 = core.const -1 : i64
    %81 = core.const -1 : i64
    core.ret %75, %76, %77, %78, %79, %80, %81
^restore7(%held: i64):
    %82 = core.const 2 : i64
    %83 = core.ptr_offset %caps, %82 : ptr<i64, stack>
    core.store %held, %83
    core.br ^fail2
^fits8:
    core.br ^scan9(%64)
^scan9(%q: i64):
    %84 = core.cmp.lt %q, %20 : bool
    core.cond_br %84, ^bound10, ^scanned12(%q)
^bound10:
    %85 = core.buffer_load %buf, %q : u8
    %86 = core.cast %85 : i64
    %87 = core.const 0 : i64
    %88 = core.const 192 : i64
    %89 = core.cmp.lt %86, %88 : bool
    %90 = core.const 0 : i64
    %91 = core.select %89, %90, %87 : i64
    %92 = core.const 128 : i64
    %93 = core.cmp.lt %86, %92 : bool
    %94 = core.const 576460745995190270 : i64
    %95 = core.select %93, %94, %91 : i64
    %96 = core.const 64 : i64
    %97 = core.cmp.lt %86, %96 : bool
    %98 = core.const 287948901175001088 : i64
    %99 = core.select %97, %98, %95 : i64
    %100 = core.const 63 : i64
    %101 = core.and %86, %100 : i64
    %102 = core.shr %99, %101 : i64
    %103 = core.const 1 : i64
    %104 = core.and %102, %103 : i64
    %105 = core.const 0 : i64
    %106 = core.cmp.ne %104, %105 : bool
    %107 = core.const 1 : i64
    %108 = core.add %q, %107 {overflow = "proven"} : i64
    core.cond_br %106, ^scan9(%108), ^scanned12(%q)
^scanned12(%0: i64):
    %109 = core.const 1 : i64
    %110 = core.add %64, %109 {overflow = "proven"} : i64
    %111 = core.cmp.lt %0, %110 : bool
    core.cond_br %111, ^fail2, ^enough14
^exit13:
    %112 = core.const 3 : i64
    %113 = core.ptr_offset %caps, %112 : ptr<i64, stack>
    %114 = core.load %113 : i64
    %115 = core.load %sp : i64
    %116 = core.const 4096 : i64
    %117 = core.cmp.lt %115, %116 : bool
    core.guard %117 {kind = "range", label = "regex.stack.ok"}
    %118 = core.const 3 : i64
    %119 = core.mul %115, %118 {overflow = "proven"} : i64
    %120 = core.ptr_offset %stack, %119 : ptr<i64, stack>
    %121 = core.const 2 : i64
    %122 = core.load %p : i64
    %123 = core.const 0 : i64
    %124 = core.ptr_offset %120, %123 : ptr<i64, stack>
    core.store %121, %124
    %125 = core.const 1 : i64
    %126 = core.ptr_offset %120, %125 : ptr<i64, stack>
    core.store %122, %126
    %127 = core.const 2 : i64
    %128 = core.ptr_offset %120, %127 : ptr<i64, stack>
    core.store %114, %128
    %129 = core.const 1 : i64
    %130 = core.add %115, %129 {overflow = "proven"} : i64
    core.store %130, %sp
    %131 = core.load %p : i64
    %132 = core.const 3 : i64
    %133 = core.ptr_offset %caps, %132 : ptr<i64, stack>
    core.store %131, %133
    %134 = core.load %p : i64
    %135 = core.cmp.le %134, %20 : bool
    core.cond_br %135, ^fits19, ^fail2
^enough14:
    core.store %0, %p
    %136 = core.cmp.gt %0, %110 : bool
    core.cond_br %136, ^keep16, ^exit13
^giveback15(%1: i64):
    %137 = core.load %p : i64
    %138 = core.const 1 : i64
    %139 = core.sub %137, %138 {overflow = "proven"} : i64
    core.store %139, %p
    %140 = core.cmp.gt %139, %1 : bool
    core.cond_br %140, ^keep17, ^exit13
^keep16:
    %141 = core.load %sp : i64
    %142 = core.const 4096 : i64
    %143 = core.cmp.lt %141, %142 : bool
    core.guard %143 {kind = "range", label = "regex.stack.ok"}
    %144 = core.const 3 : i64
    %145 = core.mul %141, %144 {overflow = "proven"} : i64
    %146 = core.ptr_offset %stack, %145 : ptr<i64, stack>
    %147 = core.const 1 : i64
    %148 = core.load %p : i64
    %149 = core.const 0 : i64
    %150 = core.ptr_offset %146, %149 : ptr<i64, stack>
    core.store %147, %150
    %151 = core.const 1 : i64
    %152 = core.ptr_offset %146, %151 : ptr<i64, stack>
    core.store %148, %152
    %153 = core.const 2 : i64
    %154 = core.ptr_offset %146, %153 : ptr<i64, stack>
    core.store %110, %154
    %155 = core.const 1 : i64
    %156 = core.add %141, %155 {overflow = "proven"} : i64
    core.store %156, %sp
    core.br ^exit13
^keep17:
    %157 = core.load %sp : i64
    %158 = core.const 4096 : i64
    %159 = core.cmp.lt %157, %158 : bool
    core.guard %159 {kind = "range", label = "regex.stack.ok"}
    %160 = core.const 3 : i64
    %161 = core.mul %157, %160 {overflow = "proven"} : i64
    %162 = core.ptr_offset %stack, %161 : ptr<i64, stack>
    %163 = core.const 1 : i64
    %164 = core.load %p : i64
    %165 = core.const 0 : i64
    %166 = core.ptr_offset %162, %165 : ptr<i64, stack>
    core.store %163, %166
    %167 = core.const 1 : i64
    %168 = core.ptr_offset %162, %167 : ptr<i64, stack>
    core.store %164, %168
    %169 = core.const 2 : i64
    %170 = core.ptr_offset %162, %169 : ptr<i64, stack>
    core.store %1, %170
    %171 = core.const 1 : i64
    %172 = core.add %157, %171 {overflow = "proven"} : i64
    core.store %172, %sp
    core.br ^exit13
^restore18(%2: i64):
    %173 = core.const 3 : i64
    %174 = core.ptr_offset %caps, %173 : ptr<i64, stack>
    core.store %2, %174
    core.br ^fail2
^fits19:
    core.br ^scan20(%134)
^scan20(%3: i64):
    %175 = core.cmp.lt %3, %20 : bool
    core.cond_br %175, ^bound21, ^scanned23(%3)
^bound21:
    %176 = core.buffer_load %buf, %3 : u8
    %177 = core.cast %176 : i64
    %178 = core.const 9 : i64
    %179 = core.cmp.ge %177, %178 : bool
    %180 = core.const 13 : i64
    %181 = core.cmp.le %177, %180 : bool
    %182 = core.and %179, %181 : bool
    %183 = core.const 32 : i64
    %184 = core.cmp.eq %177, %183 : bool
    %185 = core.or %182, %184 : bool
    %186 = core.const 1 : i64
    %187 = core.add %3, %186 {overflow = "proven"} : i64
    core.cond_br %185, ^scan20(%187), ^scanned23(%3)
^scanned23(%4: i64):
    %188 = core.cmp.lt %4, %134 : bool
    core.cond_br %188, ^fail2, ^enough25
^exit24:
    %189 = core.load %p : i64
    %190 = core.cmp.lt %189, %20 : bool
    core.cond_br %190, ^read29, ^fail2
^enough25:
    core.store %4, %p
    %191 = core.cmp.gt %4, %134 : bool
    core.cond_br %191, ^keep27, ^exit24
^giveback26(%5: i64):
    %192 = core.load %p : i64
    %193 = core.const 1 : i64
    %194 = core.sub %192, %193 {overflow = "proven"} : i64
    core.store %194, %p
    %195 = core.cmp.gt %194, %5 : bool
    core.cond_br %195, ^keep28, ^exit24
^keep27:
    %196 = core.load %sp : i64
    %197 = core.const 4096 : i64
    %198 = core.cmp.lt %196, %197 : bool
    core.guard %198 {kind = "range", label = "regex.stack.ok"}
    %199 = core.const 3 : i64
    %200 = core.mul %196, %199 {overflow = "proven"} : i64
    %201 = core.ptr_offset %stack, %200 : ptr<i64, stack>
    %202 = core.const 3 : i64
    %203 = core.load %p : i64
    %204 = core.const 0 : i64
    %205 = core.ptr_offset %201, %204 : ptr<i64, stack>
    core.store %202, %205
    %206 = core.const 1 : i64
    %207 = core.ptr_offset %201, %206 : ptr<i64, stack>
    core.store %203, %207
    %208 = core.const 2 : i64
    %209 = core.ptr_offset %201, %208 : ptr<i64, stack>
    core.store %134, %209
    %210 = core.const 1 : i64
    %211 = core.add %196, %210 {overflow = "proven"} : i64
    core.store %211, %sp
    core.br ^exit24
^keep28:
    %212 = core.load %sp : i64
    %213 = core.const 4096 : i64
    %214 = core.cmp.lt %212, %213 : bool
    core.guard %214 {kind = "range", label = "regex.stack.ok"}
    %215 = core.const 3 : i64
    %216 = core.mul %212, %215 {overflow = "proven"} : i64
    %217 = core.ptr_offset %stack, %216 : ptr<i64, stack>
    %218 = core.const 3 : i64
    %219 = core.load %p : i64
    %220 = core.const 0 : i64
    %221 = core.ptr_offset %217, %220 : ptr<i64, stack>
    core.store %218, %221
    %222 = core.const 1 : i64
    %223 = core.ptr_offset %217, %222 : ptr<i64, stack>
    core.store %219, %223
    %224 = core.const 2 : i64
    %225 = core.ptr_offset %217, %224 : ptr<i64, stack>
    core.store %5, %225
    %226 = core.const 1 : i64
    %227 = core.add %212, %226 {overflow = "proven"} : i64
    core.store %227, %sp
    core.br ^exit24
^read29:
    %228 = core.buffer_load %buf, %189 : u8
    %229 = core.cast %228 : i64
    %230 = core.const 61 : i64
    %231 = core.cmp.eq %229, %230 : bool
    core.cond_br %231, ^advance30, ^fail2
^advance30:
    %232 = core.const 1 : i64
    %233 = core.add %189, %232 {overflow = "proven"} : i64
    core.store %233, %p
    %234 = core.load %p : i64
    %235 = core.cmp.le %234, %20 : bool
    core.cond_br %235, ^fits31, ^fail2
^fits31:
    core.br ^scan32(%234)
^scan32(%6: i64):
    %236 = core.cmp.lt %6, %20 : bool
    core.cond_br %236, ^bound33, ^scanned35(%6)
^bound33:
    %237 = core.buffer_load %buf, %6 : u8
    %238 = core.cast %237 : i64
    %239 = core.const 9 : i64
    %240 = core.cmp.ge %238, %239 : bool
    %241 = core.const 13 : i64
    %242 = core.cmp.le %238, %241 : bool
    %243 = core.and %240, %242 : bool
    %244 = core.const 32 : i64
    %245 = core.cmp.eq %238, %244 : bool
    %246 = core.or %243, %245 : bool
    %247 = core.const 1 : i64
    %248 = core.add %6, %247 {overflow = "proven"} : i64
    core.cond_br %246, ^scan32(%248), ^scanned35(%6)
^scanned35(%7: i64):
    %249 = core.cmp.lt %7, %234 : bool
    core.cond_br %249, ^fail2, ^enough37
^exit36:
    %250 = core.const 4 : i64
    %251 = core.ptr_offset %caps, %250 : ptr<i64, stack>
    %252 = core.load %251 : i64
    %253 = core.load %sp : i64
    %254 = core.const 4096 : i64
    %255 = core.cmp.lt %253, %254 : bool
    core.guard %255 {kind = "range", label = "regex.stack.ok"}
    %256 = core.const 3 : i64
    %257 = core.mul %253, %256 {overflow = "proven"} : i64
    %258 = core.ptr_offset %stack, %257 : ptr<i64, stack>
    %259 = core.const 5 : i64
    %260 = core.load %p : i64
    %261 = core.const 0 : i64
    %262 = core.ptr_offset %258, %261 : ptr<i64, stack>
    core.store %259, %262
    %263 = core.const 1 : i64
    %264 = core.ptr_offset %258, %263 : ptr<i64, stack>
    core.store %260, %264
    %265 = core.const 2 : i64
    %266 = core.ptr_offset %258, %265 : ptr<i64, stack>
    core.store %252, %266
    %267 = core.const 1 : i64
    %268 = core.add %253, %267 {overflow = "proven"} : i64
    core.store %268, %sp
    %269 = core.load %p : i64
    %270 = core.const 4 : i64
    %271 = core.ptr_offset %caps, %270 : ptr<i64, stack>
    core.store %269, %271
    %272 = core.load %p : i64
    %273 = core.const 1 : i64
    %274 = core.add %272, %273 {overflow = "proven"} : i64
    %275 = core.cmp.le %274, %20 : bool
    core.cond_br %275, ^fits42, ^fail2
^enough37:
    core.store %7, %p
    %276 = core.cmp.gt %7, %234 : bool
    core.cond_br %276, ^keep39, ^exit36
^giveback38(%8: i64):
    %277 = core.load %p : i64
    %278 = core.const 1 : i64
    %279 = core.sub %277, %278 {overflow = "proven"} : i64
    core.store %279, %p
    %280 = core.cmp.gt %279, %8 : bool
    core.cond_br %280, ^keep40, ^exit36
^keep39:
    %281 = core.load %sp : i64
    %282 = core.const 4096 : i64
    %283 = core.cmp.lt %281, %282 : bool
    core.guard %283 {kind = "range", label = "regex.stack.ok"}
    %284 = core.const 3 : i64
    %285 = core.mul %281, %284 {overflow = "proven"} : i64
    %286 = core.ptr_offset %stack, %285 : ptr<i64, stack>
    %287 = core.const 4 : i64
    %288 = core.load %p : i64
    %289 = core.const 0 : i64
    %290 = core.ptr_offset %286, %289 : ptr<i64, stack>
    core.store %287, %290
    %291 = core.const 1 : i64
    %292 = core.ptr_offset %286, %291 : ptr<i64, stack>
    core.store %288, %292
    %293 = core.const 2 : i64
    %294 = core.ptr_offset %286, %293 : ptr<i64, stack>
    core.store %234, %294
    %295 = core.const 1 : i64
    %296 = core.add %281, %295 {overflow = "proven"} : i64
    core.store %296, %sp
    core.br ^exit36
^keep40:
    %297 = core.load %sp : i64
    %298 = core.const 4096 : i64
    %299 = core.cmp.lt %297, %298 : bool
    core.guard %299 {kind = "range", label = "regex.stack.ok"}
    %300 = core.const 3 : i64
    %301 = core.mul %297, %300 {overflow = "proven"} : i64
    %302 = core.ptr_offset %stack, %301 : ptr<i64, stack>
    %303 = core.const 4 : i64
    %304 = core.load %p : i64
    %305 = core.const 0 : i64
    %306 = core.ptr_offset %302, %305 : ptr<i64, stack>
    core.store %303, %306
    %307 = core.const 1 : i64
    %308 = core.ptr_offset %302, %307 : ptr<i64, stack>
    core.store %304, %308
    %309 = core.const 2 : i64
    %310 = core.ptr_offset %302, %309 : ptr<i64, stack>
    core.store %8, %310
    %311 = core.const 1 : i64
    %312 = core.add %297, %311 {overflow = "proven"} : i64
    core.store %312, %sp
    core.br ^exit36
^restore41(%9: i64):
    %313 = core.const 4 : i64
    %314 = core.ptr_offset %caps, %313 : ptr<i64, stack>
    core.store %9, %314
    core.br ^fail2
^fits42:
    core.br ^scan43(%272)
^scan43(%10: i64):
    %315 = core.cmp.lt %10, %20 : bool
    core.cond_br %315, ^bound44, ^scanned46(%10)
^bound44:
    %316 = core.buffer_load %buf, %10 : u8
    %317 = core.cast %316 : i64
    %318 = core.const 48 : i64
    %319 = core.cmp.ge %317, %318 : bool
    %320 = core.const 57 : i64
    %321 = core.cmp.le %317, %320 : bool
    %322 = core.and %319, %321 : bool
    %323 = core.const 1 : i64
    %324 = core.add %10, %323 {overflow = "proven"} : i64
    core.cond_br %322, ^scan43(%324), ^scanned46(%10)
^scanned46(%11: i64):
    %325 = core.const 1 : i64
    %326 = core.add %272, %325 {overflow = "proven"} : i64
    %327 = core.cmp.lt %11, %326 : bool
    core.cond_br %327, ^fail2, ^enough48
^exit47:
    %328 = core.const 5 : i64
    %329 = core.ptr_offset %caps, %328 : ptr<i64, stack>
    %330 = core.load %329 : i64
    %331 = core.load %sp : i64
    %332 = core.const 4096 : i64
    %333 = core.cmp.lt %331, %332 : bool
    core.guard %333 {kind = "range", label = "regex.stack.ok"}
    %334 = core.const 3 : i64
    %335 = core.mul %331, %334 {overflow = "proven"} : i64
    %336 = core.ptr_offset %stack, %335 : ptr<i64, stack>
    %337 = core.const 7 : i64
    %338 = core.load %p : i64
    %339 = core.const 0 : i64
    %340 = core.ptr_offset %336, %339 : ptr<i64, stack>
    core.store %337, %340
    %341 = core.const 1 : i64
    %342 = core.ptr_offset %336, %341 : ptr<i64, stack>
    core.store %338, %342
    %343 = core.const 2 : i64
    %344 = core.ptr_offset %336, %343 : ptr<i64, stack>
    core.store %330, %344
    %345 = core.const 1 : i64
    %346 = core.add %331, %345 {overflow = "proven"} : i64
    core.store %346, %sp
    %347 = core.load %p : i64
    %348 = core.const 5 : i64
    %349 = core.ptr_offset %caps, %348 : ptr<i64, stack>
    core.store %347, %349
    %350 = core.load %p : i64
    %351 = core.const 1 : i64
    %352 = core.ptr_offset %caps, %351 : ptr<i64, stack>
    core.store %350, %352
    %353 = core.const true : bool
    %354 = core.const 0 : i64
    %355 = core.ptr_offset %caps, %354 : ptr<i64, stack>
    %356 = core.load %355 : i64
    %357 = core.const 1 : i64
    %358 = core.ptr_offset %caps, %357 : ptr<i64, stack>
    %359 = core.load %358 : i64
    %360 = core.const 2 : i64
    %361 = core.ptr_offset %caps, %360 : ptr<i64, stack>
    %362 = core.load %361 : i64
    %363 = core.const 3 : i64
    %364 = core.ptr_offset %caps, %363 : ptr<i64, stack>
    %365 = core.load %364 : i64
    %366 = core.const 4 : i64
    %367 = core.ptr_offset %caps, %366 : ptr<i64, stack>
    %368 = core.load %367 : i64
    %369 = core.const 5 : i64
    %370 = core.ptr_offset %caps, %369 : ptr<i64, stack>
    %371 = core.load %370 : i64
    core.ret %353, %356, %359, %362, %365, %368, %371
^enough48:
    core.store %11, %p
    %372 = core.cmp.gt %11, %326 : bool
    core.cond_br %372, ^keep50, ^exit47
^giveback49(%12: i64):
    %373 = core.load %p : i64
    %374 = core.const 1 : i64
    %375 = core.sub %373, %374 {overflow = "proven"} : i64
    core.store %375, %p
    %376 = core.cmp.gt %375, %12 : bool
    core.cond_br %376, ^keep51, ^exit47
^keep50:
    %377 = core.load %sp : i64
    %378 = core.const 4096 : i64
    %379 = core.cmp.lt %377, %378 : bool
    core.guard %379 {kind = "range", label = "regex.stack.ok"}
    %380 = core.const 3 : i64
    %381 = core.mul %377, %380 {overflow = "proven"} : i64
    %382 = core.ptr_offset %stack, %381 : ptr<i64, stack>
    %383 = core.const 6 : i64
    %384 = core.load %p : i64
    %385 = core.const 0 : i64
    %386 = core.ptr_offset %382, %385 : ptr<i64, stack>
    core.store %383, %386
    %387 = core.const 1 : i64
    %388 = core.ptr_offset %382, %387 : ptr<i64, stack>
    core.store %384, %388
    %389 = core.const 2 : i64
    %390 = core.ptr_offset %382, %389 : ptr<i64, stack>
    core.store %326, %390
    %391 = core.const 1 : i64
    %392 = core.add %377, %391 {overflow = "proven"} : i64
    core.store %392, %sp
    core.br ^exit47
^keep51:
    %393 = core.load %sp : i64
    %394 = core.const 4096 : i64
    %395 = core.cmp.lt %393, %394 : bool
    core.guard %395 {kind = "range", label = "regex.stack.ok"}
    %396 = core.const 3 : i64
    %397 = core.mul %393, %396 {overflow = "proven"} : i64
    %398 = core.ptr_offset %stack, %397 : ptr<i64, stack>
    %399 = core.const 6 : i64
    %400 = core.load %p : i64
    %401 = core.const 0 : i64
    %402 = core.ptr_offset %398, %401 : ptr<i64, stack>
    core.store %399, %402
    %403 = core.const 1 : i64
    %404 = core.ptr_offset %398, %403 : ptr<i64, stack>
    core.store %400, %404
    %405 = core.const 2 : i64
    %406 = core.ptr_offset %398, %405 : ptr<i64, stack>
    core.store %12, %406
    %407 = core.const 1 : i64
    %408 = core.add %393, %407 {overflow = "proven"} : i64
    core.store %408, %sp
    core.br ^exit47
^restore52(%13: i64):
    %409 = core.const 5 : i64
    %410 = core.ptr_offset %caps, %409 : ptr<i64, stack>
    core.store %13, %410
    core.br ^fail2
^pop53:
    %411 = core.const 1 : i64
    %412 = core.sub %68, %411 {overflow = "proven"} : i64
    core.store %412, %sp
    %413 = core.const 3 : i64
    %414 = core.mul %412, %413 {overflow = "proven"} : i64
    %415 = core.ptr_offset %stack, %414 : ptr<i64, stack>
    %416 = core.const 0 : i64
    %417 = core.ptr_offset %415, %416 : ptr<i64, stack>
    %418 = core.load %417 : i64
    %419 = core.const 1 : i64
    %420 = core.ptr_offset %415, %419 : ptr<i64, stack>
    %421 = core.load %420 : i64
    core.store %421, %p
    %422 = core.const 2 : i64
    %423 = core.ptr_offset %415, %422 : ptr<i64, stack>
    %424 = core.load %423 : i64
    %425 = core.const 0 : i64
    %426 = core.cmp.eq %418, %425 : bool
    core.cond_br %426, ^restore7(%424), ^dispatch54
^dispatch54:
    %427 = core.const 1 : i64
    %428 = core.cmp.eq %418, %427 : bool
    core.cond_br %428, ^giveback15(%424), ^dispatch55
^dispatch55:
    %429 = core.const 2 : i64
    %430 = core.cmp.eq %418, %429 : bool
    core.cond_br %430, ^restore18(%424), ^dispatch56
^dispatch56:
    %431 = core.const 3 : i64
    %432 = core.cmp.eq %418, %431 : bool
    core.cond_br %432, ^giveback26(%424), ^dispatch57
^dispatch57:
    %433 = core.const 4 : i64
    %434 = core.cmp.eq %418, %433 : bool
    core.cond_br %434, ^giveback38(%424), ^dispatch58
^dispatch58:
    %435 = core.const 5 : i64
    %436 = core.cmp.eq %418, %435 : bool
    core.cond_br %436, ^restore41(%424), ^dispatch59
^dispatch59:
    %437 = core.const 6 : i64
    %438 = core.cmp.eq %418, %437 : bool
    core.cond_br %438, ^giveback49(%424), ^dispatch60
^dispatch60:
    %439 = core.const 7 : i64
    %440 = core.cmp.eq %418, %439 : bool
    core.cond_br %440, ^restore52(%424), ^dispatch61
^dispatch61:
    core.unreachable
}

private func @ppy.regex.2(%buf: buffer<u8>, %pos: i64, %endpos: i64) -> (bool, i64, i64) attrs {ppy.regex = "0x[0-9a-f]+", ppy.synthesized = "regex.search"} {
^entry:
    %1 = core.buffer_len %buf : index
    %2 = core.cast %1 : i64
    %3 = core.const 0 : i64
    %4 = core.cmp.lt %endpos, %3 : bool
    %5 = core.select %4, %3, %endpos : i64
    %6 = core.cmp.gt %5, %2 : bool
    %7 = core.select %6, %2, %5 : i64
    %8 = core.cmp.lt %pos, %3 : bool
    %9 = core.select %8, %3, %pos : i64
    %10 = core.cmp.gt %9, %2 : bool
    %11 = core.select %10, %2, %9 : i64
    %p = core.alloca : ptr<i64, stack>
    %sp = core.alloca : ptr<i64, stack>
    %start = core.alloca : ptr<i64, stack>
    %stack = core.alloca {count = 12288} : ptr<i64, stack>
    %caps = core.alloca {count = 2} : ptr<i64, stack>
    %12 = core.const 0 : i64
    %13 = core.cmp.gt %11, %7 : bool
    core.cond_br %13, ^notfound4, ^attempt1(%11)
^attempt1(%s: i64):
    core.store %s, %p
    core.store %s, %start
    core.store %12, %sp
    %14 = core.const -1 : i64
    %15 = core.const 0 : i64
    %16 = core.ptr_offset %caps, %15 : ptr<i64, stack>
    core.store %14, %16
    %17 = core.const 1 : i64
    %18 = core.ptr_offset %caps, %17 : ptr<i64, stack>
    core.store %14, %18
    %19 = core.const 0 : i64
    %20 = core.ptr_offset %caps, %19 : ptr<i64, stack>
    core.store %s, %20
    %21 = core.load %p : i64
    %22 = core.cmp.lt %21, %7 : bool
    core.cond_br %22, ^read7, ^fail2
^fail2:
    %23 = core.load %sp : i64
    %24 = core.const 0 : i64
    %25 = core.cmp.eq %23, %24 : bool
    core.cond_br %25, ^exhausted3, ^pop21
^exhausted3:
    %26 = core.load %start : i64
    %27 = core.const 1 : i64
    %28 = core.add %26, %27 {overflow = "proven"} : i64
    %29 = core.cmp.gt %28, %7 : bool
    core.cond_br %29, ^notfound4, ^attempt1(%28)
^notfound4:
    %30 = core.const false : bool
    %31 = core.const -1 : i64
    %32 = core.const -1 : i64
    core.ret %30, %31, %32
^read7:
    %33 = core.buffer_load %buf, %21 : u8
    %34 = core.cast %33 : i64
    %35 = core.const 48 : i64
    %36 = core.cmp.eq %34, %35 : bool
    core.cond_br %36, ^advance8, ^fail2
^advance8:
    %37 = core.const 1 : i64
    %38 = core.add %21, %37 {overflow = "proven"} : i64
    core.store %38, %p
    %39 = core.load %p : i64
    %40 = core.cmp.lt %39, %7 : bool
    core.cond_br %40, ^read9, ^fail2
^read9:
    %41 = core.buffer_load %buf, %39 : u8
    %42 = core.cast %41 : i64
    %43 = core.const 88 : i64
    %44 = core.cmp.eq %42, %43 : bool
    %45 = core.const 120 : i64
    %46 = core.cmp.eq %42, %45 : bool
    %47 = core.or %44, %46 : bool
    core.cond_br %47, ^advance10, ^fail2
^advance10:
    %48 = core.const 1 : i64
    %49 = core.add %39, %48 {overflow = "proven"} : i64
    core.store %49, %p
    %50 = core.load %p : i64
    %51 = core.const 1 : i64
    %52 = core.add %50, %51 {overflow = "proven"} : i64
    %53 = core.cmp.le %52, %7 : bool
    core.cond_br %53, ^fits11, ^fail2
^fits11:
    core.br ^scan12(%50)
^scan12(%q: i64):
    %54 = core.cmp.lt %q, %7 : bool
    core.cond_br %54, ^bound13, ^scanned15(%q)
^bound13:
    %55 = core.buffer_load %buf, %q : u8
    %56 = core.cast %55 : i64
    %57 = core.const 48 : i64
    %58 = core.cmp.ge %56, %57 : bool
    %59 = core.const 57 : i64
    %60 = core.cmp.le %56, %59 : bool
    %61 = core.and %58, %60 : bool
    %62 = core.const 65 : i64
    %63 = core.cmp.ge %56, %62 : bool
    %64 = core.const 70 : i64
    %65 = core.cmp.le %56, %64 : bool
    %66 = core.and %63, %65 : bool
    %67 = core.const 97 : i64
    %68 = core.cmp.ge %56, %67 : bool
    %69 = core.const 102 : i64
    %70 = core.cmp.le %56, %69 : bool
    %71 = core.and %68, %70 : bool
    %72 = core.or %61, %66 : bool
    %73 = core.or %72, %71 : bool
    %74 = core.const 1 : i64
    %75 = core.add %q, %74 {overflow = "proven"} : i64
    core.cond_br %73, ^scan12(%75), ^scanned15(%q)
^scanned15(%0: i64):
    %76 = core.const 1 : i64
    %77 = core.add %50, %76 {overflow = "proven"} : i64
    %78 = core.cmp.lt %0, %77 : bool
    core.cond_br %78, ^fail2, ^enough17
^exit16:
    %79 = core.load %p : i64
    %80 = core.const 1 : i64
    %81 = core.ptr_offset %caps, %80 : ptr<i64, stack>
    core.store %79, %81
    %82 = core.const true : bool
    %83 = core.const 0 : i64
    %84 = core.ptr_offset %caps, %83 : ptr<i64, stack>
    %85 = core.load %84 : i64
    %86 = core.const 1 : i64
    %87 = core.ptr_offset %caps, %86 : ptr<i64, stack>
    %88 = core.load %87 : i64
    core.ret %82, %85, %88
^enough17:
    core.store %0, %p
    %89 = core.cmp.gt %0, %77 : bool
    core.cond_br %89, ^keep19, ^exit16
^giveback18(%held: i64):
    %90 = core.load %p : i64
    %91 = core.const 1 : i64
    %92 = core.sub %90, %91 {overflow = "proven"} : i64
    core.store %92, %p
    %93 = core.cmp.gt %92, %held : bool
    core.cond_br %93, ^keep20, ^exit16
^keep19:
    %94 = core.load %sp : i64
    %95 = core.const 4096 : i64
    %96 = core.cmp.lt %94, %95 : bool
    core.guard %96 {kind = "range", label = "regex.stack.ok"}
    %97 = core.const 3 : i64
    %98 = core.mul %94, %97 {overflow = "proven"} : i64
    %99 = core.ptr_offset %stack, %98 : ptr<i64, stack>
    %100 = core.const 0 : i64
    %101 = core.load %p : i64
    %102 = core.const 0 : i64
    %103 = core.ptr_offset %99, %102 : ptr<i64, stack>
    core.store %100, %103
    %104 = core.const 1 : i64
    %105 = core.ptr_offset %99, %104 : ptr<i64, stack>
    core.store %101, %105
    %106 = core.const 2 : i64
    %107 = core.ptr_offset %99, %106 : ptr<i64, stack>
    core.store %77, %107
    %108 = core.const 1 : i64
    %109 = core.add %94, %108 {overflow = "proven"} : i64
    core.store %109, %sp
    core.br ^exit16
^keep20:
    %110 = core.load %sp : i64
    %111 = core.const 4096 : i64
    %112 = core.cmp.lt %110, %111 : bool
    core.guard %112 {kind = "range", label = "regex.stack.ok"}
    %113 = core.const 3 : i64
    %114 = core.mul %110, %113 {overflow = "proven"} : i64
    %115 = core.ptr_offset %stack, %114 : ptr<i64, stack>
    %116 = core.const 0 : i64
    %117 = core.load %p : i64
    %118 = core.const 0 : i64
    %119 = core.ptr_offset %115, %118 : ptr<i64, stack>
    core.store %116, %119
    %120 = core.const 1 : i64
    %121 = core.ptr_offset %115, %120 : ptr<i64, stack>
    core.store %117, %121
    %122 = core.const 2 : i64
    %123 = core.ptr_offset %115, %122 : ptr<i64, stack>
    core.store %held, %123
    %124 = core.const 1 : i64
    %125 = core.add %110, %124 {overflow = "proven"} : i64
    core.store %125, %sp
    core.br ^exit16
^pop21:
    %126 = core.const 1 : i64
    %127 = core.sub %23, %126 {overflow = "proven"} : i64
    core.store %127, %sp
    %128 = core.const 3 : i64
    %129 = core.mul %127, %128 {overflow = "proven"} : i64
    %130 = core.ptr_offset %stack, %129 : ptr<i64, stack>
    %131 = core.const 0 : i64
    %132 = core.ptr_offset %130, %131 : ptr<i64, stack>
    %133 = core.load %132 : i64
    %134 = core.const 1 : i64
    %135 = core.ptr_offset %130, %134 : ptr<i64, stack>
    %136 = core.load %135 : i64
    core.store %136, %p
    %137 = core.const 2 : i64
    %138 = core.ptr_offset %130, %137 : ptr<i64, stack>
    %139 = core.load %138 : i64
    %140 = core.const 0 : i64
    %141 = core.cmp.eq %133, %140 : bool
    core.cond_br %141, ^giveback18(%139), ^dispatch22
^dispatch22:
    core.unreachable
}

private func @ppy.regex.3(%buf: buffer<u8>, %pos: i64, %endpos: i64) -> (bool, i64, i64) attrs {ppy.regex = "[A-Za-z_]\\w*", ppy.synthesized = "regex.fullmatch"} {
^entry:
    %1 = core.buffer_len %buf : index
    %2 = core.cast %1 : i64
    %3 = core.const 0 : i64
    %4 = core.cmp.lt %endpos, %3 : bool
    %5 = core.select %4, %3, %endpos : i64
    %6 = core.cmp.gt %5, %2 : bool
    %7 = core.select %6, %2, %5 : i64
    %8 = core.cmp.lt %pos, %3 : bool
    %9 = core.select %8, %3, %pos : i64
    %10 = core.cmp.gt %9, %2 : bool
    %11 = core.select %10, %2, %9 : i64
    %p = core.alloca : ptr<i64, stack>
    %sp = core.alloca : ptr<i64, stack>
    %stack = core.alloca {count = 12288} : ptr<i64, stack>
    %caps = core.alloca {count = 2} : ptr<i64, stack>
    %12 = core.const 0 : i64
    core.store %11, %p
    core.store %12, %sp
    %13 = core.const -1 : i64
    %14 = core.const 0 : i64
    %15 = core.ptr_offset %caps, %14 : ptr<i64, stack>
    core.store %13, %15
    %16 = core.const 1 : i64
    %17 = core.ptr_offset %caps, %16 : ptr<i64, stack>
    core.store %13, %17
    %18 = core.const 0 : i64
    %19 = core.ptr_offset %caps, %18 : ptr<i64, stack>
    core.store %11, %19
    %20 = core.load %p : i64
    %21 = core.cmp.lt %20, %7 : bool
    core.cond_br %21, ^read7, ^fail2
^fail2:
    %22 = core.load %sp : i64
    %23 = core.const 0 : i64
    %24 = core.cmp.eq %22, %23 : bool
    core.cond_br %24, ^exhausted3, ^pop19
^exhausted3:
    %25 = core.const false : bool
    %26 = core.const -1 : i64
    %27 = core.const -1 : i64
    core.ret %25, %26, %27
^success5:
    %28 = core.load %p : i64
    %29 = core.const 1 : i64
    %30 = core.ptr_offset %caps, %29 : ptr<i64, stack>
    core.store %28, %30
    %31 = core.const true : bool
    %32 = core.const 0 : i64
    %33 = core.ptr_offset %caps, %32 : ptr<i64, stack>
    %34 = core.load %33 : i64
    %35 = core.const 1 : i64
    %36 = core.ptr_offset %caps, %35 : ptr<i64, stack>
    %37 = core.load %36 : i64
    core.ret %31, %34, %37
^read7:
    %38 = core.buffer_load %buf, %20 : u8
    %39 = core.cast %38 : i64
    %40 = core.const 65 : i64
    %41 = core.cmp.ge %39, %40 : bool
    %42 = core.const 90 : i64
    %43 = core.cmp.le %39, %42 : bool
    %44 = core.and %41, %43 : bool
    %45 = core.const 95 : i64
    %46 = core.cmp.eq %39, %45 : bool
    %47 = core.const 97 : i64
    %48 = core.cmp.ge %39, %47 : bool
    %49 = core.const 122 : i64
    %50 = core.cmp.le %39, %49 : bool
    %51 = core.and %48, %50 : bool
    %52 = core.or %44, %46 : bool
    %53 = core.or %52, %51 : bool
    core.cond_br %53, ^advance8, ^fail2
^advance8:
    %54 = core.const 1 : i64
    %55 = core.add %20, %54 {overflow = "proven"} : i64
    core.store %55, %p
    %56 = core.load %p : i64
    %57 = core.cmp.le %56, %7 : bool
    core.cond_br %57, ^fits9, ^fail2
^fits9:
    core.br ^scan10(%56)
^scan10(%q: i64):
    %58 = core.cmp.lt %q, %7 : bool
    core.cond_br %58, ^bound11, ^scanned13(%q)
^bound11:
    %59 = core.buffer_load %buf, %q : u8
    %60 = core.cast %59 : i64
    %61 = core.const 0 : i64
    %62 = core.const 192 : i64
    %63 = core.cmp.lt %60, %62 : bool
    %64 = core.const 0 : i64
    %65 = core.select %63, %64, %61 : i64
    %66 = core.const 128 : i64
    %67 = core.cmp.lt %60, %66 : bool
    %68 = core.const 576460745995190270 : i64
    %69 = core.select %67, %68, %65 : i64
    %70 = core.const 64 : i64
    %71 = core.cmp.lt %60, %70 : bool
    %72 = core.const 287948901175001088 : i64
    %73 = core.select %71, %72, %69 : i64
    %74 = core.const 63 : i64
    %75 = core.and %60, %74 : i64
    %76 = core.shr %73, %75 : i64
    %77 = core.const 1 : i64
    %78 = core.and %76, %77 : i64
    %79 = core.const 0 : i64
    %80 = core.cmp.ne %78, %79 : bool
    %81 = core.const 1 : i64
    %82 = core.add %q, %81 {overflow = "proven"} : i64
    core.cond_br %80, ^scan10(%82), ^scanned13(%q)
^scanned13(%0: i64):
    %83 = core.cmp.lt %0, %56 : bool
    core.cond_br %83, ^fail2, ^enough15
^exit14:
    %84 = core.load %p : i64
    %85 = core.cmp.eq %84, %7 : bool
    core.cond_br %85, ^success5, ^fail2
^enough15:
    core.store %0, %p
    %86 = core.cmp.gt %0, %56 : bool
    core.cond_br %86, ^keep17, ^exit14
^giveback16(%held: i64):
    %87 = core.load %p : i64
    %88 = core.const 1 : i64
    %89 = core.sub %87, %88 {overflow = "proven"} : i64
    core.store %89, %p
    %90 = core.cmp.gt %89, %held : bool
    core.cond_br %90, ^keep18, ^exit14
^keep17:
    %91 = core.load %sp : i64
    %92 = core.const 4096 : i64
    %93 = core.cmp.lt %91, %92 : bool
    core.guard %93 {kind = "range", label = "regex.stack.ok"}
    %94 = core.const 3 : i64
    %95 = core.mul %91, %94 {overflow = "proven"} : i64
    %96 = core.ptr_offset %stack, %95 : ptr<i64, stack>
    %97 = core.const 0 : i64
    %98 = core.load %p : i64
    %99 = core.const 0 : i64
    %100 = core.ptr_offset %96, %99 : ptr<i64, stack>
    core.store %97, %100
    %101 = core.const 1 : i64
    %102 = core.ptr_offset %96, %101 : ptr<i64, stack>
    core.store %98, %102
    %103 = core.const 2 : i64
    %104 = core.ptr_offset %96, %103 : ptr<i64, stack>
    core.store %56, %104
    %105 = core.const 1 : i64
    %106 = core.add %91, %105 {overflow = "proven"} : i64
    core.store %106, %sp
    core.br ^exit14
^keep18:
    %107 = core.load %sp : i64
    %108 = core.const 4096 : i64
    %109 = core.cmp.lt %107, %108 : bool
    core.guard %109 {kind = "range", label = "regex.stack.ok"}
    %110 = core.const 3 : i64
    %111 = core.mul %107, %110 {overflow = "proven"} : i64
    %112 = core.ptr_offset %stack, %111 : ptr<i64, stack>
    %113 = core.const 0 : i64
    %114 = core.load %p : i64
    %115 = core.const 0 : i64
    %116 = core.ptr_offset %112, %115 : ptr<i64, stack>
    core.store %113, %116
    %117 = core.const 1 : i64
    %118 = core.ptr_offset %112, %117 : ptr<i64, stack>
    core.store %114, %118
    %119 = core.const 2 : i64
    %120 = core.ptr_offset %112, %119 : ptr<i64, stack>
    core.store %held, %120
    %121 = core.const 1 : i64
    %122 = core.add %107, %121 {overflow = "proven"} : i64
    core.store %122, %sp
    core.br ^exit14
^pop19:
    %123 = core.const 1 : i64
    %124 = core.sub %22, %123 {overflow = "proven"} : i64
    core.store %124, %sp
    %125 = core.const 3 : i64
    %126 = core.mul %124, %125 {overflow = "proven"} : i64
    %127 = core.ptr_offset %stack, %126 : ptr<i64, stack>
    %128 = core.const 0 : i64
    %129 = core.ptr_offset %127, %128 : ptr<i64, stack>
    %130 = core.load %129 : i64
    %131 = core.const 1 : i64
    %132 = core.ptr_offset %127, %131 : ptr<i64, stack>
    %133 = core.load %132 : i64
    core.store %133, %p
    %134 = core.const 2 : i64
    %135 = core.ptr_offset %127, %134 : ptr<i64, stack>
    %136 = core.load %135 : i64
    %137 = core.const 0 : i64
    %138 = core.cmp.eq %130, %137 : bool
    core.cond_br %138, ^giveback16(%136), ^dispatch20
^dispatch20:
    core.unreachable
}

ppy emit c patterns.ppy

1270 lines
/* patterns: generated by ppy, C11 */
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

#if defined(__GNUC__) || defined(__clang__)
#define PPY_UNREACHABLE() __builtin_unreachable()
#elif defined(_MSC_VER)
#define PPY_UNREACHABLE() __assume(0)
#else
#define PPY_UNREACHABLE() abort()
#endif

static inline int ppy_ovf_add_i64(int64_t a, int64_t b, int64_t *out) {
#if defined(__GNUC__) || defined(__clang__)
    return __builtin_add_overflow(a, b, out);
#else
    if ((b > 0 && a > INT64_MAX - b) || (b < 0 && a < INT64_MIN - b)) {
        return 1;
    }
    *out = a + b;
    return 0;
#endif
}

static inline int ppy_ovf_sub_i64(int64_t a, int64_t b, int64_t *out) {
#if defined(__GNUC__) || defined(__clang__)
    return __builtin_sub_overflow(a, b, out);
#else
    if ((b < 0 && a > INT64_MAX + b) || (b > 0 && a < INT64_MIN + b)) {
        return 1;
    }
    *out = a - b;
    return 0;
#endif
}

static inline int ppy_ovf_mul_i64(int64_t a, int64_t b, int64_t *out) {
#if defined(__GNUC__) || defined(__clang__)
    return __builtin_mul_overflow(a, b, out);
#else
    if (a > 0) {
        if (b > 0) { if (a > INT64_MAX / b) return 1; }
        else if (b < INT64_MIN / a) return 1;
    } else if (b > 0) {
        if (a < INT64_MIN / b) return 1;
    } else if (a != 0 && b < INT64_MAX / a) return 1;
    *out = a * b;
    return 0;
#endif
}

int32_t ppy_patterns_count_words(uint8_t *text, int64_t text_len, int64_t *out);
int32_t ppy_patterns_longest_word(uint8_t *text, int64_t text_len, int64_t *out);
int32_t ppy_patterns_sum_values(uint8_t *text, int64_t text_len, int64_t *out);
int32_t ppy_patterns_count_hex(uint8_t *text, int64_t text_len, int64_t *out);
int32_t ppy_patterns_is_identifier(uint8_t *text, int64_t text_len, int8_t *out);
int32_t ppy_regex_0(uint8_t *buf, int64_t buf_len, int64_t pos, int64_t endpos, int8_t *out0, int64_t *out1, int64_t *out2);
int32_t ppy_regex_1(uint8_t *buf, int64_t buf_len, int64_t pos, int64_t endpos, int8_t *out0, int64_t *out1, int64_t *out2, int64_t *out3, int64_t *out4, int64_t *out5, int64_t *out6);
int32_t ppy_regex_2(uint8_t *buf, int64_t buf_len, int64_t pos, int64_t endpos, int8_t *out0, int64_t *out1, int64_t *out2);
int32_t ppy_regex_3(uint8_t *buf, int64_t buf_len, int64_t pos, int64_t endpos, int8_t *out0, int64_t *out1, int64_t *out2);

int32_t ppy_patterns_count_words(uint8_t *text, int64_t text_len, int64_t *out) {
    int64_t m_spans[2];

    int64_t n = 0;
    int64_t pos = 0;
    while (1) {
        int8_t res;
        int64_t t1;
        int64_t t2;
        if (ppy_regex_0(text, text_len, pos, text_len, &res, &t1, &t2) != 0) return 1; /* call.ok */
        bool m_found = res != 0;
        m_spans[0] = t1;
        m_spans[1] = t2;
        if (m_found == false) break;
        if (ppy_ovf_add_i64(n, 1, &n)) return 1; /* arith.ok */
        pos = m_spans[1];
    }
    *out = n;
    return 0;
}

int32_t ppy_patterns_longest_word(uint8_t *text, int64_t text_len, int64_t *out) {
    int64_t best;
    int64_t pos;
    bool m_found;
    int64_t start;
    int64_t end;
    int64_t m_spans[2];
    int8_t res;
    int64_t t1;
    int64_t t2;
    int64_t t3;

    best = 0;
    pos = 0;
    goto L1_while_head1;
    L1_while_head1:;
    if (pos < text_len) {
        goto L2_while_body2;
    } else {
        goto L3_while_end3;
    }
    L2_while_body2:;
    if (!(ppy_regex_0(text, text_len, pos, text_len, &res, &t1, &t2) == 0)) goto fallback; /* call.ok */
    m_found = res != 0;
    m_spans[0] = t1;
    m_spans[1] = t2;
    if (m_found ^ true) {
        goto L4_then4;
    } else {
        goto L5_else5;
    }
    L3_while_end3:;
    *out = best;
    return 0;
    L4_then4:;
    goto L3_while_end3;
    L5_else5:;
    start = m_spans[0];
    end = m_spans[1];
    if (!(!ppy_ovf_sub_i64(end, start, &t3))) goto fallback; /* arith.ok */
    best = t3 > best ? t3 : best;
    pos = end;
    goto L1_while_head1;
    fallback:
    return 1;
}

int32_t ppy_patterns_sum_values(uint8_t *text, int64_t text_len, int64_t *out) {
    int64_t m_spans[6];

    int64_t total = 0;
    int64_t pos = 0;
    while (1) {
        int8_t res;
        int64_t t1;
        int64_t t2;
        int64_t t3;
        int64_t t4;
        int64_t t5;
        int64_t t6;
        if (ppy_regex_1(text, text_len, pos, text_len, &res, &t1, &t2, &t3, &t4, &t5, &t6) != 0) return 1; /* call.ok */
        bool m_found = res != 0;
        m_spans[0] = t1;
        m_spans[1] = t2;
        m_spans[2] = t3;
        m_spans[3] = t4;
        m_spans[4] = t5;
        m_spans[5] = t6;
        if (m_found == false) break;
        int64_t value = 0;
        int64_t t7 = m_spans[4];
        int64_t t8 = m_spans[5];
        if (t7 < 0 || (int64_t)((uint64_t)t8 - 1u) >= text_len) return 1; /* bounds.ok */
        int64_t i = t7;
        while (i < t8) {
            int64_t t9;
            if (ppy_ovf_mul_i64(value, 10, &t9)) return 1; /* arith.ok */
            int64_t t10;
            if (ppy_ovf_sub_i64((int64_t)text[i], 48, &t10)) return 1; /* arith.ok */
            if (ppy_ovf_add_i64(t9, t10, &value)) return 1; /* arith.ok */
            if (ppy_ovf_add_i64(i, 1, &i)) return 1; /* arith.ok */
        }
        if (ppy_ovf_add_i64(total, value, &total)) return 1; /* arith.ok */
        pos = m_spans[1];
    }
    *out = total;
    return 0;
}

int32_t ppy_patterns_count_hex(uint8_t *text, int64_t text_len, int64_t *out) {
    int64_t m_spans[2];

    int64_t n = 0;
    int64_t pos = 0;
    while (1) {
        int8_t res;
        int64_t t1;
        int64_t t2;
        if (ppy_regex_2(text, text_len, pos, text_len, &res, &t1, &t2) != 0) return 1; /* call.ok */
        bool m_found = res != 0;
        m_spans[0] = t1;
        m_spans[1] = t2;
        if (m_found == false) break;
        if (ppy_ovf_add_i64(n, 1, &n)) return 1; /* arith.ok */
        pos = m_spans[1];
    }
    *out = n;
    return 0;
}

int32_t ppy_patterns_is_identifier(uint8_t *text, int64_t text_len, int8_t *out) {
    int8_t res;
    int64_t res_2;
    int64_t res_3;
    if (ppy_regex_3(text, text_len, 0, text_len, &res, &res_2, &res_3) != 0) return 1; /* call.ok */
    bool t1 = res != 0;
    *out = (int8_t)t1;
    return 0;
}

int32_t ppy_regex_0(uint8_t *buf, int64_t buf_len, int64_t pos, int64_t endpos, int8_t *out0, int64_t *out1, int64_t *out2) {
    int64_t p;
    int64_t sp;
    int64_t start;
    int64_t s;
    int64_t q;
    int64_t q_2;
    int64_t held;
    int64_t t1;
    int64_t t2;
    int64_t t3;
    int64_t t4;
    int64_t stack[12288];
    int64_t caps[2];
    int64_t pass;
    int64_t t5;
    int64_t t6;
    int64_t t7;
    int64_t pass_2;
    int64_t pass_3;
    int64_t pass_4;
    int64_t t8;
    int64_t pass_5;
    int64_t pass_6;
    int64_t t9;
    int64_t t10;
    int64_t *t11;
    int64_t *t12;
    int64_t t13;
    int64_t *t14;
    int64_t pass_7;

    t1 = endpos < 0 ? 0 : endpos;
    t2 = t1 > buf_len ? buf_len : t1;
    t3 = pos < 0 ? 0 : pos;
    t4 = t3 > buf_len ? buf_len : t3;
    if (t4 > t2) {
        goto L4_notfound4;
    } else {
        pass = t4;
        s = pass;
        goto L1_attempt1;
    }
    L1_attempt1:;
    p = s;
    start = s;
    sp = 0;
    caps[0] = -1;
    caps[1] = -1;
    caps[0] = s;
    t5 = p;
    if (t5 + 1 <= t2) {
        goto L5_fits7;
    } else {
        goto L2_fail2;
    }
    L2_fail2:;
    t6 = sp;
    if (t6 == 0) {
        goto L3_exhausted3;
    } else {
        goto L14_pop17;
    }
    L3_exhausted3:;
    t7 = start + 1;
    if (t7 > t2) {
        goto L4_notfound4;
    } else {
        pass_2 = t7;
        s = pass_2;
        goto L1_attempt1;
    }
    L4_notfound4:;
    *out0 = (int8_t)false;
    *out1 = -1;
    *out2 = -1;
    return 0;
    L5_fits7:;
    pass_3 = t5;
    q = pass_3;
    goto L6_scan8;
    L6_scan8:;
    if (q < t2) {
        goto L7_bound9;
    } else {
        pass_4 = q;
        q_2 = pass_4;
        goto L8_scanned11;
    }
    L7_bound9:;
    t8 = (int64_t)buf[q];
    if (((t8 >= 65) & (t8 <= 90)) | ((t8 >= 97) & (t8 <= 122))) {
        pass_5 = q + 1;
        q = pass_5;
        goto L6_scan8;
    } else {
        pass_6 = q;
        q_2 = pass_6;
        goto L8_scanned11;
    }
    L8_scanned11:;
    t9 = t5 + 1;
    if (q_2 < t9) {
        goto L2_fail2;
    } else {
        goto L10_enough13;
    }
    L9_exit12:;
    caps[1] = p;
    *out0 = (int8_t)true;
    *out1 = caps[0];
    *out2 = caps[1];
    return 0;
    L10_enough13:;
    p = q_2;
    if (q_2 > t9) {
        goto L12_keep15;
    } else {
        goto L9_exit12;
    }
    L11_giveback14:;
    t10 = p - 1;
    p = t10;
    if (t10 > held) {
        goto L13_keep16;
    } else {
        goto L9_exit12;
    }
    L12_keep15:;
    if (!(sp < 4096)) goto fallback; /* regex.stack.ok */
    t11 = stack + sp * 3;
    t11[0] = 0;
    t11[1] = p;
    t11[2] = t9;
    sp += 1;
    goto L9_exit12;
    L13_keep16:;
    if (!(sp < 4096)) goto fallback; /* regex.stack.ok */
    t12 = stack + sp * 3;
    t12[0] = 0;
    t12[1] = p;
    t12[2] = held;
    sp += 1;
    goto L9_exit12;
    L14_pop17:;
    t13 = t6 - 1;
    sp = t13;
    t14 = stack + t13 * 3;
    p = t14[1];
    if (t14[0] == 0) {
        pass_7 = t14[2];
        held = pass_7;
        goto L11_giveback14;
    } else {
        goto L15_dispatch18;
    }
    L15_dispatch18:;
    PPY_UNREACHABLE();
    fallback:
    return 1;
}

int32_t ppy_regex_1(uint8_t *buf, int64_t buf_len, int64_t pos, int64_t endpos, int8_t *out0, int64_t *out1, int64_t *out2, int64_t *out3, int64_t *out4, int64_t *out5, int64_t *out6) {
    int64_t p;
    int64_t sp;
    int64_t start;
    int64_t s;
    int64_t held;
    int64_t q;
    int64_t q_2;
    int64_t held_2;
    int64_t held_3;
    int64_t q_3;
    int64_t q_4;
    int64_t held_4;
    int64_t q_5;
    int64_t q_6;
    int64_t held_5;
    int64_t held_6;
    int64_t q_7;
    int64_t q_8;
    int64_t held_7;
    int64_t held_8;
    int64_t t1;
    int64_t t2;
    int64_t t3;
    int64_t t4;
    int64_t stack[12288];
    int64_t caps[6];
    int64_t pass;
    int64_t t5;
    int64_t *t6;
    int64_t t7;
    int64_t t8;
    int64_t t9;
    int64_t pass_2;
    int64_t pass_3;
    int64_t pass_4;
    int64_t t10;
    int64_t pass_5;
    int64_t pass_6;
    int64_t t11;
    int64_t t12;
    int64_t *t13;
    int64_t t14;
    int64_t t15;
    int64_t *t16;
    int64_t *t17;
    int64_t pass_7;
    int64_t pass_8;
    int64_t t18;
    int64_t pass_9;
    int64_t pass_10;
    int64_t t19;
    int64_t t20;
    int64_t *t21;
    int64_t *t22;
    int64_t t23;
    int64_t pass_11;
    int64_t pass_12;
    int64_t t24;
    int64_t pass_13;
    int64_t pass_14;
    int64_t t25;
    int64_t *t26;
    int64_t t27;
    int64_t t28;
    int64_t *t29;
    int64_t *t30;
    int64_t pass_15;
    int64_t pass_16;
    int64_t t31;
    int64_t pass_17;
    int64_t pass_18;
    int64_t t32;
    int64_t t33;
    int64_t *t34;
    int64_t t35;
    int64_t *t36;
    int64_t *t37;
    int64_t t38;
    int64_t *t39;
    int64_t t40;
    int64_t t41;
    int64_t pass_19;
    int64_t pass_20;
    int64_t pass_21;
    int64_t pass_22;
    int64_t pass_23;
    int64_t pass_24;
    int64_t pass_25;
    int64_t pass_26;

    t1 = endpos < 0 ? 0 : endpos;
    t2 = t1 > buf_len ? buf_len : t1;
    t3 = pos < 0 ? 0 : pos;
    t4 = t3 > buf_len ? buf_len : t3;
    if (t4 > t2) {
        goto L4_notfound4;
    } else {
        pass = t4;
        s = pass;
        goto L1_attempt1;
    }
    L1_attempt1:;
    p = s;
    start = s;
    sp = 0;
    caps[0] = -1;
    caps[1] = -1;
    caps[2] = -1;
    caps[3] = -1;
    caps[4] = -1;
    caps[5] = -1;
    caps[0] = s;
    t5 = caps[2];
    if (!(sp < 4096)) goto fallback; /* regex.stack.ok */
    t6 = stack + sp * 3;
    t6[0] = 0;
    t6[1] = p;
    t6[2] = t5;
    sp += 1;
    caps[2] = p;
    t7 = p;
    if (t7 + 1 <= t2) {
        goto L6_fits8;
    } else {
        goto L2_fail2;
    }
    L2_fail2:;
    t8 = sp;
    if (t8 == 0) {
        goto L3_exhausted3;
    } else {
        goto L47_pop53;
    }
    L3_exhausted3:;
    t9 = start + 1;
    if (t9 > t2) {
        goto L4_notfound4;
    } else {
        pass_2 = t9;
        s = pass_2;
        goto L1_attempt1;
    }
    L4_notfound4:;
    *out0 = (int8_t)false;
    *out1 = -1;
    *out2 = -1;
    *out3 = -1;
    *out4 = -1;
    *out5 = -1;
    *out6 = -1;
    return 0;
    L5_restore7:;
    caps[2] = held;
    goto L2_fail2;
    L6_fits8:;
    pass_3 = t7;
    q = pass_3;
    goto L7_scan9;
    L7_scan9:;
    if (q < t2) {
        goto L8_bound10;
    } else {
        pass_4 = q;
        q_2 = pass_4;
        goto L9_scanned12;
    }
    L8_bound10:;
    t10 = (int64_t)buf[q];
    if ((((t10 < 64 ? INT64_C(287948901175001088) : (t10 < 128 ? INT64_C(576460745995190270) : (t10 < 192 ? 0 : 0))) >> (t10 & 63)) & 1) != 0) {
        pass_5 = q + 1;
        q = pass_5;
        goto L7_scan9;
    } else {
        pass_6 = q;
        q_2 = pass_6;
        goto L9_scanned12;
    }
    L9_scanned12:;
    t11 = t7 + 1;
    if (q_2 < t11) {
        goto L2_fail2;
    } else {
        goto L11_enough14;
    }
    L10_exit13:;
    t12 = caps[3];
    if (!(sp < 4096)) goto fallback; /* regex.stack.ok */
    t13 = stack + sp * 3;
    t13[0] = 2;
    t13[1] = p;
    t13[2] = t12;
    sp += 1;
    caps[3] = p;
    t14 = p;
    if (t14 <= t2) {
        goto L16_fits19;
    } else {
        goto L2_fail2;
    }
    L11_enough14:;
    p = q_2;
    if (q_2 > t11) {
        goto L13_keep16;
    } else {
        goto L10_exit13;
    }
    L12_giveback15:;
    t15 = p - 1;
    p = t15;
    if (t15 > held_2) {
        goto L14_keep17;
    } else {
        goto L10_exit13;
    }
    L13_keep16:;
    if (!(sp < 4096)) goto fallback; /* regex.stack.ok */
    t16 = stack + sp * 3;
    t16[0] = 1;
    t16[1] = p;
    t16[2] = t11;
    sp += 1;
    goto L10_exit13;
    L14_keep17:;
    if (!(sp < 4096)) goto fallback; /* regex.stack.ok */
    t17 = stack + sp * 3;
    t17[0] = 1;
    t17[1] = p;
    t17[2] = held_2;
    sp += 1;
    goto L10_exit13;
    L15_restore18:;
    caps[3] = held_3;
    goto L2_fail2;
    L16_fits19:;
    pass_7 = t14;
    q_3 = pass_7;
    goto L17_scan20;
    L17_scan20:;
    if (q_3 < t2) {
        goto L18_bound21;
    } else {
        pass_8 = q_3;
        q_4 = pass_8;
        goto L19_scanned23;
    }
    L18_bound21:;
    t18 = (int64_t)buf[q_3];
    if (((t18 >= 9) & (t18 <= 13)) | (t18 == 32)) {
        pass_9 = q_3 + 1;
        q_3 = pass_9;
        goto L17_scan20;
    } else {
        pass_10 = q_3;
        q_4 = pass_10;
        goto L19_scanned23;
    }
    L19_scanned23:;
    if (q_4 < t14) {
        goto L2_fail2;
    } else {
        goto L21_enough25;
    }
    L20_exit24:;
    t19 = p;
    if (t19 < t2) {
        goto L25_read29;
    } else {
        goto L2_fail2;
    }
    L21_enough25:;
    p = q_4;
    if (q_4 > t14) {
        goto L23_keep27;
    } else {
        goto L20_exit24;
    }
    L22_giveback26:;
    t20 = p - 1;
    p = t20;
    if (t20 > held_4) {
        goto L24_keep28;
    } else {
        goto L20_exit24;
    }
    L23_keep27:;
    if (!(sp < 4096)) goto fallback; /* regex.stack.ok */
    t21 = stack + sp * 3;
    t21[0] = 3;
    t21[1] = p;
    t21[2] = t14;
    sp += 1;
    goto L20_exit24;
    L24_keep28:;
    if (!(sp < 4096)) goto fallback; /* regex.stack.ok */
    t22 = stack + sp * 3;
    t22[0] = 3;
    t22[1] = p;
    t22[2] = held_4;
    sp += 1;
    goto L20_exit24;
    L25_read29:;
    if ((int64_t)buf[t19] == 61) {
        goto L26_advance30;
    } else {
        goto L2_fail2;
    }
    L26_advance30:;
    p = t19 + 1;
    t23 = p;
    if (t23 <= t2) {
        goto L27_fits31;
    } else {
        goto L2_fail2;
    }
    L27_fits31:;
    pass_11 = t23;
    q_5 = pass_11;
    goto L28_scan32;
    L28_scan32:;
    if (q_5 < t2) {
        goto L29_bound33;
    } else {
        pass_12 = q_5;
        q_6 = pass_12;
        goto L30_scanned35;
    }
    L29_bound33:;
    t24 = (int64_t)buf[q_5];
    if (((t24 >= 9) & (t24 <= 13)) | (t24 == 32)) {
        pass_13 = q_5 + 1;
        q_5 = pass_13;
        goto L28_scan32;
    } else {
        pass_14 = q_5;
        q_6 = pass_14;
        goto L30_scanned35;
    }
    L30_scanned35:;
    if (q_6 < t23) {
        goto L2_fail2;
    } else {
        goto L32_enough37;
    }
    L31_exit36:;
    t25 = caps[4];
    if (!(sp < 4096)) goto fallback; /* regex.stack.ok */
    t26 = stack + sp * 3;
    t26[0] = 5;
    t26[1] = p;
    t26[2] = t25;
    sp += 1;
    caps[4] = p;
    t27 = p;
    if (t27 + 1 <= t2) {
        goto L37_fits42;
    } else {
        goto L2_fail2;
    }
    L32_enough37:;
    p = q_6;
    if (q_6 > t23) {
        goto L34_keep39;
    } else {
        goto L31_exit36;
    }
    L33_giveback38:;
    t28 = p - 1;
    p = t28;
    if (t28 > held_5) {
        goto L35_keep40;
    } else {
        goto L31_exit36;
    }
    L34_keep39:;
    if (!(sp < 4096)) goto fallback; /* regex.stack.ok */
    t29 = stack + sp * 3;
    t29[0] = 4;
    t29[1] = p;
    t29[2] = t23;
    sp += 1;
    goto L31_exit36;
    L35_keep40:;
    if (!(sp < 4096)) goto fallback; /* regex.stack.ok */
    t30 = stack + sp * 3;
    t30[0] = 4;
    t30[1] = p;
    t30[2] = held_5;
    sp += 1;
    goto L31_exit36;
    L36_restore41:;
    caps[4] = held_6;
    goto L2_fail2;
    L37_fits42:;
    pass_15 = t27;
    q_7 = pass_15;
    goto L38_scan43;
    L38_scan43:;
    if (q_7 < t2) {
        goto L39_bound44;
    } else {
        pass_16 = q_7;
        q_8 = pass_16;
        goto L40_scanned46;
    }
    L39_bound44:;
    t31 = (int64_t)buf[q_7];
    if ((t31 >= 48) & (t31 <= 57)) {
        pass_17 = q_7 + 1;
        q_7 = pass_17;
        goto L38_scan43;
    } else {
        pass_18 = q_7;
        q_8 = pass_18;
        goto L40_scanned46;
    }
    L40_scanned46:;
    t32 = t27 + 1;
    if (q_8 < t32) {
        goto L2_fail2;
    } else {
        goto L42_enough48;
    }
    L41_exit47:;
    t33 = caps[5];
    if (!(sp < 4096)) goto fallback; /* regex.stack.ok */
    t34 = stack + sp * 3;
    t34[0] = 7;
    t34[1] = p;
    t34[2] = t33;
    sp += 1;
    caps[5] = p;
    caps[1] = p;
    *out0 = (int8_t)true;
    *out1 = caps[0];
    *out2 = caps[1];
    *out3 = caps[2];
    *out4 = caps[3];
    *out5 = caps[4];
    *out6 = caps[5];
    return 0;
    L42_enough48:;
    p = q_8;
    if (q_8 > t32) {
        goto L44_keep50;
    } else {
        goto L41_exit47;
    }
    L43_giveback49:;
    t35 = p - 1;
    p = t35;
    if (t35 > held_7) {
        goto L45_keep51;
    } else {
        goto L41_exit47;
    }
    L44_keep50:;
    if (!(sp < 4096)) goto fallback; /* regex.stack.ok */
    t36 = stack + sp * 3;
    t36[0] = 6;
    t36[1] = p;
    t36[2] = t32;
    sp += 1;
    goto L41_exit47;
    L45_keep51:;
    if (!(sp < 4096)) goto fallback; /* regex.stack.ok */
    t37 = stack + sp * 3;
    t37[0] = 6;
    t37[1] = p;
    t37[2] = held_7;
    sp += 1;
    goto L41_exit47;
    L46_restore52:;
    caps[5] = held_8;
    goto L2_fail2;
    L47_pop53:;
    t38 = t8 - 1;
    sp = t38;
    t39 = stack + t38 * 3;
    t40 = t39[0];
    p = t39[1];
    t41 = t39[2];
    if (t40 == 0) {
        pass_19 = t41;
        held = pass_19;
        goto L5_restore7;
    } else {
        goto L48_dispatch54;
    }
    L48_dispatch54:;
    if (t40 == 1) {
        pass_20 = t41;
        held_2 = pass_20;
        goto L12_giveback15;
    } else {
        goto L49_dispatch55;
    }
    L49_dispatch55:;
    if (t40 == 2) {
        pass_21 = t41;
        held_3 = pass_21;
        goto L15_restore18;
    } else {
        goto L50_dispatch56;
    }
    L50_dispatch56:;
    if (t40 == 3) {
        pass_22 = t41;
        held_4 = pass_22;
        goto L22_giveback26;
    } else {
        goto L51_dispatch57;
    }
    L51_dispatch57:;
    if (t40 == 4) {
        pass_23 = t41;
        held_5 = pass_23;
        goto L33_giveback38;
    } else {
        goto L52_dispatch58;
    }
    L52_dispatch58:;
    if (t40 == 5) {
        pass_24 = t41;
        held_6 = pass_24;
        goto L36_restore41;
    } else {
        goto L53_dispatch59;
    }
    L53_dispatch59:;
    if (t40 == 6) {
        pass_25 = t41;
        held_7 = pass_25;
        goto L43_giveback49;
    } else {
        goto L54_dispatch60;
    }
    L54_dispatch60:;
    if (t40 == 7) {
        pass_26 = t41;
        held_8 = pass_26;
        goto L46_restore52;
    } else {
        goto L55_dispatch61;
    }
    L55_dispatch61:;
    PPY_UNREACHABLE();
    fallback:
    return 1;
}

int32_t ppy_regex_2(uint8_t *buf, int64_t buf_len, int64_t pos, int64_t endpos, int8_t *out0, int64_t *out1, int64_t *out2) {
    int64_t p;
    int64_t sp;
    int64_t start;
    int64_t s;
    int64_t q;
    int64_t q_2;
    int64_t held;
    int64_t t1;
    int64_t t2;
    int64_t t3;
    int64_t t4;
    int64_t stack[12288];
    int64_t caps[2];
    int64_t pass;
    int64_t t5;
    int64_t t6;
    int64_t t7;
    int64_t pass_2;
    int64_t t8;
    int64_t t9;
    int64_t t10;
    int64_t pass_3;
    int64_t pass_4;
    int64_t t11;
    int64_t pass_5;
    int64_t pass_6;
    int64_t t12;
    int64_t t13;
    int64_t *t14;
    int64_t *t15;
    int64_t t16;
    int64_t *t17;
    int64_t pass_7;

    t1 = endpos < 0 ? 0 : endpos;
    t2 = t1 > buf_len ? buf_len : t1;
    t3 = pos < 0 ? 0 : pos;
    t4 = t3 > buf_len ? buf_len : t3;
    if (t4 > t2) {
        goto L4_notfound4;
    } else {
        pass = t4;
        s = pass;
        goto L1_attempt1;
    }
    L1_attempt1:;
    p = s;
    start = s;
    sp = 0;
    caps[0] = -1;
    caps[1] = -1;
    caps[0] = s;
    t5 = p;
    if (t5 < t2) {
        goto L5_read7;
    } else {
        goto L2_fail2;
    }
    L2_fail2:;
    t6 = sp;
    if (t6 == 0) {
        goto L3_exhausted3;
    } else {
        goto L18_pop21;
    }
    L3_exhausted3:;
    t7 = start + 1;
    if (t7 > t2) {
        goto L4_notfound4;
    } else {
        pass_2 = t7;
        s = pass_2;
        goto L1_attempt1;
    }
    L4_notfound4:;
    *out0 = (int8_t)false;
    *out1 = -1;
    *out2 = -1;
    return 0;
    L5_read7:;
    if ((int64_t)buf[t5] == 48) {
        goto L6_advance8;
    } else {
        goto L2_fail2;
    }
    L6_advance8:;
    p = t5 + 1;
    t8 = p;
    if (t8 < t2) {
        goto L7_read9;
    } else {
        goto L2_fail2;
    }
    L7_read9:;
    t9 = (int64_t)buf[t8];
    if ((t9 == 88) | (t9 == 120)) {
        goto L8_advance10;
    } else {
        goto L2_fail2;
    }
    L8_advance10:;
    p = t8 + 1;
    t10 = p;
    if (t10 + 1 <= t2) {
        goto L9_fits11;
    } else {
        goto L2_fail2;
    }
    L9_fits11:;
    pass_3 = t10;
    q = pass_3;
    goto L10_scan12;
    L10_scan12:;
    if (q < t2) {
        goto L11_bound13;
    } else {
        pass_4 = q;
        q_2 = pass_4;
        goto L12_scanned15;
    }
    L11_bound13:;
    t11 = (int64_t)buf[q];
    if ((((t11 >= 48) & (t11 <= 57)) | ((t11 >= 65) & (t11 <= 70))) | ((t11 >= 97) & (t11 <= 102))) {
        pass_5 = q + 1;
        q = pass_5;
        goto L10_scan12;
    } else {
        pass_6 = q;
        q_2 = pass_6;
        goto L12_scanned15;
    }
    L12_scanned15:;
    t12 = t10 + 1;
    if (q_2 < t12) {
        goto L2_fail2;
    } else {
        goto L14_enough17;
    }
    L13_exit16:;
    caps[1] = p;
    *out0 = (int8_t)true;
    *out1 = caps[0];
    *out2 = caps[1];
    return 0;
    L14_enough17:;
    p = q_2;
    if (q_2 > t12) {
        goto L16_keep19;
    } else {
        goto L13_exit16;
    }
    L15_giveback18:;
    t13 = p - 1;
    p = t13;
    if (t13 > held) {
        goto L17_keep20;
    } else {
        goto L13_exit16;
    }
    L16_keep19:;
    if (!(sp < 4096)) goto fallback; /* regex.stack.ok */
    t14 = stack + sp * 3;
    t14[0] = 0;
    t14[1] = p;
    t14[2] = t12;
    sp += 1;
    goto L13_exit16;
    L17_keep20:;
    if (!(sp < 4096)) goto fallback; /* regex.stack.ok */
    t15 = stack + sp * 3;
    t15[0] = 0;
    t15[1] = p;
    t15[2] = held;
    sp += 1;
    goto L13_exit16;
    L18_pop21:;
    t16 = t6 - 1;
    sp = t16;
    t17 = stack + t16 * 3;
    p = t17[1];
    if (t17[0] == 0) {
        pass_7 = t17[2];
        held = pass_7;
        goto L15_giveback18;
    } else {
        goto L19_dispatch22;
    }
    L19_dispatch22:;
    PPY_UNREACHABLE();
    fallback:
    return 1;
}

int32_t ppy_regex_3(uint8_t *buf, int64_t buf_len, int64_t pos, int64_t endpos, int8_t *out0, int64_t *out1, int64_t *out2) {
    int64_t p;
    int64_t sp;
    int64_t q;
    int64_t q_2;
    int64_t held;
    int64_t t1;
    int64_t t2;
    int64_t t3;
    int64_t t4;
    int64_t stack[12288];
    int64_t caps[2];
    int64_t t5;
    int64_t t6;
    int64_t t7;
    int64_t t8;
    int64_t pass;
    int64_t pass_2;
    int64_t t9;
    int64_t pass_3;
    int64_t pass_4;
    int64_t t10;
    int64_t *t11;
    int64_t *t12;
    int64_t t13;
    int64_t *t14;
    int64_t pass_5;

    t1 = endpos < 0 ? 0 : endpos;
    t2 = t1 > buf_len ? buf_len : t1;
    t3 = pos < 0 ? 0 : pos;
    t4 = t3 > buf_len ? buf_len : t3;
    p = t4;
    sp = 0;
    caps[0] = -1;
    caps[1] = -1;
    caps[0] = t4;
    t5 = p;
    if (t5 < t2) {
        goto L4_read7;
    } else {
        goto L1_fail2;
    }
    L1_fail2:;
    t6 = sp;
    if (t6 == 0) {
        goto L2_exhausted3;
    } else {
        goto L15_pop19;
    }
    L2_exhausted3:;
    *out0 = (int8_t)false;
    *out1 = -1;
    *out2 = -1;
    return 0;
    L3_success5:;
    caps[1] = p;
    *out0 = (int8_t)true;
    *out1 = caps[0];
    *out2 = caps[1];
    return 0;
    L4_read7:;
    t7 = (int64_t)buf[t5];
    if ((((t7 >= 65) & (t7 <= 90)) | (t7 == 95)) | ((t7 >= 97) & (t7 <= 122))) {
        goto L5_advance8;
    } else {
        goto L1_fail2;
    }
    L5_advance8:;
    p = t5 + 1;
    t8 = p;
    if (t8 <= t2) {
        goto L6_fits9;
    } else {
        goto L1_fail2;
    }
    L6_fits9:;
    pass = t8;
    q = pass;
    goto L7_scan10;
    L7_scan10:;
    if (q < t2) {
        goto L8_bound11;
    } else {
        pass_2 = q;
        q_2 = pass_2;
        goto L9_scanned13;
    }
    L8_bound11:;
    t9 = (int64_t)buf[q];
    if ((((t9 < 64 ? INT64_C(287948901175001088) : (t9 < 128 ? INT64_C(576460745995190270) : (t9 < 192 ? 0 : 0))) >> (t9 & 63)) & 1) != 0) {
        pass_3 = q + 1;
        q = pass_3;
        goto L7_scan10;
    } else {
        pass_4 = q;
        q_2 = pass_4;
        goto L9_scanned13;
    }
    L9_scanned13:;
    if (q_2 < t8) {
        goto L1_fail2;
    } else {
        goto L11_enough15;
    }
    L10_exit14:;
    if (p == t2) {
        goto L3_success5;
    } else {
        goto L1_fail2;
    }
    L11_enough15:;
    p = q_2;
    if (q_2 > t8) {
        goto L13_keep17;
    } else {
        goto L10_exit14;
    }
    L12_giveback16:;
    t10 = p - 1;
    p = t10;
    if (t10 > held) {
        goto L14_keep18;
    } else {
        goto L10_exit14;
    }
    L13_keep17:;
    if (!(sp < 4096)) goto fallback; /* regex.stack.ok */
    t11 = stack + sp * 3;
    t11[0] = 0;
    t11[1] = p;
    t11[2] = t8;
    sp += 1;
    goto L10_exit14;
    L14_keep18:;
    if (!(sp < 4096)) goto fallback; /* regex.stack.ok */
    t12 = stack + sp * 3;
    t12[0] = 0;
    t12[1] = p;
    t12[2] = held;
    sp += 1;
    goto L10_exit14;
    L15_pop19:;
    t13 = t6 - 1;
    sp = t13;
    t14 = stack + t13 * 3;
    p = t14[1];
    if (t14[0] == 0) {
        pass_5 = t14[2];
        held = pass_5;
        goto L12_giveback16;
    } else {
        goto L16_dispatch20;
    }
    L16_dispatch20:;
    PPY_UNREACHABLE();
    fallback:
    return 1;
}

One pattern, one matcher

WORD = re.compile(rb"[A-Za-z]+")
PAIR = re.compile(rb"(?P<key>\w+)\s*=\s*(\d+)")


def sum_values(text: Buffer[ppy.u8]) -> int:
    total = 0
    pos = 0
    while True:
        m = PAIR.search(text, pos)
        if m is None:
            return total
        value = 0
        for i in range(m.start(2), m.end(2)):
            value = value * 10 + (text[i] - 48)
        total += value
        pos = m.end()

PAIR.search(text, pos) becomes a regex.search operation in the IR. The lower-regex pass compiles the pattern into a private function of core operations, so the LLVM and C backends run it without a regex library.

The match is a local. m is None and if m: narrow it, and m.start(2), m.end(), and start, end = m.span() are loads.

The matcher backtracks the way re does (ordered alternation, greedy and lazy repeats, a group's last iteration), so the spans agree byte for byte. A repeat of one byte class such as [A-Za-z]+ scans its run rather than pushing per byte.

The same source runs unchanged on CPython, where re accepts the array.array("B") the buffer is.

Compared with CPython's re and Rust's regex

The benchmark makes four passes over 400,000 generated lines (7.9 MB): count the words, find the longest, sum the name = value pairs, count the hex numbers. The programs are in compare/: patterns_bench.ppy, patterns_re.py, and patterns.rs with its Cargo.toml. The site shows them whole. Times are in milliseconds, best of five passes, mean and spread over five processes.

PPy: a pattern compiled from a bytes literal, search from a position, m.end(). The same file runs on CPython.

def sum_values(text: Buffer[ppy.u8]) -> int:
    total = 0
    pos = 0
    while True:
        m = PAIR.search(text, pos)
        if m is None:
            return total
        value = 0
        for i in range(m.start(2), m.end(2)):
            value = value * 10 + (text[i] - 48)
        total += value
        pos = m.end()

CPython re: the idiomatic spelling, finditer and int(m.group(2)).

def sum_values(text: bytes) -> int:
    return sum(int(m.group(2)) for m in PAIR.finditer(text))

Rust regex: captures_iter over &[u8], the number parsed from the captured bytes, built with cargo build --release.

fn sum_values(pair: &Regex, text: &[u8]) -> u64 {
    pair.captures_iter(text)
        .map(|c| std::str::from_utf8(&c[2]).unwrap().parse::<u64>().unwrap())
        .sum()
}
PPy ppy run CPython re Rust regex
count_words 6.57 ± 0.05 107.07 ± 1.27 18.23 ± 0.13
longest_word 6.53 ± 0.05 133.05 ± 8.69 36.85 ± 2.99
sum_values 56.70 ± 0.33 198.20 ± 1.86 65.62 ± 0.79
count_hex 6.59 ± 0.03 10.22 ± 0.10 2.33 ± 0.10

PPy compiles each pattern into a function of core operations: a backtracker in which a byte-class repeat scans its run instead of stepping byte by byte. A match is a few locals rather than an object, so a search loop is a native loop. That is the whole distance to re, whose matcher is a bytecode interpreter allocating a match object per hit.

Against Rust, the pattern decides:

  • [A-Za-z]+ is a scan in both engines.
  • \w+\s*=\s*(\d+) makes regex fall back to its slower capturing engine.
  • 0x[0-9a-f]+ under (?i) is where its lazy DFA wins outright. A literal-prefix prefilter is the obvious next step for the PPy matcher there.

Intel Core Ultra 9 386H; rustc 1.95.0 with regex 1.x, CPython 3.12.13 for re, PPy on CPython 3.13.13, from a checkout on a native filesystem.

What stays with Python

m.group() returns bytes, which has no native form, so a function that calls it keeps running on Python. Read the buffer between start() and end() instead.

  • Backreferences, lookahead and lookbehind, atomic groups, and possessive repeats are refused when the pattern is analysed, and ppy explain names the construct.
  • A match that would need more than the matcher's stack of 4096 entries ((a|b)*c over a long input without a c) fails a guard, and the function falls back to re for that call.

Read on: Regular expressions · The IR: the regex dialect · Substring search

patterns.ppy is hand-written; there is no .py source and no conversion step.

43_regex/patterns.ppy

"""Regular expressions over a byte buffer, compiled to native matchers."""

import array
import re
import time

import ppy
from ppy import Buffer

WORD = re.compile(rb"[A-Za-z]+")
PAIR = re.compile(rb"(?P<key>\w+)\s*=\s*(\d+)")
HEX = re.compile(rb"0x[0-9a-f]+", re.IGNORECASE)


def count_words(text: Buffer[ppy.u8]) -> int:
    n = 0
    pos = 0
    while True:
        m = WORD.search(text, pos)
        if m is None:
            return n
        n += 1
        pos = m.end()


def longest_word(text: Buffer[ppy.u8]) -> int:
    best = 0
    pos = 0
    while pos < len(text):
        m = WORD.search(text, pos)
        if not m:
            break
        start, end = m.span()
        best = max(best, end - start)
        pos = end
    return best


def sum_values(text: Buffer[ppy.u8]) -> int:
    total = 0
    pos = 0
    while True:
        m = PAIR.search(text, pos)
        if m is None:
            return total
        value = 0
        for i in range(m.start(2), m.end(2)):
            value = value * 10 + (text[i] - 48)
        total += value
        pos = m.end()


def count_hex(text: Buffer[ppy.u8]) -> int:
    n = 0
    pos = 0
    while True:
        m = HEX.search(text, pos)
        if m is None:
            return n
        n += 1
        pos = m.end()


def is_identifier(text: Buffer[ppy.u8]) -> bool:
    return re.fullmatch(rb"[A-Za-z_]\w*", text) is not None


def make_text(lines: int) -> Buffer[ppy.u8]:
    """`lines` lines of `name = value` pairs, words, and hex numbers, the same every run."""
    words = [b"alpha", b"beta", b"gamma", b"delta", b"epsilon", b"zeta", b"eta", b"theta"]
    parts = []
    state = 12345
    for i in range(lines):
        state = (state * 1103515245 + 12345) % (1 << 31)
        word = words[state % len(words)]
        parts.append(word + b" = " + str(state % 1000).encode() + b"  " + word.upper())
        if i % 7 == 0:
            parts.append(b"0x" + format(state, "x").encode())
        parts.append(b"\n")
    return memoryview(array.array("B", b"".join(parts)))


def main() -> None:
    text = make_text(50_000)
    print(len(text), "bytes")
    started = time.perf_counter()
    print(count_words(text), longest_word(text), sum_values(text), count_hex(text))
    elapsed = time.perf_counter() - started
    snake = array.array("B", b"snake_case9")
    lives = array.array("B", b"9lives")
    print(is_identifier(snake), is_identifier(lives))
    print(f"# four passes: {elapsed * 1000:.1f} ms")


main()

Counterpart programs

The programs the comparison above measured, each written the way its tool expects. The PPy one is first.

patterns_bench.ppy (PPy)
"""The four passes of `patterns.ppy` over 400,000 lines, timed: the PPY side of the comparison."""

import array
import re
import time

import ppy
from ppy import Buffer

WORD = re.compile(rb"[A-Za-z]+")
PAIR = re.compile(rb"(?P<key>\w+)\s*=\s*(\d+)")
HEX = re.compile(rb"0x[0-9a-f]+", re.IGNORECASE)


def count_words(text: Buffer[ppy.u8]) -> int:
    n = 0
    pos = 0
    while True:
        m = WORD.search(text, pos)
        if m is None:
            return n
        n += 1
        pos = m.end()


def longest_word(text: Buffer[ppy.u8]) -> int:
    best = 0
    pos = 0
    while pos < len(text):
        m = WORD.search(text, pos)
        if not m:
            break
        start, end = m.span()
        best = max(best, end - start)
        pos = end
    return best


def sum_values(text: Buffer[ppy.u8]) -> int:
    total = 0
    pos = 0
    while True:
        m = PAIR.search(text, pos)
        if m is None:
            return total
        value = 0
        for i in range(m.start(2), m.end(2)):
            value = value * 10 + (text[i] - 48)
        total += value
        pos = m.end()


def count_hex(text: Buffer[ppy.u8]) -> int:
    n = 0
    pos = 0
    while True:
        m = HEX.search(text, pos)
        if m is None:
            return n
        n += 1
        pos = m.end()


def make_text(lines: int) -> Buffer[ppy.u8]:
    """`lines` lines of `name = value` pairs, words, and hex numbers, the same every run."""
    words = [b"alpha", b"beta", b"gamma", b"delta", b"epsilon", b"zeta", b"eta", b"theta"]
    parts = []
    state = 12345
    for i in range(lines):
        state = (state * 1103515245 + 12345) % (1 << 31)
        word = words[state % len(words)]
        parts.append(word + b" = " + str(state % 1000).encode() + b"  " + word.upper())
        if i % 7 == 0:
            parts.append(b"0x" + format(state, "x").encode())
        parts.append(b"\n")
    return memoryview(array.array("B", b"".join(parts)))


def main() -> None:
    text = make_text(400_000)
    for _ in range(2):
        count_words(text)
        longest_word(text)
        sum_values(text)
        count_hex(text)
    print(len(text))
    best = [1e9, 1e9, 1e9, 1e9]
    answers = [0, 0, 0, 0]
    for _ in range(5):
        started = time.perf_counter()
        answers[0] = count_words(text)
        best[0] = min(best[0], (time.perf_counter() - started) * 1000.0)
        started = time.perf_counter()
        answers[1] = longest_word(text)
        best[1] = min(best[1], (time.perf_counter() - started) * 1000.0)
        started = time.perf_counter()
        answers[2] = sum_values(text)
        best[2] = min(best[2], (time.perf_counter() - started) * 1000.0)
        started = time.perf_counter()
        answers[3] = count_hex(text)
        best[3] = min(best[3], (time.perf_counter() - started) * 1000.0)
    labels = ["count_words", "longest_word", "sum_values", "count_hex"]
    for label, answer, took in zip(labels, answers, best, strict=True):
        print(f"# {label}: {took:.2f} ms")
        print(answer)


main()
patterns.rs (Rust)
//! The same four passes with Rust's `regex` crate over bytes.

use regex::bytes::{Regex, RegexBuilder};
use std::time::Instant;

fn make_text(lines: u64) -> Vec<u8> {
    let words: [&[u8]; 8] = [
        b"alpha", b"beta", b"gamma", b"delta", b"epsilon", b"zeta", b"eta", b"theta",
    ];
    let mut out = Vec::new();
    let mut state: u64 = 12345;
    for i in 0..lines {
        state = (state * 1103515245 + 12345) % (1 << 31);
        let word = words[(state % 8) as usize];
        out.extend_from_slice(word);
        out.extend_from_slice(b" = ");
        out.extend_from_slice((state % 1000).to_string().as_bytes());
        out.extend_from_slice(b"  ");
        out.extend_from_slice(word.to_ascii_uppercase().as_slice());
        if i % 7 == 0 {
            out.extend_from_slice(format!("0x{:x}", state).as_bytes());
        }
        out.push(b'\n');
    }
    out
}

fn count_words(word: &Regex, text: &[u8]) -> u64 {
    word.find_iter(text).count() as u64
}

fn longest_word(word: &Regex, text: &[u8]) -> u64 {
    word.find_iter(text).map(|m| m.len() as u64).max().unwrap_or(0)
}

fn sum_values(pair: &Regex, text: &[u8]) -> u64 {
    pair.captures_iter(text)
        .map(|c| std::str::from_utf8(&c[2]).unwrap().parse::<u64>().unwrap())
        .sum()
}

fn count_hex(hex: &Regex, text: &[u8]) -> u64 {
    hex.find_iter(text).count() as u64
}

fn timed(label: &str, mut run: impl FnMut() -> u64) -> u64 {
    let mut best = f64::INFINITY;
    let mut answer = 0;
    for _ in 0..5 {
        let started = Instant::now();
        answer = run();
        best = best.min(started.elapsed().as_secs_f64());
    }
    println!("# {}: {:.2} ms", label, best * 1000.0);
    answer
}

fn main() {
    let word = Regex::new(r"[A-Za-z]+").unwrap();
    let pair = Regex::new(r"(?P<key>\w+)\s*=\s*(\d+)").unwrap();
    let hex = RegexBuilder::new(r"0x[0-9a-f]+").case_insensitive(true).build().unwrap();
    let text = make_text(400_000);
    println!("{}", text.len());
    println!("{}", timed("count_words", || count_words(&word, &text)));
    println!("{}", timed("longest_word", || longest_word(&word, &text)));
    println!("{}", timed("sum_values", || sum_values(&pair, &text)));
    println!("{}", timed("count_hex", || count_hex(&hex, &text)));
}
patterns_codon.py (Python)
"""The `re` program as Codon compiles it: the same source, Codon's own `re`."""

import re
import time

WORD = re.compile(rb"[A-Za-z]+")
PAIR = re.compile(rb"(?P<key>\w+)\s*=\s*(\d+)")
HEX = re.compile(rb"0x[0-9a-f]+", re.IGNORECASE)


def count_words(text: bytes) -> int:
    return sum(1 for _ in WORD.finditer(text))


def longest_word(text: bytes) -> int:
    return max((m.end() - m.start() for m in WORD.finditer(text)), default=0)


def sum_values(text: bytes) -> int:
    return sum(int(m.group(2)) for m in PAIR.finditer(text))


def count_hex(text: bytes) -> int:
    return sum(1 for _ in HEX.finditer(text))


def make_text(lines: int) -> bytes:
    words = [b"alpha", b"beta", b"gamma", b"delta", b"epsilon", b"zeta", b"eta", b"theta"]
    parts = []
    state = 12345
    for i in range(lines):
        state = (state * 1103515245 + 12345) % (1 << 31)
        word = words[state % len(words)]
        parts.append(word + b" = " + str(state % 1000).encode() + b"  " + word.upper())
        if i % 7 == 0:
            parts.append(b"0x" + format(state, "x").encode())
        parts.append(b"\n")
    return b"".join(parts)


def timed(label, run, text):
    best = 1e9
    answer = 0
    for _ in range(5):
        started = time.perf_counter()
        answer = run(text)
        best = min(best, time.perf_counter() - started)
    print(f"# {label}: {best * 1000:.2f} ms")
    return answer


def main():
    text = make_text(400_000)
    print(len(text))
    print(timed("count_words", count_words, text))
    print(timed("longest_word", longest_word, text))
    print(timed("sum_values", sum_values, text))
    print(timed("count_hex", count_hex, text))


main()
patterns_re.py (Python)
"""The same four passes with CPython's `re`, written the way `re` is written."""

import re
import time

WORD = re.compile(rb"[A-Za-z]+")
PAIR = re.compile(rb"(?P<key>\w+)\s*=\s*(\d+)")
HEX = re.compile(rb"0x[0-9a-f]+", re.IGNORECASE)


def count_words(text: bytes) -> int:
    return sum(1 for _ in WORD.finditer(text))


def longest_word(text: bytes) -> int:
    return max((m.end() - m.start() for m in WORD.finditer(text)), default=0)


def sum_values(text: bytes) -> int:
    return sum(int(m.group(2)) for m in PAIR.finditer(text))


def count_hex(text: bytes) -> int:
    return sum(1 for _ in HEX.finditer(text))


def make_text(lines: int) -> bytes:
    words = [b"alpha", b"beta", b"gamma", b"delta", b"epsilon", b"zeta", b"eta", b"theta"]
    parts = []
    state = 12345
    for i in range(lines):
        state = (state * 1103515245 + 12345) % (1 << 31)
        word = words[state % len(words)]
        parts.append(word + b" = " + str(state % 1000).encode() + b"  " + word.upper())
        if i % 7 == 0:
            parts.append(b"0x" + format(state, "x").encode())
        parts.append(b"\n")
    return b"".join(parts)


def timed(label, run, text):
    best = 1e9
    answer = 0
    for _ in range(5):
        started = time.perf_counter()
        answer = run(text)
        best = min(best, time.perf_counter() - started)
    print(f"# {label}: {best * 1000:.2f} ms")
    return answer


def main():
    text = make_text(400_000)
    print(len(text))
    print(timed("count_words", count_words, text))
    print(timed("longest_word", longest_word, text))
    print(timed("sum_values", sum_values, text))
    print(timed("count_hex", count_hex, text))


main()

Source: examples/43_regex.