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
|
package cpe
//go:generate stringer -linecomment -type=tokenType
import (
"errors"
"fmt"
)
// token type
type tokenType byte
const (
anyToken tokenType = iota // any
naToken // na
valToken // val
)
// token
type token struct {
Type tokenType // token type
Val string // token value
}
// parse buffer into token.
func newToken(val []byte) token {
if len(val) > 0 {
switch val[0] {
case '*':
return token { Type: anyToken }
case '-':
return token { Type: naToken }
default:
return token { Type: valToken, Val: string(val) }
}
} else {
// empty value
return token { Type: valToken }
}
}
// unterminated escape error
var unterminatedEsc = errors.New("unterminated escape at end of buffer")
// Parse buffer into list of tokens.
func tokenize(buf []byte) ([]token, error) {
// build result
var r []token
// current token and escape state
var curr []byte
esc := false
// build result
for _, b := range(buf) {
if esc {
switch b {
// valid escaped characters
case '\\', '*', '-', '!', '"', '#', '$', '%', '&', '\'', '(', ')',
'+', ',', '/', ':', ';', '<', '=', '>', '@', '[', ']', '^', '`',
'{', '|', '}', '~':
curr = append(curr, b)
esc = false
default:
return r, fmt.Errorf("invalid escape byte: 0x%02x", b)
}
} else {
switch b {
case '\\':
esc = true
case ':':
// push token, clear buffer
r = append(r, newToken(curr))
curr = nil
case 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'-', '.', '_', '*', '?':
curr = append(curr, b)
default:
return r, fmt.Errorf("invalid byte: 0x%02x", b)
}
}
}
// check for unterminated escape
if esc {
return r, unterminatedEsc
}
if len(curr) > 0 {
// push token, clear buffer
r = append(r, newToken(curr))
curr = nil
}
// return success
return r, nil
}
|