Repository navigation
Expand file tree
/
Copy pathparam.go
More file actions
102 lines (90 loc) · 2.51 KB
/
Copy pathparam.go
File metadata and controls
102 lines (90 loc) · 2.51 KB
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
package csscolorparser
import "strings"
// Cursor-based scanner over an input string.
//
// All delimiters it cares about are ASCII, so it works on bytes and slicing
// is always safe for UTF-8 input (a delimiter byte can never be part of a
// multi-byte sequence).
type paramParser struct {
s string
pos int
}
func newParamParser(s string) *paramParser {
return ¶mParser{s: s}
}
// value consumes and returns the substring from the current position up to
// (not including) the next space, comma, or slash. Those characters are
// ignored while inside parentheses, which may be nested.
//
// Returns ("", false) if there is no value at the current position; the
// position is left unchanged in that case.
func (p *paramParser) value() (string, bool) {
start := p.pos
i := start
depth := 0
for i < len(p.s) {
c := p.s[i]
if c == '(' {
depth++
} else if c == ')' {
if depth > 0 {
depth--
}
} else if depth == 0 && (isSpace(c) || c == ',' || c == '/') {
break
}
i++
}
if i == start {
return "", false
}
p.pos = i
return p.s[start:i], true
}
// space consumes one or more ASCII whitespace characters.
// Returns true if at least one was found, false otherwise.
func (p *paramParser) space() bool {
start := p.pos
for p.pos < len(p.s) && isSpace(p.s[p.pos]) {
p.pos++
}
return p.pos > start
}
// separator consumes a single character from chars, with optional
// whitespace around it. If no such character is found, nothing is consumed.
func (p *paramParser) separator(chars string) bool {
start := p.pos
p.space()
if p.pos < len(p.s) && strings.IndexByte(chars, p.s[p.pos]) >= 0 {
p.pos++
p.space()
return true
}
p.pos = start
return false
}
// commaOrSpace consumes one or more spaces, or a single comma. Spaces are
// allowed around the comma. Returns true if either was found.
func (p *paramParser) commaOrSpace() bool {
hadSpace := p.space()
if p.pos < len(p.s) && p.s[p.pos] == ',' {
p.pos++
p.space()
return true
}
return hadSpace
}
// commaOrSlash consumes a single comma or a single slash. Spaces are allowed
// around it. Returns true if one was found; otherwise nothing is consumed.
func (p *paramParser) commaOrSlash() bool {
return p.separator(",/")
}
// slash consumes a single slash. Spaces are allowed around it. Returns true
// if a slash was found; otherwise nothing is consumed.
func (p *paramParser) slash() bool {
return p.separator("/")
}
// isEnd reports whether the whole string has been read.
func (p *paramParser) isEnd() bool {
return p.pos >= len(p.s)
}