-
Notifications
You must be signed in to change notification settings - Fork 0
/
parse.go
115 lines (104 loc) · 2.03 KB
/
parse.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
package bandit
import (
"bytes"
"io"
"strconv"
"strings"
"text/scanner"
"unicode"
)
const (
stageLowerBound = iota
stageLower
stageUpper
stageUpperBound
)
func ParseInterval(b []byte) (Interval, error) {
return parse(bytes.NewReader(b))
}
func ParseIntervalString(s string) (Interval, error) {
return parse(strings.NewReader(s))
}
func MustParseInterval(b []byte) Interval {
ival, err := ParseInterval(b)
if err != nil {
panic(err)
}
return ival
}
func MustParseIntervalString(s string) Interval {
ival, err := ParseIntervalString(s)
if err != nil {
panic(err)
}
return ival
}
func isIdent(ch rune, i int) bool {
return ch == '-' && i == 0 || unicode.IsLetter(ch) || unicode.IsDigit(ch) && i > 0
}
func parse(src io.Reader) (ival Interval, err error) {
var s scanner.Scanner
s.Init(src)
s.IsIdentRune = isIdent
stage := stageLowerBound
var lowerBound, upperBound BoundType
var lower, upper uint64
out:
for tok := s.Scan(); tok != scanner.EOF; tok = s.Scan() {
switch stage {
case stageLowerBound:
switch tok {
case '(':
lowerBound = OpenBound
case '[':
lowerBound = ClosedBound
default:
err = ErrInvalidInterval
return
}
stage = stageLower
case stageLower:
t := s.TokenText()
switch t {
case "-∞", "-inf", "-Inf":
lowerBound = UnboundBound
default:
l, perr := strconv.ParseUint(t, 10, 64)
if perr != nil {
err = ErrInvalidInterval
return
}
lower = l
}
stage = stageUpper
case stageUpper:
t := s.TokenText()
switch t {
case ",":
continue
case "∞", "inf", "Inf":
upperBound = UnboundBound
break out
default:
u, perr := strconv.ParseUint(t, 10, 64)
if perr != nil {
err = ErrInvalidInterval
return
}
upper = u
stage = stageUpperBound
}
case stageUpperBound:
switch tok {
case ')':
upperBound = OpenBound
case ']':
upperBound = ClosedBound
default:
err = ErrInvalidInterval
return
}
}
}
return NewInterval(lowerBound, lower, upper, upperBound), nil
}