github.com/undoio/delve@v1.9.0/pkg/terminal/starbind/conv.go (about) 1 package starbind 2 3 import ( 4 "errors" 5 "fmt" 6 "math" 7 "reflect" 8 "strconv" 9 10 "go.starlark.net/starlark" 11 12 "github.com/undoio/delve/service/api" 13 ) 14 15 // autoLoadConfig is the load configuration used to automatically load more from a variable 16 var autoLoadConfig = api.LoadConfig{MaxVariableRecurse: 1, MaxStringLen: 1024, MaxArrayValues: 64, MaxStructFields: -1} 17 18 // interfaceToStarlarkValue converts an interface{} variable (produced by 19 // decoding JSON) into a starlark.Value. 20 func (env *Env) interfaceToStarlarkValue(v interface{}) starlark.Value { 21 switch v := v.(type) { 22 case uint8: 23 return starlark.MakeUint64(uint64(v)) 24 case uint16: 25 return starlark.MakeUint64(uint64(v)) 26 case uint32: 27 return starlark.MakeUint64(uint64(v)) 28 case uint64: 29 return starlark.MakeUint64(v) 30 case uintptr: 31 return starlark.MakeUint64(uint64(v)) 32 case uint: 33 return starlark.MakeUint64(uint64(v)) 34 case int8: 35 return starlark.MakeInt64(int64(v)) 36 case int16: 37 return starlark.MakeInt64(int64(v)) 38 case int32: 39 return starlark.MakeInt64(int64(v)) 40 case int64: 41 return starlark.MakeInt64(v) 42 case int: 43 return starlark.MakeInt64(int64(v)) 44 case string: 45 return starlark.String(v) 46 case map[string]uint64: 47 // this is the only map type that we use in the api, if we ever want to 48 // add more maps to the api a more general approach will be necessary. 49 var r starlark.Dict 50 for k, v := range v { 51 r.SetKey(starlark.String(k), starlark.MakeUint64(v)) 52 } 53 return &r 54 case nil: 55 return starlark.None 56 case error: 57 return starlark.String(v.Error()) 58 default: 59 vval := reflect.ValueOf(v) 60 switch vval.Type().Kind() { 61 case reflect.Ptr: 62 if vval.IsNil() { 63 return starlark.None 64 } 65 vval = vval.Elem() 66 if vval.Type().Kind() == reflect.Struct { 67 return structAsStarlarkValue{vval, env} 68 } 69 case reflect.Struct: 70 return structAsStarlarkValue{vval, env} 71 case reflect.Slice: 72 return sliceAsStarlarkValue{vval, env} 73 } 74 return starlark.String(fmt.Sprintf("%v", v)) 75 } 76 } 77 78 // sliceAsStarlarkValue converts a reflect.Value containing a slice 79 // into a starlark value. 80 // The public methods of sliceAsStarlarkValue implement the Indexable and 81 // Sequence starlark interfaces. 82 type sliceAsStarlarkValue struct { 83 v reflect.Value 84 env *Env 85 } 86 87 var _ starlark.Indexable = sliceAsStarlarkValue{} 88 var _ starlark.Sequence = sliceAsStarlarkValue{} 89 90 func (v sliceAsStarlarkValue) Freeze() { 91 } 92 93 func (v sliceAsStarlarkValue) Hash() (uint32, error) { 94 return 0, fmt.Errorf("not hashable") 95 } 96 97 func (v sliceAsStarlarkValue) String() string { 98 return fmt.Sprintf("%#v", v.v) 99 } 100 101 func (v sliceAsStarlarkValue) Truth() starlark.Bool { 102 return v.v.Len() != 0 103 } 104 105 func (v sliceAsStarlarkValue) Type() string { 106 return v.v.Type().String() 107 } 108 109 func (v sliceAsStarlarkValue) Index(i int) starlark.Value { 110 if i >= v.v.Len() { 111 return nil 112 } 113 return v.env.interfaceToStarlarkValue(v.v.Index(i).Interface()) 114 } 115 116 func (v sliceAsStarlarkValue) Len() int { 117 return v.v.Len() 118 } 119 120 func (v sliceAsStarlarkValue) Iterate() starlark.Iterator { 121 return &sliceAsStarlarkValueIterator{0, v.v, v.env} 122 } 123 124 type sliceAsStarlarkValueIterator struct { 125 cur int 126 v reflect.Value 127 env *Env 128 } 129 130 func (it *sliceAsStarlarkValueIterator) Done() { 131 } 132 133 func (it *sliceAsStarlarkValueIterator) Next(p *starlark.Value) bool { 134 if it.cur >= it.v.Len() { 135 return false 136 } 137 *p = it.env.interfaceToStarlarkValue(it.v.Index(it.cur).Interface()) 138 it.cur++ 139 return true 140 } 141 142 // structAsStarlarkValue converts any Go struct into a starlark.Value. 143 // The public methods of structAsStarlarkValue implement the 144 // starlark.HasAttrs interface. 145 type structAsStarlarkValue struct { 146 v reflect.Value 147 env *Env 148 } 149 150 var _ starlark.HasAttrs = structAsStarlarkValue{} 151 152 func (v structAsStarlarkValue) Freeze() { 153 } 154 155 func (v structAsStarlarkValue) Hash() (uint32, error) { 156 return 0, fmt.Errorf("not hashable") 157 } 158 159 func (v structAsStarlarkValue) String() string { 160 if vv, ok := v.v.Interface().(api.Variable); ok { 161 return fmt.Sprintf("Variable<%s>", vv.SinglelineString()) 162 } 163 return fmt.Sprintf("%#v", v.v) 164 } 165 166 func (v structAsStarlarkValue) Truth() starlark.Bool { 167 return true 168 } 169 170 func (v structAsStarlarkValue) Type() string { 171 if vv, ok := v.v.Interface().(api.Variable); ok { 172 return fmt.Sprintf("Variable<%s>", vv.Type) 173 } 174 return v.v.Type().String() 175 } 176 177 func (v structAsStarlarkValue) Attr(name string) (starlark.Value, error) { 178 if r, err := v.valueAttr(name); err != nil || r != nil { 179 return r, err 180 } 181 r := v.v.FieldByName(name) 182 if r == (reflect.Value{}) { 183 return starlark.None, fmt.Errorf("no field named %q in %T", name, v.v.Interface()) 184 } 185 return v.env.interfaceToStarlarkValue(r.Interface()), nil 186 } 187 188 func (v structAsStarlarkValue) valueAttr(name string) (starlark.Value, error) { 189 if v.v.Type().Name() != "Variable" || (name != "Value" && name != "Expr") { 190 return nil, nil 191 } 192 v2 := v.v.Interface().(api.Variable) 193 194 if name == "Expr" { 195 return starlark.String(varAddrExpr(&v2)), nil 196 } 197 198 return v.env.variableValueToStarlarkValue(&v2, true) 199 } 200 201 func varAddrExpr(v *api.Variable) string { 202 return fmt.Sprintf("(*(*%q)(%#x))", v.Type, v.Addr) 203 } 204 205 func (env *Env) variableValueToStarlarkValue(v *api.Variable, top bool) (starlark.Value, error) { 206 if !top && v.Addr == 0 && v.Value == "" { 207 return starlark.None, nil 208 } 209 210 switch v.Kind { 211 case reflect.Struct: 212 if v.Len != 0 && len(v.Children) == 0 { 213 return starlark.None, errors.New("value not loaded") 214 } 215 return structVariableAsStarlarkValue{v, env}, nil 216 case reflect.Slice, reflect.Array: 217 if v.Len != 0 && len(v.Children) == 0 { 218 return starlark.None, errors.New("value not loaded") 219 } 220 return sliceVariableAsStarlarkValue{v, env}, nil 221 case reflect.Map: 222 if v.Len != 0 && len(v.Children) == 0 { 223 return starlark.None, errors.New("value not loaded") 224 } 225 return mapVariableAsStarlarkValue{v, env}, nil 226 case reflect.String: 227 return starlark.String(v.Value), nil 228 case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: 229 n, _ := strconv.ParseInt(v.Value, 0, 64) 230 return starlark.MakeInt64(n), nil 231 case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint, reflect.Uintptr: 232 n, _ := strconv.ParseUint(v.Value, 0, 64) 233 return starlark.MakeUint64(n), nil 234 case reflect.Float32, reflect.Float64: 235 switch v.Value { 236 case "+Inf": 237 return starlark.Float(math.Inf(+1)), nil 238 case "-Inf": 239 return starlark.Float(math.Inf(-1)), nil 240 case "NaN": 241 return starlark.Float(math.NaN()), nil 242 default: 243 n, _ := strconv.ParseFloat(v.Value, 64) 244 return starlark.Float(n), nil 245 } 246 case reflect.Ptr, reflect.Interface: 247 if len(v.Children) > 0 { 248 v.Children[0] = *env.autoLoad(varAddrExpr(&v.Children[0])) 249 } 250 return ptrVariableAsStarlarkValue{v, env}, nil 251 } 252 return nil, nil 253 } 254 255 func (env *Env) autoLoad(expr string) *api.Variable { 256 v, err := env.ctx.Client().EvalVariable(api.EvalScope{GoroutineID: -1}, expr, autoLoadConfig) 257 if err != nil { 258 return &api.Variable{Unreadable: err.Error()} 259 } 260 return v 261 } 262 263 func (v structAsStarlarkValue) AttrNames() []string { 264 typ := v.v.Type() 265 r := make([]string, 0, typ.NumField()+1) 266 for i := 0; i < typ.NumField(); i++ { 267 r = append(r, typ.Field(i).Name) 268 } 269 return r 270 } 271 272 // structVariableAsStarlarkValue converts an api.Variable representing a 273 // struct variable (in the target process) into a starlark.Value. 274 // The public methods of structVariableAsStarlarkValue implement the 275 // starlark.HasAttrs and starlark.Mapping interfaces. 276 type structVariableAsStarlarkValue struct { 277 v *api.Variable 278 env *Env 279 } 280 281 var _ starlark.HasAttrs = structVariableAsStarlarkValue{} 282 var _ starlark.Mapping = structVariableAsStarlarkValue{} 283 284 func (v structVariableAsStarlarkValue) Freeze() { 285 } 286 287 func (v structVariableAsStarlarkValue) Hash() (uint32, error) { 288 return 0, fmt.Errorf("not hashable") 289 } 290 291 func (v structVariableAsStarlarkValue) String() string { 292 return v.v.SinglelineString() 293 } 294 295 func (v structVariableAsStarlarkValue) Truth() starlark.Bool { 296 return true 297 } 298 299 func (v structVariableAsStarlarkValue) Type() string { 300 return v.v.Type 301 } 302 303 func (v structVariableAsStarlarkValue) Attr(name string) (starlark.Value, error) { 304 for i := range v.v.Children { 305 if v.v.Children[i].Name == name { 306 v2 := v.env.autoLoad(varAddrExpr(&v.v.Children[i])) 307 return v.env.variableValueToStarlarkValue(v2, false) 308 } 309 } 310 return nil, nil // no such field or method 311 } 312 313 func (v structVariableAsStarlarkValue) AttrNames() []string { 314 r := make([]string, len(v.v.Children)) 315 for i := range v.v.Children { 316 r[i] = v.v.Children[i].Name 317 } 318 return r 319 } 320 321 func (v structVariableAsStarlarkValue) Get(key starlark.Value) (starlark.Value, bool, error) { 322 skey, ok := key.(starlark.String) 323 if !ok { 324 return starlark.None, false, nil 325 } 326 r, err := v.Attr(string(skey)) 327 if r == nil && err == nil { 328 return starlark.None, false, nil 329 } 330 if err != nil { 331 return starlark.None, false, err 332 } 333 return r, true, nil 334 } 335 336 type sliceVariableAsStarlarkValue struct { 337 v *api.Variable 338 env *Env 339 } 340 341 var _ starlark.Indexable = sliceVariableAsStarlarkValue{} 342 var _ starlark.Sequence = sliceVariableAsStarlarkValue{} 343 344 func (v sliceVariableAsStarlarkValue) Freeze() { 345 } 346 347 func (v sliceVariableAsStarlarkValue) Hash() (uint32, error) { 348 return 0, fmt.Errorf("not hashable") 349 } 350 351 func (v sliceVariableAsStarlarkValue) String() string { 352 return v.v.SinglelineString() 353 } 354 355 func (v sliceVariableAsStarlarkValue) Truth() starlark.Bool { 356 return v.v.Len != 0 357 } 358 359 func (v sliceVariableAsStarlarkValue) Type() string { 360 return v.v.Type 361 } 362 363 func (v sliceVariableAsStarlarkValue) Index(i int) starlark.Value { 364 if i >= v.Len() { 365 return nil 366 } 367 v2 := v.env.autoLoad(fmt.Sprintf("%s[%d]", varAddrExpr(v.v), i)) 368 r, err := v.env.variableValueToStarlarkValue(v2, false) 369 if err != nil { 370 return starlark.String(err.Error()) 371 } 372 return r 373 } 374 375 func (v sliceVariableAsStarlarkValue) Len() int { 376 return int(v.v.Len) 377 } 378 379 func (v sliceVariableAsStarlarkValue) Iterate() starlark.Iterator { 380 return &sliceVariableAsStarlarkValueIterator{0, v.v, v.env} 381 } 382 383 type sliceVariableAsStarlarkValueIterator struct { 384 cur int64 385 v *api.Variable 386 env *Env 387 } 388 389 func (it *sliceVariableAsStarlarkValueIterator) Done() { 390 } 391 392 func (it *sliceVariableAsStarlarkValueIterator) Next(p *starlark.Value) bool { 393 if it.cur >= it.v.Len { 394 return false 395 } 396 s := sliceVariableAsStarlarkValue{it.v, it.env} 397 *p = s.Index(int(it.cur)) 398 it.cur++ 399 return true 400 } 401 402 type ptrVariableAsStarlarkValue struct { 403 v *api.Variable 404 env *Env 405 } 406 407 var _ starlark.HasAttrs = ptrVariableAsStarlarkValue{} 408 var _ starlark.Mapping = ptrVariableAsStarlarkValue{} 409 410 func (v ptrVariableAsStarlarkValue) Freeze() { 411 } 412 413 func (v ptrVariableAsStarlarkValue) Hash() (uint32, error) { 414 return 0, fmt.Errorf("not hashable") 415 } 416 417 func (v ptrVariableAsStarlarkValue) String() string { 418 return v.v.SinglelineString() 419 } 420 421 func (v ptrVariableAsStarlarkValue) Truth() starlark.Bool { 422 return true 423 } 424 425 func (v ptrVariableAsStarlarkValue) Type() string { 426 return v.v.Type 427 } 428 429 func (v ptrVariableAsStarlarkValue) Attr(name string) (starlark.Value, error) { 430 if len(v.v.Children) == 0 { 431 return nil, nil // no such field or method 432 } 433 if v.v.Children[0].Kind == reflect.Struct { 434 // autodereference pointers to structs 435 x := structVariableAsStarlarkValue{&v.v.Children[0], v.env} 436 return x.Attr(name) 437 } else if v.v.Kind == reflect.Interface && v.v.Children[0].Kind == reflect.Ptr { 438 // allow double-autodereference for iface to ptr to struct 439 vchild := &v.v.Children[0] 440 if len(vchild.Children) > 0 { 441 vchild.Children[0] = *v.env.autoLoad(varAddrExpr(&vchild.Children[0])) 442 } 443 v2 := ptrVariableAsStarlarkValue{vchild, v.env} 444 return v2.Attr(name) 445 } 446 447 return nil, nil 448 } 449 450 func (v ptrVariableAsStarlarkValue) AttrNames() []string { 451 if v.v.Children[0].Kind != reflect.Struct { 452 return nil 453 } 454 // autodereference 455 x := structVariableAsStarlarkValue{&v.v.Children[0], v.env} 456 return x.AttrNames() 457 } 458 459 func (v ptrVariableAsStarlarkValue) Get(key starlark.Value) (starlark.Value, bool, error) { 460 if ikey, ok := key.(starlark.Int); ok { 461 if len(v.v.Children) == 0 { 462 return starlark.None, true, nil 463 } 464 if idx, _ := ikey.Int64(); idx == 0 { 465 r, err := v.env.variableValueToStarlarkValue(&v.v.Children[0], false) 466 if err != nil { 467 return starlark.String(err.Error()), true, nil 468 } 469 return r, true, nil 470 } 471 return starlark.None, false, nil 472 } 473 474 if len(v.v.Children) == 0 || v.v.Children[0].Kind != reflect.Struct { 475 return starlark.None, false, nil 476 } 477 // autodereference 478 x := structVariableAsStarlarkValue{&v.v.Children[0], v.env} 479 return x.Get(key) 480 } 481 482 type mapVariableAsStarlarkValue struct { 483 v *api.Variable 484 env *Env 485 } 486 487 var _ starlark.IterableMapping = mapVariableAsStarlarkValue{} 488 489 func (v mapVariableAsStarlarkValue) Freeze() { 490 } 491 492 func (v mapVariableAsStarlarkValue) Hash() (uint32, error) { 493 return 0, fmt.Errorf("not hashable") 494 } 495 496 func (v mapVariableAsStarlarkValue) String() string { 497 return v.v.SinglelineString() 498 } 499 500 func (v mapVariableAsStarlarkValue) Truth() starlark.Bool { 501 return true 502 } 503 504 func (v mapVariableAsStarlarkValue) Type() string { 505 return v.v.Type 506 } 507 508 func (v mapVariableAsStarlarkValue) Get(key starlark.Value) (starlark.Value, bool, error) { 509 var keyExpr string 510 switch key := key.(type) { 511 case starlark.Int: 512 keyExpr = key.String() 513 case starlark.Float: 514 keyExpr = fmt.Sprintf("%g", float64(key)) 515 case starlark.String: 516 keyExpr = fmt.Sprintf("%q", string(key)) 517 case starlark.Bool: 518 keyExpr = fmt.Sprintf("%v", bool(key)) 519 case structVariableAsStarlarkValue: 520 keyExpr = varAddrExpr(key.v) 521 default: 522 return starlark.None, false, fmt.Errorf("key type not supported %T", key) 523 } 524 525 v2 := v.env.autoLoad(fmt.Sprintf("%s[%s]", varAddrExpr(v.v), keyExpr)) 526 r, err := v.env.variableValueToStarlarkValue(v2, false) 527 if err != nil { 528 if err.Error() == "key not found" { 529 return starlark.None, false, nil 530 } 531 return starlark.None, false, err 532 } 533 return r, true, nil 534 } 535 536 func (v mapVariableAsStarlarkValue) Items() []starlark.Tuple { 537 r := make([]starlark.Tuple, 0, len(v.v.Children)/2) 538 for i := 0; i < len(v.v.Children); i += 2 { 539 r = append(r, mapStarlarkTupleAt(v.v, v.env, i)) 540 } 541 return r 542 } 543 544 func mapStarlarkTupleAt(v *api.Variable, env *Env, i int) starlark.Tuple { 545 keyv := env.autoLoad(varAddrExpr(&v.Children[i])) 546 key, err := env.variableValueToStarlarkValue(keyv, false) 547 if err != nil { 548 key = starlark.None 549 } 550 valv := env.autoLoad(varAddrExpr(&v.Children[i+1])) 551 val, err := env.variableValueToStarlarkValue(valv, false) 552 if err != nil { 553 val = starlark.None 554 } 555 return starlark.Tuple{key, val} 556 } 557 558 func (v mapVariableAsStarlarkValue) Iterate() starlark.Iterator { 559 return &mapVariableAsStarlarkValueIterator{0, v.v, v.env} 560 } 561 562 type mapVariableAsStarlarkValueIterator struct { 563 cur int 564 v *api.Variable 565 env *Env 566 } 567 568 func (it *mapVariableAsStarlarkValueIterator) Done() { 569 } 570 571 func (it *mapVariableAsStarlarkValueIterator) Next(p *starlark.Value) bool { 572 if it.cur >= 2*int(it.v.Len) { 573 return false 574 } 575 if it.cur >= len(it.v.Children) { 576 v2 := it.env.autoLoad(fmt.Sprintf("%s[%d:]", varAddrExpr(it.v), len(it.v.Children)/2)) 577 it.v.Children = append(it.v.Children, v2.Children...) 578 } 579 if it.cur >= len(it.v.Children) { 580 return false 581 } 582 583 keyv := it.env.autoLoad(varAddrExpr(&it.v.Children[it.cur])) 584 key, err := it.env.variableValueToStarlarkValue(keyv, false) 585 if err != nil { 586 key = starlark.None 587 } 588 *p = key 589 590 it.cur += 2 591 return true 592 } 593 594 // unmarshalStarlarkValue unmarshals a starlark.Value 'val' into a Go variable 'dst'. 595 // This works similarly to encoding/json.Unmarshal and similar functions, 596 // but instead of getting its input from a byte buffer, it uses a 597 // starlark.Value. 598 func unmarshalStarlarkValue(val starlark.Value, dst interface{}, path string) error { 599 return unmarshalStarlarkValueIntl(val, reflect.ValueOf(dst), path) 600 } 601 602 func unmarshalStarlarkValueIntl(val starlark.Value, dst reflect.Value, path string) (err error) { 603 defer func() { 604 // catches reflect panics 605 ierr := recover() 606 if ierr != nil { 607 err = fmt.Errorf("error setting argument %q to %s: %v", path, val, ierr) 608 } 609 }() 610 611 converr := func(args ...string) error { 612 if len(args) > 0 { 613 return fmt.Errorf("error setting argument %q: can not convert %s to %s: %s", path, val, dst.Type().String(), args[0]) 614 } 615 return fmt.Errorf("error setting argument %q: can not convert %s to %s", path, val, dst.Type().String()) 616 } 617 618 if _, isnone := val.(starlark.NoneType); isnone { 619 return nil 620 } 621 622 for dst.Kind() == reflect.Ptr { 623 if dst.IsNil() { 624 dst.Set(reflect.New(dst.Type().Elem())) 625 } 626 dst = dst.Elem() 627 } 628 629 switch val := val.(type) { 630 case starlark.Bool: 631 dst.SetBool(bool(val)) 632 case starlark.Int: 633 switch dst.Kind() { 634 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 635 n, ok := val.Uint64() 636 if !ok { 637 return converr() 638 } 639 dst.SetUint(n) 640 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 641 n, ok := val.Int64() 642 if !ok { 643 return converr() 644 } 645 dst.SetInt(n) 646 default: 647 return converr() 648 } 649 case starlark.Float: 650 dst.SetFloat(float64(val)) 651 case starlark.String: 652 dst.SetString(string(val)) 653 case *starlark.List: 654 if dst.Kind() != reflect.Slice { 655 return converr() 656 } 657 for i := 0; i < val.Len(); i++ { 658 cur := reflect.New(dst.Type().Elem()) 659 err := unmarshalStarlarkValueIntl(val.Index(i), cur, path) 660 if err != nil { 661 return err 662 } 663 } 664 case *starlark.Dict: 665 if dst.Kind() != reflect.Struct { 666 return converr() 667 } 668 for _, k := range val.Keys() { 669 if _, ok := k.(starlark.String); !ok { 670 return converr(fmt.Sprintf("non-string key %q", k.String())) 671 } 672 fieldName := string(k.(starlark.String)) 673 dstfield := dst.FieldByName(fieldName) 674 if dstfield == (reflect.Value{}) { 675 return converr(fmt.Sprintf("unknown field %s", fieldName)) 676 } 677 valfield, _, _ := val.Get(starlark.String(fieldName)) 678 err := unmarshalStarlarkValueIntl(valfield, dstfield, path+"."+fieldName) 679 if err != nil { 680 return err 681 } 682 } 683 case structAsStarlarkValue: 684 rv := val.v 685 if rv.Kind() == reflect.Ptr { 686 rv = rv.Elem() 687 } 688 dst.Set(rv) 689 default: 690 return converr() 691 } 692 return nil 693 }