aboutsummaryrefslogtreecommitdiff
path: root/internal/plan/index.go
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-09-12 12:58:14 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-09-12 12:58:14 +0200
commit24a84671ace373ae331fa83a1ff484990f4dff0e (patch)
treea6b6e3949d7dd241f1d13e079dfb982d758c89a2 /internal/plan/index.go
parent3b36a48b7ce5a53a9366f3b31f94311f178e2553 (diff)
downloadkrino-24a84671ace373ae331fa83a1ff484990f4dff0e.tar.gz
krino-24a84671ace373ae331fa83a1ff484990f4dff0e.zip
krino: planning — chains, placeholders, conflicts, JSON
Diffstat (limited to 'internal/plan/index.go')
-rw-r--r--internal/plan/index.go44
1 files changed, 44 insertions, 0 deletions
diff --git a/internal/plan/index.go b/internal/plan/index.go
new file mode 100644
index 0000000..abe073f
--- /dev/null
+++ b/internal/plan/index.go
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package plan
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+// MaxIndex returns the highest {N} used in s, 0 when none. It reports the
+// same errors Expand does for a malformed placeholder: an unclosed
+// placeholder, or {0} (capture groups are numbered from 1). It shares
+// Expand's scanner shape: "{{" and "}}" each emit one literal brace, and any
+// other "{" opens a placeholder that runs to the next "}".
+func MaxIndex(s string) (int, error) {
+ max := 0
+ for i := 0; i < len(s); {
+ switch {
+ case s[i] == '{' && i+1 < len(s) && s[i+1] == '{':
+ i += 2
+ case s[i] == '}' && i+1 < len(s) && s[i+1] == '}':
+ i += 2
+ case s[i] == '{':
+ end := strings.IndexByte(s[i+1:], '}')
+ if end < 0 {
+ return 0, fmt.Errorf("unclosed placeholder")
+ }
+ body := s[i+1 : i+1+end]
+ if n, err := strconv.Atoi(body); err == nil {
+ if n == 0 {
+ return 0, fmt.Errorf("capture groups are numbered from 1")
+ }
+ if n >= 1 && n <= 9 && n > max {
+ max = n
+ }
+ }
+ i += end + 2
+ default:
+ i++
+ }
+ }
+ return max, nil
+}