<- Back to shtanton's homepage
aboutsummaryrefslogtreecommitdiff
path: root/subex/subexast.go
diff options
context:
space:
mode:
authorCharlie Stanton <charlie@shtanton.xyz>2023-04-18 12:47:55 +0100
committerCharlie Stanton <charlie@shtanton.xyz>2023-04-18 12:47:55 +0100
commit8e9f0b186745afd51579d2a6136a57705efc7574 (patch)
tree7ae5fa77518e2e9f4f4f6b87470ae314506daf0b /subex/subexast.go
parentebd4f72fb2d1968ac9c13e5b5e743d265a9df6ca (diff)
downloadstred-go-8e9f0b186745afd51579d2a6136a57705efc7574.tar
Adds the repeat construct, obsoleting maximise, minimise, try, maybe and probably more
The repeat construct repeats a subex a number of times, this number is based on a provided list which is ordered by priority and can be unbounded.
Diffstat (limited to 'subex/subexast.go')
-rw-r--r--subex/subexast.go78
1 files changed, 67 insertions, 11 deletions
diff --git a/subex/subexast.go b/subex/subexast.go
index 0c5c676..650f038 100644
--- a/subex/subexast.go
+++ b/subex/subexast.go
@@ -80,22 +80,78 @@ func (ast SubexASTMinimise) String() string {
return fmt.Sprintf("(%v)-", ast.content)
}
-// Run the subex as many times as possible but at least min times and at most max times
+type ConvexRange struct {
+ start, end int
+}
+func (cr ConvexRange) minmax() (int, int) {
+ if cr.start == -1 {
+ return cr.end, -1
+ } else if cr.end == -1 {
+ return cr.start, -1
+ } else if cr.start < cr.end {
+ return cr.start, cr.end
+ } else {
+ return cr.end, cr.start
+ }
+}
+func (cr ConvexRange) decrement() ConvexRange {
+ if cr.start == -1 {
+ return ConvexRange{-1, cr.end - 1}
+ } else if cr.end == -1 {
+ return ConvexRange{cr.start - 1, -1}
+ } else {
+ return ConvexRange{cr.start - 1, cr.end - 1}
+ }
+}
+func (cr ConvexRange) compile(content SubexAST, next SubexState) SubexState {
+ min, _ := cr.minmax()
+ if min != 0 {
+ return content.compileWith(cr.decrement().compile(content, next))
+ }
+ if cr.start == -1 {
+ state := &SubexGroupState {nil, next}
+ state.first = content.compileWith(state)
+ return state
+ }
+ if cr.end == -1 {
+ state := &SubexGroupState {next, nil}
+ state.second = content.compileWith(state)
+ return state
+ }
+
+ if cr.end == 0 {
+ state := next;
+ for i := 0; i < cr.start; i += 1 {
+ state = &SubexGroupState {
+ content.compileWith(state),
+ next,
+ }
+ }
+ return state
+ } else {
+ state := next;
+ for i := 0; i < cr.end; i += 1 {
+ state = &SubexGroupState {
+ next,
+ content.compileWith(state),
+ }
+ }
+ return state
+ }
+}
+
+// Try to run the subex a number of times that is one of the numbers in the acceptable range
+// Prioritising the left
type SubexASTRepeat struct {
content SubexAST
- min, max int
+ acceptable []ConvexRange
}
func (ast SubexASTRepeat) compileWith(next SubexState) SubexState {
- for i := ast.min; i < ast.max; i += 1 {
- next = &SubexGroupState {
- ast.content.compileWith(next),
- next,
- }
+ var state SubexState = &SubexDeadState{}
+ for _, convex := range ast.acceptable {
+ state = SubexGroupState {state, convex.compile(ast.content, next)}
}
- for i := 0; i < ast.min; i += 1 {
- next = ast.content.compileWith(next)
- }
- return next
+ return state
}
// Read in a single specific Atom and output it unchanged