Add @(rodata) and @(require_results) to core:text/match

This commit is contained in:
gingerBill
2025-10-07 09:45:54 +01:00
parent 5a12ccef44
commit fb93713f24
+51 -25
View File
@@ -9,11 +9,12 @@ MAX_CAPTURES :: 32
Capture :: struct { Capture :: struct {
init: int, init: int,
len: int, len: int,
} }
Match :: struct { Match :: struct {
byte_start, byte_end: int, byte_start: int,
byte_end: int,
} }
Error :: enum { Error :: enum {
@@ -33,12 +34,13 @@ CAP_UNFINISHED :: -1
INVALID :: -1 INVALID :: -1
Match_State :: struct { Match_State :: struct {
src: string, src: string,
pattern: string, pattern: string,
level: int, level: int,
capture: [MAX_CAPTURES]Capture, capture: [MAX_CAPTURES]Capture,
} }
@(require_results)
match_class :: proc(c: rune, cl: rune) -> (res: bool) { match_class :: proc(c: rune, cl: rune) -> (res: bool) {
switch unicode.to_lower(cl) { switch unicode.to_lower(cl) {
case 'a': res = is_alpha(c) case 'a': res = is_alpha(c)
@@ -65,19 +67,23 @@ is_punct :: unicode.is_punct
is_space :: unicode.is_space is_space :: unicode.is_space
is_cntrl :: unicode.is_control is_cntrl :: unicode.is_control
@(require_results)
is_alnum :: proc(c: rune) -> bool { is_alnum :: proc(c: rune) -> bool {
return unicode.is_alpha(c) || unicode.is_digit(c) return unicode.is_alpha(c) || unicode.is_digit(c)
} }
@(require_results)
is_graph :: proc(c: rune) -> bool { is_graph :: proc(c: rune) -> bool {
return (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || unicode.is_digit(c) return (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || unicode.is_digit(c)
} }
@(require_results)
is_xdigit :: proc(c: rune) -> bool { is_xdigit :: proc(c: rune) -> bool {
return (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || unicode.is_digit(c) return (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || unicode.is_digit(c)
} }
// find the first utf8 charater and its size, return an error if the character is an error // find the first utf8 charater and its size, return an error if the character is an error
@(require_results)
utf8_peek :: proc(bytes: string) -> (c: rune, size: int, err: Error) { utf8_peek :: proc(bytes: string) -> (c: rune, size: int, err: Error) {
c, size = utf8.decode_rune_in_string(bytes) c, size = utf8.decode_rune_in_string(bytes)
@@ -90,6 +96,7 @@ utf8_peek :: proc(bytes: string) -> (c: rune, size: int, err: Error) {
// find the first utf8 charater and its size and advance the index // find the first utf8 charater and its size and advance the index
// return an error if the character is an error // return an error if the character is an error
@(require_results)
utf8_advance :: proc(bytes: string, index: ^int) -> (c: rune, err: Error) { utf8_advance :: proc(bytes: string, index: ^int) -> (c: rune, err: Error) {
size: int size: int
c, size = utf8.decode_rune_in_string(bytes[index^:]) c, size = utf8.decode_rune_in_string(bytes[index^:])
@@ -103,10 +110,12 @@ utf8_advance :: proc(bytes: string, index: ^int) -> (c: rune, err: Error) {
} }
// continuation byte? // continuation byte?
@(require_results)
is_cont :: proc(b: byte) -> bool { is_cont :: proc(b: byte) -> bool {
return b & 0xc0 == 0x80 return b & 0xc0 == 0x80
} }
@(require_results)
utf8_prev :: proc(bytes: string, a, b: int) -> int { utf8_prev :: proc(bytes: string, a, b: int) -> int {
b := b b := b
@@ -117,6 +126,7 @@ utf8_prev :: proc(bytes: string, a, b: int) -> int {
return a < b ? b - 1 : a return a < b ? b - 1 : a
} }
@(require_results)
utf8_next :: proc(bytes: string, a: int) -> int { utf8_next :: proc(bytes: string, a: int) -> int {
a := a a := a
b := len(bytes) b := len(bytes)
@@ -128,6 +138,7 @@ utf8_next :: proc(bytes: string, a: int) -> int {
return a < b ? a + 1 : b return a < b ? a + 1 : b
} }
@(require_results)
check_capture :: proc(ms: ^Match_State, l: rune) -> (int, Error) { check_capture :: proc(ms: ^Match_State, l: rune) -> (int, Error) {
l := int(l - '1') l := int(l - '1')
@@ -138,6 +149,7 @@ check_capture :: proc(ms: ^Match_State, l: rune) -> (int, Error) {
return l, .OK return l, .OK
} }
@(require_results)
capture_to_close :: proc(ms: ^Match_State) -> (int, Error) { capture_to_close :: proc(ms: ^Match_State) -> (int, Error) {
level := ms.level - 1 level := ms.level - 1
@@ -152,6 +164,7 @@ capture_to_close :: proc(ms: ^Match_State) -> (int, Error) {
return 0, .Invalid_Pattern_Capture return 0, .Invalid_Pattern_Capture
} }
@(require_results)
class_end :: proc(ms: ^Match_State, p: int) -> (step: int, err: Error) { class_end :: proc(ms: ^Match_State, p: int) -> (step: int, err: Error) {
step = p step = p
ch := utf8_advance(ms.pattern, &step) or_return ch := utf8_advance(ms.pattern, &step) or_return
@@ -163,7 +176,7 @@ class_end :: proc(ms: ^Match_State, p: int) -> (step: int, err: Error) {
return return
} }
utf8_advance(ms.pattern, &step) or_return _ = utf8_advance(ms.pattern, &step) or_return
case '[': case '[':
// fine with step by 1 // fine with step by 1
@@ -198,6 +211,7 @@ class_end :: proc(ms: ^Match_State, p: int) -> (step: int, err: Error) {
return return
} }
@(require_results)
match_bracket_class :: proc(ms: ^Match_State, c: rune, p, ec: int) -> (sig: bool, err: Error) { match_bracket_class :: proc(ms: ^Match_State, c: rune, p, ec: int) -> (sig: bool, err: Error) {
sig = true sig = true
p := p p := p
@@ -240,6 +254,7 @@ match_bracket_class :: proc(ms: ^Match_State, c: rune, p, ec: int) -> (sig: bool
return return
} }
@(require_results)
single_match :: proc(ms: ^Match_State, s, p, ep: int) -> (matched: bool, schar_size: int, err: Error) { single_match :: proc(ms: ^Match_State, s, p, ep: int) -> (matched: bool, schar_size: int, err: Error) {
if s >= len(ms.src) { if s >= len(ms.src) {
return return
@@ -261,6 +276,7 @@ single_match :: proc(ms: ^Match_State, s, p, ep: int) -> (matched: bool, schar_s
return return
} }
@(require_results)
match_balance :: proc(ms: ^Match_State, s, p: int) -> (unused: int, err: Error) { match_balance :: proc(ms: ^Match_State, s, p: int) -> (unused: int, err: Error) {
if p >= len(ms.pattern) - 1 { if p >= len(ms.pattern) - 1 {
return INVALID, .Invalid_Pattern_Capture return INVALID, .Invalid_Pattern_Capture
@@ -300,6 +316,7 @@ match_balance :: proc(ms: ^Match_State, s, p: int) -> (unused: int, err: Error)
return INVALID, .OK return INVALID, .OK
} }
@(require_results)
max_expand :: proc(ms: ^Match_State, s, p, ep: int) -> (res: int, err: Error) { max_expand :: proc(ms: ^Match_State, s, p, ep: int) -> (res: int, err: Error) {
m := s m := s
@@ -331,6 +348,7 @@ max_expand :: proc(ms: ^Match_State, s, p, ep: int) -> (res: int, err: Error) {
return INVALID, .OK return INVALID, .OK
} }
@(require_results)
min_expand :: proc(ms: ^Match_State, s, p, ep: int) -> (res: int, err: Error) { min_expand :: proc(ms: ^Match_State, s, p, ep: int) -> (res: int, err: Error) {
s := s s := s
@@ -352,6 +370,7 @@ min_expand :: proc(ms: ^Match_State, s, p, ep: int) -> (res: int, err: Error) {
} }
} }
@(require_results)
start_capture :: proc(ms: ^Match_State, s, p, what: int) -> (res: int, err: Error) { start_capture :: proc(ms: ^Match_State, s, p, what: int) -> (res: int, err: Error) {
level := ms.level level := ms.level
@@ -366,6 +385,7 @@ start_capture :: proc(ms: ^Match_State, s, p, what: int) -> (res: int, err: Erro
return return
} }
@(require_results)
end_capture :: proc(ms: ^Match_State, s, p: int) -> (res: int, err: Error) { end_capture :: proc(ms: ^Match_State, s, p: int) -> (res: int, err: Error) {
l := capture_to_close(ms) or_return l := capture_to_close(ms) or_return
@@ -379,6 +399,7 @@ end_capture :: proc(ms: ^Match_State, s, p: int) -> (res: int, err: Error) {
return return
} }
@(require_results)
match_capture :: proc(ms: ^Match_State, s: int, char: rune) -> (res: int, err: Error) { match_capture :: proc(ms: ^Match_State, s: int, char: rune) -> (res: int, err: Error) {
index := check_capture(ms, char) or_return index := check_capture(ms, char) or_return
length := ms.capture[index].len length := ms.capture[index].len
@@ -390,6 +411,7 @@ match_capture :: proc(ms: ^Match_State, s: int, char: rune) -> (res: int, err: E
return INVALID, .OK return INVALID, .OK
} }
@(require_results)
match :: proc(ms: ^Match_State, s, p: int) -> (unused: int, err: Error) { match :: proc(ms: ^Match_State, s, p: int) -> (unused: int, err: Error) {
s := s s := s
p := p p := p
@@ -486,6 +508,7 @@ match :: proc(ms: ^Match_State, s, p: int) -> (unused: int, err: Error) {
return s, .OK return s, .OK
} }
@(require_results)
match_default :: proc(ms: ^Match_State, s, p: int) -> (unused: int, err: Error) { match_default :: proc(ms: ^Match_State, s, p: int) -> (unused: int, err: Error) {
s := s s := s
ep := class_end(ms, p) or_return ep := class_end(ms, p) or_return
@@ -521,6 +544,7 @@ match_default :: proc(ms: ^Match_State, s, p: int) -> (unused: int, err: Error)
return s, .OK return s, .OK
} }
@(require_results)
push_onecapture :: proc(ms: ^Match_State, i: int, s: int, e: int, matches: []Match) -> (err: Error) { push_onecapture :: proc(ms: ^Match_State, i: int, s: int, e: int, matches: []Match) -> (err: Error) {
if i >= ms.level { if i >= ms.level {
if i == 0 { if i == 0 {
@@ -542,6 +566,7 @@ push_onecapture :: proc(ms: ^Match_State, i: int, s: int, e: int, matches: []M
return return
} }
@(require_results)
push_captures :: proc( push_captures :: proc(
ms: ^Match_State, ms: ^Match_State,
s: int, s: int,
@@ -559,6 +584,7 @@ push_captures :: proc(
// SPECIALS := "^$*+?.([%-" // SPECIALS := "^$*+?.([%-"
// all special characters inside a small ascii array // all special characters inside a small ascii array
@(rodata)
SPECIALS_TABLE := [256]bool { SPECIALS_TABLE := [256]bool {
'^' = true, '^' = true,
'$' = true, '$' = true,
@@ -573,6 +599,7 @@ SPECIALS_TABLE := [256]bool {
} }
// helper call to quick search for special characters // helper call to quick search for special characters
@(require_results)
index_special :: proc(text: string) -> int { index_special :: proc(text: string) -> int {
for i in 0..<len(text) { for i in 0..<len(text) {
if SPECIALS_TABLE[text[i]] { if SPECIALS_TABLE[text[i]] {
@@ -583,6 +610,7 @@ index_special :: proc(text: string) -> int {
return -1 return -1
} }
@(require_results)
lmem_find :: proc(s1, s2: string) -> int { lmem_find :: proc(s1, s2: string) -> int {
l1 := len(s1) l1 := len(s1)
l2 := len(s2) l2 := len(s2)
@@ -618,6 +646,7 @@ lmem_find :: proc(s1, s2: string) -> int {
// find a pattern with in a haystack with an offset // find a pattern with in a haystack with an offset
// allow_memfind will speed up simple searches // allow_memfind will speed up simple searches
@(require_results)
find_aux :: proc( find_aux :: proc(
haystack: string, haystack: string,
pattern: string, pattern: string,
@@ -684,6 +713,7 @@ find_aux :: proc(
// rest has to be used from captures // rest has to be used from captures
// assumes captures is zeroed on first iteration // assumes captures is zeroed on first iteration
// resets captures to zero on last iteration // resets captures to zero on last iteration
@(require_results)
gmatch :: proc( gmatch :: proc(
haystack: ^string, haystack: ^string,
pattern: string, pattern: string,
@@ -707,6 +737,7 @@ gmatch :: proc(
} }
// gsub with builder, replace patterns found with the replace content // gsub with builder, replace patterns found with the replace content
@(require_results)
gsub_builder :: proc( gsub_builder :: proc(
builder: ^strings.Builder, builder: ^strings.Builder,
haystack: string, haystack: string,
@@ -746,6 +777,7 @@ gsub_builder :: proc(
} }
// uses temp builder to build initial string - then allocates the result // uses temp builder to build initial string - then allocates the result
@(require_results)
gsub_allocator :: proc( gsub_allocator :: proc(
haystack: string, haystack: string,
pattern: string, pattern: string,
@@ -768,12 +800,7 @@ Gsub_Proc :: proc(
) )
// call a procedure on every match in the haystack // call a procedure on every match in the haystack
gsub_with :: proc( gsub_with :: proc(haystack, pattern: string, data: rawptr, call: Gsub_Proc) {
haystack: string,
pattern: string,
data: rawptr,
call: Gsub_Proc,
) {
// find matches // find matches
captures: [MAX_CAPTURES]Match captures: [MAX_CAPTURES]Match
haystack := haystack haystack := haystack
@@ -800,11 +827,8 @@ gsub :: proc { gsub_builder, gsub_allocator }
// iterative find with zeroth capture only // iterative find with zeroth capture only
// assumes captures is zeroed on first iteration // assumes captures is zeroed on first iteration
// resets captures to zero on last iteration // resets captures to zero on last iteration
gfind :: proc( @(require_results)
haystack: ^string, gfind :: proc(haystack: ^string, pattern: string, captures: ^[MAX_CAPTURES]Match) -> (res: string, ok: bool) {
pattern: string,
captures: ^[MAX_CAPTURES]Match,
) -> (res: string, ok: bool) {
haystack^ = haystack[captures[0].byte_end:] haystack^ = haystack[captures[0].byte_end:]
if len(haystack) > 0 { if len(haystack) > 0 {
length, err := find_aux(haystack^, pattern, 0, true, captures) length, err := find_aux(haystack^, pattern, 0, true, captures)
@@ -822,10 +846,8 @@ gfind :: proc(
} }
// rebuilds a pattern into a case insensitive pattern // rebuilds a pattern into a case insensitive pattern
pattern_case_insensitive_builder :: proc( @(require_results)
builder: ^strings.Builder, pattern_case_insensitive_builder :: proc(builder: ^strings.Builder, pattern: string) -> string {
pattern: string,
) -> (res: string) {
p := pattern p := pattern
last_percent: bool last_percent: bool
@@ -849,11 +871,8 @@ pattern_case_insensitive_builder :: proc(
return strings.to_string(builder^) return strings.to_string(builder^)
} }
pattern_case_insensitive_allocator :: proc( @(require_results)
pattern: string, pattern_case_insensitive_allocator :: proc(pattern: string, cap: int = 256, allocator := context.allocator) -> string {
cap: int = 256,
allocator := context.allocator,
) -> (res: string) {
builder := strings.builder_make(0, cap, context.temp_allocator) builder := strings.builder_make(0, cap, context.temp_allocator)
return pattern_case_insensitive_builder(&builder, pattern) return pattern_case_insensitive_builder(&builder, pattern)
} }
@@ -877,6 +896,7 @@ Matcher :: struct {
} }
// init using haystack & pattern and an optional byte offset // init using haystack & pattern and an optional byte offset
@(require_results)
matcher_init :: proc(haystack, pattern: string, offset: int = 0) -> (res: Matcher) { matcher_init :: proc(haystack, pattern: string, offset: int = 0) -> (res: Matcher) {
res.haystack = haystack res.haystack = haystack
res.pattern = pattern res.pattern = pattern
@@ -886,6 +906,7 @@ matcher_init :: proc(haystack, pattern: string, offset: int = 0) -> (res: Matche
} }
// find the first match and return the byte start / end position in the string, true on success // find the first match and return the byte start / end position in the string, true on success
@(require_results)
matcher_find :: proc(matcher: ^Matcher) -> (start, end: int, ok: bool) #no_bounds_check { matcher_find :: proc(matcher: ^Matcher) -> (start, end: int, ok: bool) #no_bounds_check {
matcher.captures_length, matcher.err = find_aux( matcher.captures_length, matcher.err = find_aux(
matcher.haystack, matcher.haystack,
@@ -902,6 +923,7 @@ matcher_find :: proc(matcher: ^Matcher) -> (start, end: int, ok: bool) #no_bound
} }
// find the first match and return the matched word, true on success // find the first match and return the matched word, true on success
@(require_results)
matcher_match :: proc(matcher: ^Matcher) -> (word: string, ok: bool) #no_bounds_check { matcher_match :: proc(matcher: ^Matcher) -> (word: string, ok: bool) #no_bounds_check {
matcher.captures_length, matcher.err = find_aux( matcher.captures_length, matcher.err = find_aux(
matcher.haystack, matcher.haystack,
@@ -917,6 +939,7 @@ matcher_match :: proc(matcher: ^Matcher) -> (word: string, ok: bool) #no_bounds_
} }
// get the capture at the "correct" spot, as spot 0 is reserved for the first match // get the capture at the "correct" spot, as spot 0 is reserved for the first match
@(require_results)
matcher_capture :: proc(matcher: ^Matcher, index: int, loc := #caller_location) -> string #no_bounds_check { matcher_capture :: proc(matcher: ^Matcher, index: int, loc := #caller_location) -> string #no_bounds_check {
runtime.bounds_check_error_loc(loc, index + 1, MAX_CAPTURES - 1) runtime.bounds_check_error_loc(loc, index + 1, MAX_CAPTURES - 1)
cap := matcher.captures[index + 1] cap := matcher.captures[index + 1]
@@ -924,6 +947,7 @@ matcher_capture :: proc(matcher: ^Matcher, index: int, loc := #caller_location)
} }
// get the raw match out of the captures, skipping spot 0 // get the raw match out of the captures, skipping spot 0
@(require_results)
matcher_capture_raw :: proc(matcher: ^Matcher, index: int, loc := #caller_location) -> Match #no_bounds_check { matcher_capture_raw :: proc(matcher: ^Matcher, index: int, loc := #caller_location) -> Match #no_bounds_check {
runtime.bounds_check_error_loc(loc, index + 1, MAX_CAPTURES - 1) runtime.bounds_check_error_loc(loc, index + 1, MAX_CAPTURES - 1)
return matcher.captures[index + 1] return matcher.captures[index + 1]
@@ -933,6 +957,7 @@ matcher_capture_raw :: proc(matcher: ^Matcher, index: int, loc := #caller_locati
matcher_gmatch :: matcher_match_iter matcher_gmatch :: matcher_match_iter
// iteratively match the haystack till it cant find any matches // iteratively match the haystack till it cant find any matches
@(require_results)
matcher_match_iter :: proc(matcher: ^Matcher) -> (res: string, index: int, ok: bool) { matcher_match_iter :: proc(matcher: ^Matcher) -> (res: string, index: int, ok: bool) {
if len(matcher.iter) > 0 { if len(matcher.iter) > 0 {
matcher.captures_length, matcher.err = find_aux( matcher.captures_length, matcher.err = find_aux(
@@ -962,6 +987,7 @@ matcher_match_iter :: proc(matcher: ^Matcher) -> (res: string, index: int, ok: b
} }
// get a slice of all valid captures above the first match // get a slice of all valid captures above the first match
@(require_results)
matcher_captures_slice :: proc(matcher: ^Matcher) -> []Match { matcher_captures_slice :: proc(matcher: ^Matcher) -> []Match {
return matcher.captures[1:matcher.captures_length] return matcher.captures[1:matcher.captures_length]
} }