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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
package main
func parseReplacement(l *RuneReader) (output []TransducerOutput) {
loop: for {
r := l.next()
switch r {
case eof:
panic("Missing closing \"")
case '"':
break loop
case '$':
slot := l.next()
if slot == eof {
panic("Missing slot character")
}
output = append(output, TransducerReplacementLoad(slot))
default:
output = append(output, TransducerReplacementRune(r))
}
}
return output
}
func parseSubex(l *RuneReader, minPower int) SubexAST {
var lhs SubexAST
r := l.next()
switch r {
case eof:
return nil
case '(':
lhs = parseSubex(l, 0)
if !l.accept(")") {
panic("Missing matching )")
}
case ')', '*', '-', '|', '!', '?', ';':
l.rewind()
return nil
case '$':
slot := l.next()
if slot == eof {
panic("Missing slot character")
}
match := parseSubex(l, 100)
if match == nil {
panic("Missing regex for store")
}
lhs = SubexASTStore{
match: match,
slot: slot,
}
case '"':
replacement := parseReplacement(l)
lhs = SubexASTOutput{replacement}
case '.':
lhs = SubexASTCopyAny{}
default:
lhs = SubexASTCopyRune(r)
}
loop: for {
if minPower <= 0 {
next := parseSubex(l, 1)
if next != nil {
lhs = SubexASTConcat{lhs, next}
continue loop
}
}
r := l.next()
switch {
case r == '*' && minPower <= 8:
lhs = SubexASTMaximise{lhs}
case r == '-' && minPower <= 8:
lhs = SubexASTMinimise{lhs}
case r == '!' && minPower <= 8:
lhs = SubexASTTry{lhs}
case r == '?' && minPower <= 8:
lhs = SubexASTMaybe{lhs}
case r == '|' && minPower <= 4:
rhs := parseSubex(l, 5)
if rhs == nil {
panic("Missing subex after |")
}
lhs = SubexASTOr{lhs, rhs}
case r == ';' && minPower <= 2:
rhs := parseSubex(l, 3)
if rhs == nil {
panic("Missing subex after ;")
}
lhs = SubexASTJoin{
content: lhs,
delimiter: rhs,
}
default:
l.rewind()
break loop
}
}
return lhs
}
func parse(input string) SubexAST {
l := RuneReader {
input: input,
pos: 0,
width: 0,
}
return parseSubex(&l, 0)
}
|