-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathkleene.go
54 lines (44 loc) · 1.18 KB
/
kleene.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/*
(c) 2019 Launix, Inh. Carl-Philip Hänsch
Author: Tim Kluge
Dual licensed with custom aggreements or GPLv3
*/
package packrat
type KleeneParser[T any] struct {
callback func(string, ...T) T
subParser, sepParser Parser[T]
}
func NewKleeneParser[T any](callback func(string, ...T) T, subparser Parser[T], sepparser Parser[T]) *KleeneParser[T] {
return &KleeneParser[T]{callback: callback, subParser: subparser, sepParser: sepparser}
}
func (p *KleeneParser[T]) Set(embedded Parser[T], separator Parser[T]) {
p.subParser = embedded
p.sepParser = separator
}
// Match matches the embedded parser or the empty string.
func (p *KleeneParser[T]) Match(s *Scanner[T]) (Node[T], bool) {
var nodes []T
start := s.position
i := 0
lastValidPosition := s.position
for {
if i > 0 && p.sepParser != nil {
_, ok := s.applyRule(p.sepParser)
if !ok {
break
}
}
i++
node, ok := s.applyRule(p.subParser)
if !ok {
break
}
nodes = append(nodes, node.Payload)
lastValidPosition = s.position
}
s.setPosition(lastValidPosition)
if len(nodes) == 0 {
return Node[T]{Payload: p.callback("")}, true
}
return Node[T]{p.callback(s.input[start:s.position], nodes...)}, true
}