/
patterns.go
123 lines (106 loc) · 2.48 KB
/
patterns.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
package cmd
import (
"regexp"
"strconv"
"strings"
)
// Key is an element of the patterns used to define command parameters
// for email requests.
type Key uint32
const (
// KeyRepeated is written +, represents any positive number of repetitions
// of the previous pattern element.
KeyRepeated Key = Key(0)
// KeyRepeatedNull is written * represents any number of repetitions of
// the previous pattern element, including zero.
KeyRepeatedNull Key = Key(1)
// KeyBoolean represents a boolean value.
KeyBoolean Key = Key(2)
// KeyNatural represents a natural number value.
KeyNatural Key = Key(3)
// KeyString represents a string value.
KeyString Key = Key(4)
// KeySymbol represents a symbol value.
KeySymbol Key = Key(5)
)
var (
regexNatural = regexp.MustCompile("[0-9]+")
regexString = regexp.MustCompile("\\\".*\\\"")
regexSymbol = regexp.MustCompile("[a-zA-Z][a-zA-Z0-9]+")
)
func keyString(key Key) string {
switch key {
case KeyRepeated:
return "+"
case KeyRepeatedNull:
return "*"
case KeyBoolean:
return " boolean"
case KeyNatural:
return " natural"
case KeyString:
return " string"
case KeySymbol:
return " symbol"
default:
return ""
}
}
// Pattern represents a valid way of interpreting a command with a set of
// parameters.
type Pattern struct {
help string
key []Key
read func([]string) (Command, error)
}
func patternString(keys []Key) string {
str := make([]string, len(keys))
for i, key := range keys {
str[i] = keyString(key)
}
return strings.Join(str, "")
}
func recognizedPatterns(patterns []Pattern) [][]Key {
key := make([][]Key, len(patterns))
for i, p := range patterns {
key[i] = p.key
}
return key
}
// ReadPattern attempts to return a type corresponding to the given pattern
// which is read from the given string.
func ReadPattern(params []string, elements ...interface{}) error {
if len(params) != len(elements) {
return &ErrInvalidNumberOfParameters{
params: params,
expected: uint32(len(elements)),
}
}
for i, elem := range elements {
param := params[i]
switch e := elem.(type) {
default:
return ErrInvalidType
case *bool:
if param == "true" {
*e = true
} else if param == "false" {
*e = false
} else {
return ErrInvalidBoolean
}
case *uint64:
n, err := strconv.ParseUint(param, 10, 64)
if err != nil {
return err
}
*e = n
case *string:
if !regexString.Match([]byte(param)) {
return ErrInvalidString
}
*e = param[1 : len(param)-1]
}
}
return nil
}