diff options
Diffstat (limited to 'subex/subexast.go')
-rw-r--r-- | subex/subexast.go | 78 |
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 |