1 package starlark
2
3
4
5
6 import (
7 "fmt"
8 "log"
9 "reflect"
10 "strings"
11
12 "go.starlark.net/internal/spell"
13 )
14
15
16
17 type Unpacker interface {
18 Unpack(v Value) error
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 func UnpackArgs(fnname string, args Tuple, kwargs []Tuple, pairs ...interface{}) error {
94 nparams := len(pairs) / 2
95 var defined intset
96 defined.init(nparams)
97
98 paramName := func(x interface{}) (name string, skipNone bool) {
99 name = x.(string)
100 if strings.HasSuffix(name, "??") {
101 name = strings.TrimSuffix(name, "??")
102 skipNone = true
103 } else if name[len(name)-1] == '?' {
104 name = name[:len(name)-1]
105 }
106
107 return name, skipNone
108 }
109
110
111 if len(args) > nparams {
112 return fmt.Errorf("%s: got %d arguments, want at most %d",
113 fnname, len(args), nparams)
114 }
115 for i, arg := range args {
116 defined.set(i)
117 name, skipNone := paramName(pairs[2*i])
118 if skipNone {
119 if _, isNone := arg.(NoneType); isNone {
120 continue
121 }
122 }
123 if err := unpackOneArg(arg, pairs[2*i+1]); err != nil {
124 return fmt.Errorf("%s: for parameter %s: %s", fnname, name, err)
125 }
126 }
127
128
129 kwloop:
130 for _, item := range kwargs {
131 name, arg := item[0].(String), item[1]
132 for i := 0; i < nparams; i++ {
133 pName, skipNone := paramName(pairs[2*i])
134 if pName == string(name) {
135
136 if defined.set(i) {
137 return fmt.Errorf("%s: got multiple values for keyword argument %s",
138 fnname, name)
139 }
140
141 if skipNone {
142 if _, isNone := arg.(NoneType); isNone {
143 continue kwloop
144 }
145 }
146
147 ptr := pairs[2*i+1]
148 if err := unpackOneArg(arg, ptr); err != nil {
149 return fmt.Errorf("%s: for parameter %s: %s", fnname, name, err)
150 }
151 continue kwloop
152 }
153 }
154 err := fmt.Errorf("%s: unexpected keyword argument %s", fnname, name)
155 names := make([]string, 0, nparams)
156 for i := 0; i < nparams; i += 2 {
157 param, _ := paramName(pairs[i])
158 names = append(names, param)
159 }
160 if n := spell.Nearest(string(name), names); n != "" {
161 err = fmt.Errorf("%s (did you mean %s?)", err.Error(), n)
162 }
163 return err
164 }
165
166
167
168 for i := len(args); i < nparams; i++ {
169 name := pairs[2*i].(string)
170 if strings.HasSuffix(name, "?") {
171 break
172 }
173 if !defined.get(i) {
174 return fmt.Errorf("%s: missing argument for %s", fnname, name)
175 }
176 }
177
178 return nil
179 }
180
181
182
183
184
185
186
187
188
189
190 func UnpackPositionalArgs(fnname string, args Tuple, kwargs []Tuple, min int, vars ...interface{}) error {
191 if len(kwargs) > 0 {
192 return fmt.Errorf("%s: unexpected keyword arguments", fnname)
193 }
194 max := len(vars)
195 if len(args) < min {
196 var atleast string
197 if min < max {
198 atleast = "at least "
199 }
200 return fmt.Errorf("%s: got %d arguments, want %s%d", fnname, len(args), atleast, min)
201 }
202 if len(args) > max {
203 var atmost string
204 if max > min {
205 atmost = "at most "
206 }
207 return fmt.Errorf("%s: got %d arguments, want %s%d", fnname, len(args), atmost, max)
208 }
209 for i, arg := range args {
210 if err := unpackOneArg(arg, vars[i]); err != nil {
211 return fmt.Errorf("%s: for parameter %d: %s", fnname, i+1, err)
212 }
213 }
214 return nil
215 }
216
217 func unpackOneArg(v Value, ptr interface{}) error {
218
219 switch ptr := ptr.(type) {
220 case Unpacker:
221 return ptr.Unpack(v)
222 case *Value:
223 *ptr = v
224 case *string:
225 s, ok := AsString(v)
226 if !ok {
227 return fmt.Errorf("got %s, want string", v.Type())
228 }
229 *ptr = s
230 case *bool:
231 b, ok := v.(Bool)
232 if !ok {
233 return fmt.Errorf("got %s, want bool", v.Type())
234 }
235 *ptr = bool(b)
236 case *int, *int8, *int16, *int32, *int64,
237 *uint, *uint8, *uint16, *uint32, *uint64, *uintptr:
238 return AsInt(v, ptr)
239 case *float64:
240 f, ok := v.(Float)
241 if !ok {
242 return fmt.Errorf("got %s, want float", v.Type())
243 }
244 *ptr = float64(f)
245 case **List:
246 list, ok := v.(*List)
247 if !ok {
248 return fmt.Errorf("got %s, want list", v.Type())
249 }
250 *ptr = list
251 case **Dict:
252 dict, ok := v.(*Dict)
253 if !ok {
254 return fmt.Errorf("got %s, want dict", v.Type())
255 }
256 *ptr = dict
257 case *Callable:
258 f, ok := v.(Callable)
259 if !ok {
260 return fmt.Errorf("got %s, want callable", v.Type())
261 }
262 *ptr = f
263 case *Iterable:
264 it, ok := v.(Iterable)
265 if !ok {
266 return fmt.Errorf("got %s, want iterable", v.Type())
267 }
268 *ptr = it
269 default:
270
271 ptrv := reflect.ValueOf(ptr)
272 if ptrv.Kind() != reflect.Ptr {
273 log.Panicf("internal error: not a pointer: %T", ptr)
274 }
275 paramVar := ptrv.Elem()
276 if !reflect.TypeOf(v).AssignableTo(paramVar.Type()) {
277
278
279
280
281
282 if !paramVar.Type().AssignableTo(reflect.TypeOf(new(Value)).Elem()) {
283 log.Panicf("pointer element type does not implement Value: %T", ptr)
284 }
285
286
287
288
289
290
291
292
293
294
295
296
297
298 paramType := paramVar.Type().String()
299
300
301 func() {
302 defer func() { recover() }()
303 if typer, _ := paramVar.Interface().(interface{ Type() string }); typer != nil {
304 paramType = typer.Type()
305 }
306 }()
307 return fmt.Errorf("got %s, want %s", v.Type(), paramType)
308 }
309 paramVar.Set(reflect.ValueOf(v))
310 }
311 return nil
312 }
313
314 type intset struct {
315 small uint64
316 large map[int]bool
317 }
318
319 func (is *intset) init(n int) {
320 if n >= 64 {
321 is.large = make(map[int]bool)
322 }
323 }
324
325 func (is *intset) set(i int) (prev bool) {
326 if is.large == nil {
327 prev = is.small&(1<<uint(i)) != 0
328 is.small |= 1 << uint(i)
329 } else {
330 prev = is.large[i]
331 is.large[i] = true
332 }
333 return
334 }
335
336 func (is *intset) get(i int) bool {
337 if is.large == nil {
338 return is.small&(1<<uint(i)) != 0
339 }
340 return is.large[i]
341 }
342
343 func (is *intset) len() int {
344 if is.large == nil {
345
346 len := 0
347 for i := 0; i < 64; i++ {
348 if is.small&(1<<uint(i)) != 0 {
349 len++
350 }
351 }
352 return len
353 }
354 return len(is.large)
355 }
356
View as plain text