-
Notifications
You must be signed in to change notification settings - Fork 0
/
scanner.go
121 lines (102 loc) · 2.69 KB
/
scanner.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
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package json2
import (
"unicode"
)
// Scanner is a func that returns a subset of the input and a success bool.
type Scanner func([]rune) ([]rune, bool)
// If returns a scanner that accepts the a rune if it satisfies the condition.
func If(condition func(rune) bool) Scanner {
return func(input []rune) ([]rune, bool) {
if len(input) > 0 && condition(input[0]) {
return input[0:1], true
}
return nil, false
}
}
// Rune returns a scanner that accepts r.
func Rune(r rune) Scanner {
return If(func(b rune) bool {
return r == b
})
}
// Space returns a scanner that accepts whitespace as defined in the unicode
// package.
func Space() Scanner {
return func(input []rune) ([]rune, bool) {
if len(input) > 0 && unicode.IsSpace(input[0]) {
return input[0:1], true
}
return nil, false
}
}
// And returns a scanner that accepts all scanners in sequence.
func And(scanners ...Scanner) Scanner {
return func(input []rune) ([]rune, bool) {
remaining := input
accumulated := []rune{}
for _, s := range scanners {
if read, ok := s(remaining); !ok {
return nil, false
} else {
accumulated = append(accumulated, read...)
remaining = remaining[len(read):]
}
}
return accumulated, true
}
}
// Or returns a scanner that accepts the first successful scan in scanners.
func Or(scanners ...Scanner) Scanner {
return func(input []rune) ([]rune, bool) {
for _, s := range scanners {
if read, ok := s(input); ok {
return read, true
}
}
return nil, false
}
}
// Maybe runs scanner and returns true regardless of the output.
func Maybe(scanner Scanner) Scanner {
return func(input []rune) ([]rune, bool) {
read, _ := scanner(input)
return read, true
}
}
// Any returns a scanner that accepts any number of occurrences of scanner,
// including zero.
func Any(scanner Scanner) Scanner {
return func(input []rune) ([]rune, bool) {
remaining := input
accumulated := []rune{}
for {
if read, ok := scanner(remaining); !ok {
return accumulated, true
} else {
accumulated = append(accumulated, read...)
remaining = remaining[len(read):]
}
}
}
}
// N returns a scanner that accepts scanner exactly n times.
func N(n int, scanner Scanner) Scanner {
return func(input []rune) ([]rune, bool) {
scanners := make([]Scanner, n)
for i := 0; i < n; i++ {
scanners[i] = scanner
}
return And(scanners...)(input)
}
}
// AtLeast returns a scanner that accepts scanner at least n times.
func AtLeast(n int, scanner Scanner) Scanner {
return func(input []rune) ([]rune, bool) {
scanners := make([]Scanner, n, n+1)
for i := range scanners {
scanners[i] = scanner
}
scanners = append(scanners, Any(scanner))
return And(scanners...)(input)
}
}