-
Notifications
You must be signed in to change notification settings - Fork 0
/
config.go
152 lines (137 loc) · 3.64 KB
/
config.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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package args
import (
"fmt"
)
type specConstant uint8
// Special character constants for Config methods.
const (
SpecSymbolPrefix specConstant = iota
SpecOpenQuote
SpecCloseQuote
SpecSeparator
SpecEscape
)
type opConstant uint8
// Operator constants for Config methods.
const (
OpCond opConstant = iota
OpDump
OpImport
OpInclude
OpMacro
OpReset
OpSkip
)
// Config holds configurable special characters and operator names.
type Config struct {
specList [5]rune
opDict map[string]opConstant
}
var specialDescription = [5]string{
"symbol prefix",
"open quote",
"close quote",
"separator",
"escape",
}
// NewConfig returns the address of a new default Config.
func NewConfig() *Config {
return &Config{
specList: [5]rune{'$', '[', ']', '=', '\\'},
opDict: map[string]opConstant{
"macro": OpMacro,
"cond": OpCond,
"dump": OpDump,
"import": OpImport,
"include": OpInclude,
"reset": OpReset,
"--": OpSkip,
},
}
}
func (c *Config) copy() *Config {
var sc [5]rune
for i, r := range c.specList {
sc[i] = r
}
oc := make(map[string]opConstant, len(c.opDict))
for n, v := range c.opDict {
oc[n] = v
}
return &Config{specList: sc, opDict: oc}
}
// GetSpecial returns the character currently corresponding to a special
// character identified by its constant.
func (c *Config) GetSpecial(which specConstant) rune {
switch which {
case SpecSymbolPrefix, SpecOpenQuote, SpecCloseQuote, SpecSeparator, SpecEscape:
return c.specList[which]
}
panic(fmt.Errorf(`unknown special: %v`, which))
}
// SetSpecial changes a special character identified by a constant. Panics if
// ch is invalid, or is already used, or if spec is unknown.
func (c *Config) SetSpecial(spec specConstant, ch rune) {
switch spec {
case SpecSymbolPrefix:
case SpecOpenQuote:
case SpecCloseQuote:
case SpecSeparator:
case SpecEscape:
default:
panic(fmt.Errorf(`unknown special: %v`, spec))
}
if !validSpecial(ch) {
panic(fmt.Errorf("cannot use '%c' as %s: not a valid special character", ch, specialDescription[spec]))
}
if c.isDuplicate(spec, ch) {
panic(fmt.Errorf("cannot use '%c' as %s: already used", ch, specialDescription[spec]))
}
c.specList[spec] = ch
}
func (c *Config) isDuplicate(i specConstant, ch rune) bool {
switch i {
case 0:
return ch == c.specList[1] || ch == c.specList[2] || ch == c.specList[3] || ch == c.specList[4]
case 1:
return ch == c.specList[0] || ch == c.specList[2] || ch == c.specList[3] || ch == c.specList[4]
case 2:
return ch == c.specList[0] || ch == c.specList[1] || ch == c.specList[3] || ch == c.specList[4]
case 3:
return ch == c.specList[0] || ch == c.specList[1] || ch == c.specList[2] || ch == c.specList[4]
case 4:
return ch == c.specList[0] || ch == c.specList[1] || ch == c.specList[2] || ch == c.specList[3]
}
panic(fmt.Errorf("bug found: %d", i))
}
// GetOpName returns the name of operator op. Panics if op is unknown.
func (c *Config) GetOpName(op opConstant) string {
for n, o := range c.opDict {
if o == op {
return n
}
}
panic(fmt.Errorf(`unknown operator: %v`, op))
}
// SetOpName changes the name of an operator identified by a constant. Panics if
// name is invalid, or is already used, or if op is unknown.
func (c *Config) SetOpName(op opConstant, name string) {
if err := validate(name); err != nil {
panic(err)
}
if _, ok := c.opDict[name]; ok {
panic(fmt.Errorf(`cannot set name of %v to "%s": name already used`, op, name))
}
done := false
for n, o := range c.opDict {
if o == op {
delete(c.opDict, n)
c.opDict[name] = op
done = true
break
}
}
if !done {
panic(fmt.Errorf(`cannot set name of %v to "%s": no such operator`, op, name))
}
}