...
1 package exec
2
3 import (
4 "sort"
5 "strings"
6
7 "github.com/pkg/errors"
8 )
9
10
11 type VarArgs struct {
12 Args []*Value
13 KwArgs map[string]*Value
14 }
15
16 func NewVarArgs() *VarArgs {
17 return &VarArgs{
18 Args: []*Value{},
19 KwArgs: map[string]*Value{},
20 }
21 }
22
23
24 func (va *VarArgs) First() *Value {
25 if len(va.Args) > 0 {
26 return va.Args[0]
27 }
28 return AsValue(nil)
29 }
30
31
32 func (va *VarArgs) GetKwarg(key string, fallback interface{}) *Value {
33 value, ok := va.KwArgs[key]
34 if ok {
35 return value
36 }
37 return AsValue(fallback)
38 }
39
40 type KwArg struct {
41 Name string
42 Default interface{}
43 }
44
45
46 func (va *VarArgs) Expect(args int, kwargs []*KwArg) *ReducedVarArgs {
47 rva := &ReducedVarArgs{VarArgs: va}
48 reduced := &VarArgs{
49 Args: va.Args,
50 KwArgs: map[string]*Value{},
51 }
52 reduceIdx := -1
53 unexpectedArgs := []string{}
54 if len(va.Args) < args {
55
56 if args > 1 {
57 rva.error = errors.Errorf(`Expected %d arguments, got %d`, args, len(va.Args))
58 } else {
59 rva.error = errors.Errorf(`Expected an argument, got %d`, len(va.Args))
60 }
61 return rva
62 } else if len(va.Args) > args {
63 reduced.Args = va.Args[:args]
64 for idx, arg := range va.Args[args:] {
65 if len(kwargs) > idx {
66 reduced.KwArgs[kwargs[idx].Name] = arg
67 reduceIdx = idx + 1
68 } else {
69 unexpectedArgs = append(unexpectedArgs, arg.String())
70 }
71 }
72 }
73
74 unexpectedKwArgs := []string{}
75 Loop:
76 for key, value := range va.KwArgs {
77 for idx, kwarg := range kwargs {
78 if key == kwarg.Name {
79 if reduceIdx < 0 || idx >= reduceIdx {
80 reduced.KwArgs[key] = value
81 continue Loop
82 } else {
83 rva.error = errors.Errorf(`Keyword '%s' has been submitted twice`, key)
84 break Loop
85 }
86 }
87 }
88 kv := strings.Join([]string{key, value.String()}, "=")
89 unexpectedKwArgs = append(unexpectedKwArgs, kv)
90 }
91 sort.Strings(unexpectedKwArgs)
92
93 if rva.error != nil {
94 return rva
95 }
96
97 switch {
98 case len(unexpectedArgs) == 0 && len(unexpectedKwArgs) == 0:
99 case len(unexpectedArgs) == 1 && len(unexpectedKwArgs) == 0:
100 rva.error = errors.Errorf(`Unexpected argument '%s'`, unexpectedArgs[0])
101 case len(unexpectedArgs) > 1 && len(unexpectedKwArgs) == 0:
102 rva.error = errors.Errorf(`Unexpected arguments '%s'`, strings.Join(unexpectedArgs, ", "))
103 case len(unexpectedArgs) == 0 && len(unexpectedKwArgs) == 1:
104 rva.error = errors.Errorf(`Unexpected keyword argument '%s'`, unexpectedKwArgs[0])
105 case len(unexpectedArgs) == 0 && len(unexpectedKwArgs) > 0:
106 rva.error = errors.Errorf(`Unexpected keyword arguments '%s'`, strings.Join(unexpectedKwArgs, ", "))
107 default:
108 rva.error = errors.Errorf(`Unexpected arguments '%s, %s'`,
109 strings.Join(unexpectedArgs, ", "),
110 strings.Join(unexpectedKwArgs, ", "),
111 )
112 }
113
114 if rva.error != nil {
115 return rva
116 }
117
118 for _, kwarg := range kwargs {
119 _, exists := reduced.KwArgs[kwarg.Name]
120 if !exists {
121 reduced.KwArgs[kwarg.Name] = AsValue(kwarg.Default)
122 }
123 }
124 rva.VarArgs = reduced
125 return rva
126 }
127
128
129 func (va *VarArgs) ExpectArgs(args int) *ReducedVarArgs {
130 return va.Expect(args, []*KwArg{})
131 }
132
133
134 func (va *VarArgs) ExpectNothing() *ReducedVarArgs {
135 return va.ExpectArgs(0)
136 }
137
138
139 func (va *VarArgs) ExpectKwArgs(kwargs []*KwArg) *ReducedVarArgs {
140 return va.Expect(0, kwargs)
141 }
142
143
144
145 type ReducedVarArgs struct {
146 *VarArgs
147 error error
148 }
149
150
151 func (rva *ReducedVarArgs) IsError() bool {
152 return rva.error != nil
153 }
154
155 func (rva *ReducedVarArgs) Error() string {
156 if rva.IsError() {
157 return rva.error.Error()
158 }
159 return ""
160 }
161
View as plain text