-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparser.go
125 lines (109 loc) · 2.95 KB
/
parser.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
122
123
124
125
package tagparser
import (
"errors"
"unicode"
)
const valueQuote = '"'
const keyValueDelimiter = ':'
// Parse parses a custom tag string of struct.
//
// Strict mode is a mode selector:
// It raises an error when an unacceptable custom tag string is given if the mode is true.
// On the other hand, if the mode is false, it immediately returns the processed results until just before the invalid custom tag syntax. It never raises any error.
func Parse(tagString string, isStrict bool) (map[string]string, error) {
key := make([]rune, 0, 100)
keyCursor := 0
value := make([]rune, 0, 100)
valueCursor := 0
inKeyParsing := true
isEscaping := false
tagKeyValue := make(map[string]string)
tagSetMarker := make(map[string]bool)
tagRunes := []rune(tagString)
tagRunesLen := len(tagRunes)
for i := 0; i < tagRunesLen; i++ {
r := tagRunes[i]
if inKeyParsing {
if unicode.IsSpace(r) {
if keyCursor > 0 {
if isStrict {
return nil, errors.New("invalid custom tag syntax: key must not contain any white space, but it contains")
}
// give up when key contain any white space
break
}
continue
}
if r == valueQuote {
if isStrict {
return nil, errors.New("invalid custom tag syntax: key must not contain any double quote, but it contains")
}
// give up when key contains any double quote
break
}
if r == keyValueDelimiter {
if keyCursor <= 0 {
if isStrict {
return nil, errors.New("invalid custom tag syntax: key must not be empty, but it gets empty")
}
// give up when key is empty
break
}
inKeyParsing = false
i++
if i >= tagRunesLen {
if isStrict {
return nil, errors.New("invalid custom tag syntax: value must not be empty, but it gets empty")
}
// give up when value is empty
break
}
if tagRunes[i] != valueQuote {
if isStrict {
return nil, errors.New("invalid custom tag syntax: quote for value is missing")
}
// give up when value isn't wrapped by double quote
break
}
continue
}
key = append(key, r)
keyCursor++
continue
}
// value parsing
if !isEscaping && r == valueQuote {
keyStr := string(key[:keyCursor])
if !tagSetMarker[keyStr] {
tagSetMarker[keyStr] = true
tagKeyValue[keyStr] = string(value[:valueCursor])
}
key = key[:0]
keyCursor = 0
value = value[:0]
valueCursor = 0
inKeyParsing = true
continue
}
if r == '\\' {
if isEscaping {
value = append(value, r)
valueCursor++
isEscaping = false
continue
}
isEscaping = true
continue
}
value = append(value, r)
isEscaping = false
valueCursor++
}
if inKeyParsing && keyCursor > 0 && isStrict {
return nil, errors.New("invalid custom tag syntax: a delimiter of key and value is missing")
}
if !inKeyParsing && valueCursor > 0 && isStrict {
return nil, errors.New("invalid custom tag syntax: a value is not terminated with quote")
}
return tagKeyValue, nil
}