/
decl.go
130 lines (111 loc) · 2.83 KB
/
decl.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
package main
import (
"errors"
"fmt"
)
type Declaration struct {
Package string
Import []string
Prefix string // Defaults to "", could be "Err" if errors are used as part of another package
Defaults map[string]ErrorParams
Errors map[string]ErrorDef
}
type declInterfaces map[string]map[string]string
type ErrorDef struct {
D string // (D)escription
O string // (O)utput
P ErrorParams // (P)arams
Params ErrorParams // merged params
}
type ErrorParams map[string]ErrorParam
type ErrorParam struct {
T string // Go (T)ype of the param
D string // (D)escription of the param
V interface{} // Default (V)alue of the param
}
// merge sets key in eps to ep, merges info if needed
func (eps *ErrorParams) merge(key string, ep ErrorParam) error {
ep1, ok := (*eps)[key]
if !ok {
(*eps)[key] = ep
return nil
}
// key is already in the map, merge info
if ep.T != "" {
if ep1.T == "" {
ep1.T = ep.T
} else if ep1.T != ep.T {
return errors.New(fmt.Sprintf("Param %q has conflicting type %q. Default type: %q", key, ep.T, ep1.T))
}
}
if ep.D != "" {
ep1.D = ep.D
}
if ep.V != nil {
ep1.V = ep.V
}
(*eps)[key] = ep1
return nil
}
// merge lets ep2 params overwrite ep params and returns a new merged map
func mergeParams(defs map[string]ErrorParams, ep1 ErrorParams) (ep ErrorParams, err error) {
ep = ErrorParams{}
for _, errParam := range defs {
for pname, param := range errParam {
err = ep.merge(pname, param)
if err != nil {
return ep, err
}
}
}
for pname, param := range ep1 {
err = ep.merge(pname, param)
if err != nil {
return ep, err
}
}
return ep, nil
}
type reservedNames []string
func isReserved(name string) bool {
for _, n := range []string{"Error", "Wrap", "Unwrap", "Params", "ErrorCode", "Stack"} {
if n == name {
return true
}
}
return false
}
// Validate returns an error if the declaration is not valid
func (d *Declaration) Validate() (err error) {
// Check that all defaults have a type, without we cannot create
// the interfaces
for defName, errParams := range d.Defaults {
for pname, errParam := range errParams {
if isReserved(pname) {
return errors.New(fmt.Sprintf(`Error %q: Parameter cannot be reversed name %q`, defName, pname))
}
if errParam.T == "" {
return errors.New(fmt.Sprintf(`Default %q.%q requires a type.`, defName, pname))
}
}
}
for ename, errDef := range d.Errors {
for pname := range errDef.P {
if isReserved(pname) {
return errors.New(fmt.Sprintf(`Error %q: Parameter cannot be reversed name %q`, ename, pname))
}
}
errDef.Params, err = mergeParams(d.Defaults, errDef.P)
if err != nil {
return err
}
for pname, pDef := range errDef.Params {
if pDef.D == "" {
pDef.D = pname
}
errDef.Params[pname] = pDef
}
d.Errors[ename] = errDef
}
return nil
}