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  }