github.com/emcfarlane/larking@v0.0.0-20220605172417-1704b45ee6c3/starlib/starlarkrule/attrs.go (about)

     1  // Copyright 2022 Edward McFarlane. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package starlarkrule
     6  
     7  import (
     8  	_ "embed"
     9  	"fmt"
    10  	"strings"
    11  
    12  	"github.com/emcfarlane/larking/starlib/starext"
    13  	"github.com/emcfarlane/larking/starlib/starlarkstruct"
    14  	"go.starlark.net/starlark"
    15  	"go.starlark.net/syntax"
    16  )
    17  
    18  func NewAttrModule() *starlarkstruct.Module {
    19  	return &starlarkstruct.Module{
    20  		Name: "attr",
    21  		Members: starlark.StringDict{
    22  			"bool":     starext.MakeBuiltin("attr.bool", attrBool),
    23  			"int":      starext.MakeBuiltin("attr.int", attrInt),
    24  			"int_list": starext.MakeBuiltin("attr.int_list", attrIntList),
    25  			"label":    starext.MakeBuiltin("attr.label", attrLabel),
    26  			//TODO:"label_keyed_string_dict": starext.MakeBuiltin("attr.label_keyed_string_dict", attrLabelKeyedStringDict),
    27  			"label_list": starext.MakeBuiltin("attr.label_list", attrLabelList),
    28  			"string":     starext.MakeBuiltin("attr.string", attrString),
    29  			//TODO:"string_dict":             starext.MakeBuiltin("attr.string_dict", attrStringDict),
    30  			"string_list": starext.MakeBuiltin("attr.string_list", attrStringList),
    31  			//TODO:"string_list_dict":        starext.MakeBuiltin("attr.string_list_dict", attrStringListDict),
    32  		},
    33  	}
    34  }
    35  
    36  type AttrType string
    37  
    38  const (
    39  	AttrTypeBool                 AttrType = "attr.bool"
    40  	AttrTypeInt                  AttrType = "attr.int"
    41  	AttrTypeIntList              AttrType = "attr.int_list"
    42  	AttrTypeLabel                AttrType = "attr.label"
    43  	AttrTypeLabelKeyedStringDict AttrType = "attr.label_keyed_string_dict"
    44  	AttrTypeLabelList            AttrType = "attr.label_list"
    45  	AttrTypeOutput               AttrType = "attr.output"
    46  	AttrTypeOutputList           AttrType = "attr.output_list"
    47  	AttrTypeString               AttrType = "attr.string"
    48  	AttrTypeStringDict           AttrType = "attr.string_dict"
    49  	AttrTypeStringList           AttrType = "attr.string_list"
    50  	AttrTypeStringListDict       AttrType = "attr.string_list_dict"
    51  	AttrTypeResolver             AttrType = "attr.resolver"
    52  
    53  	AttrArgsConstructor starlark.String = "attr.args" // starlarkstruct constructor
    54  )
    55  
    56  // Attr defines attributes to a rules attributes.
    57  type Attr struct {
    58  	Typ        AttrType
    59  	Def        starlark.Value // default
    60  	Doc        string
    61  	Executable bool
    62  	Mandatory  bool
    63  	AllowEmpty bool
    64  	AllowFiles allowedFiles // nil, bool, globlist([]string)
    65  	Values     interface{}  // []typ
    66  
    67  	// TODO: resolver
    68  	//Resolver starlark.Callable
    69  	//Ins Outs Attr
    70  
    71  	//Output bool // declare as output value
    72  }
    73  
    74  func (a *Attr) String() string {
    75  	var b strings.Builder
    76  	b.WriteString(string(a.Typ))
    77  	b.WriteString("(")
    78  	b.WriteString("default = ")
    79  	b.WriteString(a.Def.String())
    80  	b.WriteString(", doc = " + a.Doc)
    81  	b.WriteString(", executable = ")
    82  	b.WriteString(starlark.Bool(a.Executable).String())
    83  	b.WriteString(", mandatory = ")
    84  	b.WriteString(starlark.Bool(a.Mandatory).String())
    85  	b.WriteString(", allow_empty = ")
    86  	b.WriteString(starlark.Bool(a.AllowEmpty).String())
    87  	b.WriteString(", allow_files = ")
    88  	b.WriteString(starlark.Bool(a.AllowFiles.allow).String())
    89  
    90  	b.WriteString(", values = ")
    91  	switch v := a.Values.(type) {
    92  	case []string, []int:
    93  		b.WriteString(fmt.Sprintf("%v", v))
    94  	case nil:
    95  		b.WriteString(starlark.None.String())
    96  	default:
    97  		panic(fmt.Sprintf("unhandled values type: %T", a.Values))
    98  	}
    99  	b.WriteString(")")
   100  	return b.String()
   101  }
   102  func (a *Attr) Type() string         { return string(a.Typ) }
   103  func (a *Attr) AttrType() AttrType   { return a.Typ }
   104  func (a *Attr) Freeze()              {} // immutable
   105  func (a *Attr) Truth() starlark.Bool { return true }
   106  func (a *Attr) Hash() (uint32, error) {
   107  	var x, mult uint32 = 0x345678, 1000003
   108  	for _, elem := range []starlark.Value{
   109  		starlark.String(a.Typ),
   110  		starlark.String(a.Def.String()), // TODO
   111  		starlark.String(a.Doc),
   112  		starlark.Bool(a.Executable),
   113  		starlark.Bool(a.Mandatory),
   114  		starlark.Bool(a.AllowEmpty),
   115  		starlark.String(fmt.Sprintf("%v", a.AllowFiles)),
   116  		starlark.String(fmt.Sprintf("%v", a.Values)),
   117  	} {
   118  		y, err := elem.Hash()
   119  		if err != nil {
   120  			return 0, err
   121  		}
   122  		x = x ^ y*mult
   123  		mult += 82520
   124  	}
   125  	return x, nil
   126  }
   127  
   128  func (a *Attr) IsValidType(value starlark.Value) bool {
   129  	var ok bool
   130  	switch a.Typ {
   131  	case AttrTypeBool:
   132  		_, ok = (value).(starlark.Bool)
   133  	case AttrTypeInt:
   134  		_, ok = (value).(starlark.Int)
   135  	case AttrTypeIntList:
   136  		_, ok = (value).(*starlark.List)
   137  	case AttrTypeLabel:
   138  		_, ok = (value).(*Label)
   139  		fmt.Printf("label: %T\n", value)
   140  	//case attrTypeLabelKeyedStringDict:
   141  	case AttrTypeLabelList:
   142  		list, lok := (value).(*starlark.List)
   143  		if !lok {
   144  			return false
   145  		}
   146  		for i, n := 0, list.Len(); i < n; i++ {
   147  			_, ok = (value).(*Label)
   148  			if !ok {
   149  				break
   150  			}
   151  		}
   152  	case AttrTypeOutput:
   153  		_, ok = (value).(starlark.String)
   154  	case AttrTypeOutputList:
   155  		_, ok = (value).(*starlark.List)
   156  	case AttrTypeString:
   157  		_, ok = (value).(starlark.String)
   158  	//case attrTypeStringDict:
   159  	case AttrTypeStringList:
   160  		_, ok = (value).(*starlark.List)
   161  	//case attrTypeStringListDict:
   162  	default:
   163  		panic(fmt.Sprintf("unhandled type: %s", a.Typ))
   164  	}
   165  	return ok
   166  }
   167  
   168  func attrEqual(x, y *Attr, depth int) (bool, error) {
   169  	if ok := (x.Typ == y.Typ &&
   170  		x.Def == y.Def &&
   171  		x.Executable == y.Executable &&
   172  		x.Mandatory == y.Mandatory &&
   173  		x.AllowEmpty == y.AllowEmpty); !ok {
   174  		return ok, nil
   175  	}
   176  
   177  	if ok, err := starlark.EqualDepth(x.Def, y.Def, depth-1); !ok || err != nil {
   178  		return ok, err
   179  	}
   180  
   181  	switch x := x.Values.(type) {
   182  	case []string:
   183  		y, ok := y.Values.([]string)
   184  		if !ok {
   185  			return false, nil
   186  		}
   187  		if len(x) != len(y) {
   188  			return false, nil
   189  		}
   190  		for i, n := 0, len(x); i < n; i++ {
   191  			if x[i] != y[i] {
   192  				return false, nil
   193  			}
   194  		}
   195  
   196  	case []int:
   197  		y, ok := y.Values.([]int)
   198  		if !ok {
   199  			return false, nil
   200  		}
   201  		if len(x) != len(y) {
   202  			return false, nil
   203  		}
   204  		for i, n := 0, len(x); i < n; i++ {
   205  			if x[i] != y[i] {
   206  				return false, nil
   207  			}
   208  		}
   209  	case nil:
   210  		if ok := x == y.Values; !ok {
   211  			return ok, nil
   212  		}
   213  	default:
   214  		return false, nil
   215  	}
   216  	return true, nil
   217  }
   218  
   219  func (x *Attr) CompareSameType(op syntax.Token, y_ starlark.Value, depth int) (bool, error) {
   220  	y := y_.(*Attr)
   221  	switch op {
   222  	case syntax.EQL:
   223  		return attrEqual(x, y, depth)
   224  	case syntax.NEQ:
   225  		eq, err := attrEqual(x, y, depth)
   226  		return !eq, err
   227  	default:
   228  		return false, fmt.Errorf("%s %s %s not implemented", x.Type(), op, y.Type())
   229  	}
   230  }
   231  
   232  // Attribute attr.bool(default=False, doc='', mandatory=False)
   233  func attrBool(thread *starlark.Thread, fnname string, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
   234  	var (
   235  		def       bool
   236  		doc       string
   237  		mandatory bool
   238  	)
   239  
   240  	if err := starlark.UnpackArgs(
   241  		fnname, args, kwargs,
   242  		"default?", &def, "doc?", &doc, "mandatory?", &mandatory,
   243  	); err != nil {
   244  		return nil, err
   245  	}
   246  
   247  	return &Attr{
   248  		Typ:       AttrTypeBool,
   249  		Def:       starlark.Bool(def),
   250  		Doc:       doc,
   251  		Mandatory: mandatory,
   252  	}, nil
   253  }
   254  
   255  // Attribute attr.int(default=0, doc='', mandatory=False, values=[])
   256  func attrInt(thread *starlark.Thread, fnname string, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
   257  	var (
   258  		def       = starlark.MakeInt(0)
   259  		doc       string
   260  		mandatory bool
   261  		values    *starlark.List
   262  	)
   263  
   264  	if err := starlark.UnpackArgs(
   265  		fnname, args, kwargs,
   266  		"default?", &def, "doc?", &doc, "mandatory?", &mandatory, "values?", &values,
   267  	); err != nil {
   268  		return nil, err
   269  	}
   270  
   271  	var ints []int
   272  	if values != nil {
   273  		iter := values.Iterate()
   274  		var x starlark.Value
   275  		for iter.Next(&x) {
   276  			i, err := starlark.AsInt32(x)
   277  			if err != nil {
   278  				return nil, err
   279  			}
   280  			ints = append(ints, i)
   281  		}
   282  		iter.Done()
   283  	}
   284  
   285  	return &Attr{
   286  		Typ:       AttrTypeInt,
   287  		Def:       def,
   288  		Doc:       doc,
   289  		Mandatory: mandatory,
   290  		Values:    ints,
   291  	}, nil
   292  }
   293  
   294  // Attribute attr.int_list(mandatory=False, allow_empty=True, *, default=[], doc='')
   295  func attrIntList(thread *starlark.Thread, fnname string, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
   296  	var (
   297  		def        *starlark.List
   298  		doc        string
   299  		mandatory  bool
   300  		allowEmpty bool
   301  	)
   302  	if err := starlark.UnpackArgs(
   303  		fnname, args, kwargs,
   304  		"default?", &def, "doc?", &doc, "mandatory?", &mandatory, "allowEmpty?", &allowEmpty,
   305  	); err != nil {
   306  		return nil, err
   307  	}
   308  
   309  	iter := def.Iterate()
   310  	var x starlark.Value
   311  	for iter.Next(&x) {
   312  		if _, err := starlark.AsInt32(x); err != nil {
   313  			return nil, err
   314  		}
   315  	}
   316  	iter.Done()
   317  
   318  	return &Attr{
   319  		Typ:        AttrTypeIntList,
   320  		Def:        def,
   321  		Doc:        doc,
   322  		Mandatory:  mandatory,
   323  		AllowEmpty: allowEmpty,
   324  	}, nil
   325  }
   326  
   327  type allowedFiles struct {
   328  	allow bool
   329  	types []string // path.Match syntax?
   330  }
   331  
   332  func parseAllowFiles(allowFiles starlark.Value) (allowedFiles, error) {
   333  	switch v := allowFiles.(type) {
   334  	case nil:
   335  		return allowedFiles{allow: false}, nil
   336  	case starlark.Bool:
   337  		return allowedFiles{allow: bool(v)}, nil
   338  	case *starlark.List:
   339  		types := make([]string, v.Len())
   340  		for i, n := 0, v.Len(); i < n; i++ {
   341  			x := v.Index(i)
   342  			v, ok := starlark.AsString(x)
   343  			if !ok {
   344  				return allowedFiles{}, fmt.Errorf("unexpected type: %v", x.Type())
   345  			}
   346  			types[i] = string(v)
   347  		}
   348  		return allowedFiles{allow: true, types: types}, nil
   349  	default:
   350  		panic(fmt.Sprintf("TODO: handle allow_files type: %T", allowFiles))
   351  	}
   352  }
   353  
   354  // Attribute attr.label(default=None, doc='', executable=False, allow_files=None, allow_single_file=None, mandatory=False, providers=[], allow_rules=None, cfg=None, aspects=[])
   355  func attrLabel(thread *starlark.Thread, fnname string, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
   356  	var (
   357  		def        starlark.String
   358  		doc        string
   359  		executable = false
   360  		mandatory  bool
   361  		values     *starlark.List
   362  		allowFiles starlark.Value
   363  
   364  		// TODO: more types!
   365  		//providers
   366  	)
   367  
   368  	if err := starlark.UnpackArgs(
   369  		fnname, args, kwargs,
   370  		"default?", &def, "doc?", &doc, "executable", &executable, "mandatory?", &mandatory, "values?", &values, "allow_files?", &allowFiles,
   371  	); err != nil {
   372  		return nil, err
   373  	}
   374  
   375  	var vals []string
   376  	if values != nil {
   377  		iter := values.Iterate()
   378  		var x starlark.Value
   379  		for iter.Next(&x) {
   380  			s, ok := starlark.AsString(x)
   381  			if !ok {
   382  				return nil, fmt.Errorf("got %s, want string", x.Type())
   383  			}
   384  			vals = append(vals, s)
   385  		}
   386  		iter.Done()
   387  	}
   388  
   389  	af, err := parseAllowFiles(allowFiles)
   390  	if err != nil {
   391  		return nil, err
   392  	}
   393  
   394  	var defValue starlark.Value = starlark.None
   395  	if len(def) > 0 {
   396  		defValue = def
   397  	}
   398  
   399  	return &Attr{
   400  		Typ:        AttrTypeLabel,
   401  		Def:        defValue,
   402  		Doc:        doc,
   403  		Mandatory:  mandatory,
   404  		Values:     vals,
   405  		AllowFiles: af,
   406  	}, nil
   407  }
   408  
   409  // attr.label_list(allow_empty=True, *, default=[], doc='', allow_files=None, providers=[], flags=[], mandatory=False, cfg=None, aspects=[])
   410  func attrLabelList(thread *starlark.Thread, fnname string, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
   411  	var (
   412  		def        *starlark.List
   413  		doc        string
   414  		mandatory  bool
   415  		allowEmpty bool = true
   416  		allowFiles starlark.Value
   417  	)
   418  	if err := starlark.UnpackArgs(
   419  		fnname, args, kwargs,
   420  		"default?", &def, "doc?", &doc, "mandatory?", &mandatory, "allow_empty?", &allowEmpty, "allow_files?", &allowFiles,
   421  	); err != nil {
   422  		return nil, err
   423  	}
   424  
   425  	var defValue starlark.Value = starlark.None
   426  	if def != nil {
   427  		iter := def.Iterate()
   428  		var x starlark.Value
   429  		for iter.Next(&x) {
   430  			if _, ok := starlark.AsString(x); !ok {
   431  				return nil, fmt.Errorf("got %s, want string", x.Type())
   432  			}
   433  		}
   434  		iter.Done()
   435  		defValue = def
   436  	}
   437  
   438  	af, err := parseAllowFiles(allowFiles)
   439  	if err != nil {
   440  		return nil, err
   441  	}
   442  
   443  	return &Attr{
   444  		Typ:        AttrTypeLabelList,
   445  		Doc:        doc,
   446  		Def:        defValue,
   447  		Mandatory:  mandatory,
   448  		AllowEmpty: allowEmpty,
   449  		AllowFiles: af,
   450  	}, nil
   451  }
   452  
   453  func attrString(thread *starlark.Thread, fnname string, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
   454  	var (
   455  		def       starlark.String
   456  		doc       string
   457  		mandatory bool
   458  		values    *starlark.List
   459  	)
   460  
   461  	if err := starlark.UnpackArgs(
   462  		fnname, args, kwargs,
   463  		"default?", &def, "doc?", &doc, "mandatory?", &mandatory, "values?", &values,
   464  	); err != nil {
   465  		return nil, err
   466  	}
   467  
   468  	var strings []string
   469  	if values != nil {
   470  		iter := values.Iterate()
   471  		var x starlark.Value
   472  		for iter.Next(&x) {
   473  			s, ok := starlark.AsString(x)
   474  			if !ok {
   475  				return nil, fmt.Errorf("got %s, want string", x.Type())
   476  			}
   477  			strings = append(strings, s)
   478  		}
   479  		iter.Done()
   480  	}
   481  
   482  	return &Attr{
   483  		Typ:       AttrTypeString,
   484  		Def:       def,
   485  		Doc:       doc,
   486  		Mandatory: mandatory,
   487  		Values:    strings,
   488  	}, nil
   489  }
   490  
   491  func attrStringList(thread *starlark.Thread, fnname string, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
   492  	var (
   493  		def        *starlark.List
   494  		doc        string
   495  		mandatory  bool
   496  		allowEmpty bool
   497  	)
   498  	if err := starlark.UnpackArgs(
   499  		fnname, args, kwargs,
   500  		"default?", &def, "doc?", &doc, "mandatory?", &mandatory, "allowEmpty?", &allowEmpty,
   501  	); err != nil {
   502  		return nil, err
   503  	}
   504  
   505  	// Check defaults are all strings
   506  	if def != nil {
   507  		iter := def.Iterate()
   508  		var x starlark.Value
   509  		for iter.Next(&x) {
   510  			if _, ok := starlark.AsString(x); !ok {
   511  				return nil, fmt.Errorf("got %s, want string", x.Type())
   512  			}
   513  		}
   514  		iter.Done()
   515  	}
   516  
   517  	return &Attr{
   518  		Typ:       AttrTypeStringList,
   519  		Def:       def,
   520  		Doc:       doc,
   521  		Mandatory: mandatory,
   522  	}, nil
   523  }
   524  
   525  // Attrs -> AttrArgs
   526  type Attrs struct {
   527  	osd    starext.OrderedStringDict
   528  	frozen bool
   529  }
   530  
   531  func (a *Attrs) String() string {
   532  	buf := new(strings.Builder)
   533  	buf.WriteString("attrs")
   534  	buf.WriteByte('(')
   535  	for i := 0; i < a.osd.Len(); i++ {
   536  		k, v := a.osd.KeyIndex(i)
   537  		if i > 0 {
   538  			buf.WriteString(", ")
   539  		}
   540  		buf.WriteString(k)
   541  		buf.WriteString(" = ")
   542  		buf.WriteString(v.String())
   543  	}
   544  	buf.WriteByte(')')
   545  	return buf.String()
   546  }
   547  func (a *Attrs) Truth() starlark.Bool { return true } // even when empty
   548  func (a *Attrs) Type() string         { return "attrs" }
   549  func (a *Attrs) Hash() (uint32, error) {
   550  	// Same algorithm as struct...
   551  	var x, m uint32 = 8731, 9839
   552  	for i, n := 0, a.osd.Len(); i < n; i++ {
   553  		k, v := a.osd.KeyIndex(i)
   554  		namehash, _ := starlark.String(k).Hash()
   555  		x = x ^ 3*namehash
   556  		y, err := v.Hash()
   557  		if err != nil {
   558  			return 0, err
   559  		}
   560  		x = x ^ y*m
   561  		m += 7349
   562  	}
   563  	return x, nil
   564  }
   565  func (a *Attrs) Freeze() {
   566  	if a.frozen {
   567  		return
   568  	}
   569  	a.frozen = true
   570  	for i, n := 0, a.osd.Len(); i < n; i++ {
   571  		a.osd.Index(i).Freeze()
   572  	}
   573  }
   574  
   575  // checkMutable reports an error if the list should not be mutated.
   576  // verb+" list" should describe the operation.
   577  func (a *Attrs) checkMutable(verb string) error {
   578  	if a.frozen {
   579  		return fmt.Errorf("cannot %s frozen attrs", verb)
   580  	}
   581  	return nil
   582  }
   583  
   584  func (a *Attrs) Attr(name string) (starlark.Value, error) {
   585  	if v, ok := a.osd.Get(name); ok {
   586  		return v, nil
   587  	}
   588  	return nil, starlark.NoSuchAttrError(
   589  		fmt.Sprintf("attrs has no .%s attribute", name))
   590  }
   591  func (a *Attrs) AttrNames() []string { return a.osd.Keys() }
   592  
   593  func attrsEqual(x, y *Attrs, depth int) (bool, error) {
   594  	if x.Len() != y.Len() {
   595  		return false, nil
   596  	}
   597  	for i, n := 0, x.Len(); i < n; i++ {
   598  		x, y := x.Index(i).(*Attr), y.Index(i).(*Attr)
   599  		eq, err := attrEqual(x, y, depth-1)
   600  		if !eq || err != nil {
   601  			return eq, err
   602  		}
   603  	}
   604  	return true, nil
   605  }
   606  
   607  func (x *Attrs) CompareSameType(op syntax.Token, y_ starlark.Value, depth int) (bool, error) {
   608  	y := y_.(*Attrs)
   609  	switch op {
   610  	case syntax.EQL:
   611  		return attrsEqual(x, y, depth)
   612  	case syntax.NEQ:
   613  		eq, err := attrsEqual(x, y, depth)
   614  		return !eq, err
   615  	default:
   616  		return false, fmt.Errorf("%s %s %s not implemented", x.Type(), op, y.Type())
   617  	}
   618  }
   619  func (a *Attrs) Index(i int) starlark.Value { return a.osd.Index(i) }
   620  func (a *Attrs) Len() int                   { return a.osd.Len() }
   621  
   622  func MakeAttrs(thread *starlark.Thread, fnname string, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
   623  	if err := starlark.UnpackArgs(fnname, args, nil); err != nil {
   624  		return nil, err
   625  	}
   626  
   627  	osd := starext.NewOrderedStringDict(len(kwargs))
   628  	for _, kwarg := range kwargs {
   629  		name, _ := starlark.AsString(kwarg[0])
   630  		a, ok := kwarg[1].(*Attr)
   631  		if !ok {
   632  			return nil, fmt.Errorf("unexpected attribute value type: %T", kwarg[1])
   633  		}
   634  		osd.Insert(name, a)
   635  	}
   636  	osd.Sort()
   637  
   638  	return &Attrs{
   639  		osd:    *osd,
   640  		frozen: false,
   641  	}, nil
   642  }
   643  
   644  func (a *Attrs) Get(name string) (*Attr, bool) {
   645  	attr, ok := a.osd.Get(name)
   646  	if !ok {
   647  		return nil, ok
   648  	}
   649  	return attr.(*Attr), ok
   650  }
   651  
   652  func (a *Attrs) MakeArgs(source *Label, kwargs []starlark.Tuple) (*AttrArgs, error) {
   653  	attrSeen := make(map[string]bool)
   654  	attrArgs := starext.NewOrderedStringDict(len(kwargs))
   655  	for _, kwarg := range kwargs {
   656  		name := string(kwarg[0].(starlark.String))
   657  		value := kwarg[1]
   658  
   659  		attr, ok := a.Get(name)
   660  		if !ok {
   661  			return nil, fmt.Errorf("unexpected attribute: %s", name)
   662  		}
   663  
   664  		value, err := asAttrValue(source, name, attr, value)
   665  		if err != nil {
   666  			return nil, err
   667  		}
   668  		attrArgs.Insert(name, value)
   669  		attrSeen[name] = true
   670  	}
   671  
   672  	// Mandatory checks
   673  	for i, n := 0, a.osd.Len(); i < n; i++ {
   674  		name, x := a.osd.KeyIndex(i)
   675  		attr := x.(*Attr)
   676  		if !attrSeen[name] {
   677  			if attr.Mandatory {
   678  				return nil, fmt.Errorf("missing mandatory attribute: %s", name)
   679  			}
   680  			attrArgs.Insert(name, attr.Def)
   681  		}
   682  	}
   683  	attrArgs.Sort()
   684  	s := starlarkstruct.OrderedStringDictAsStruct(AttrArgsConstructor, attrArgs)
   685  	return &AttrArgs{
   686  		attrs:  a,
   687  		Struct: *s,
   688  	}, nil
   689  }
   690  
   691  func (a *Attrs) Name() string { return "attrargs" }
   692  func (a *Attrs) CallInternal(thread *starlark.Thread, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
   693  	if err := starlark.UnpackArgs("attrs", args, nil); err != nil {
   694  		return nil, err
   695  	}
   696  	source, err := ParseLabel(thread.Name)
   697  	if err != nil {
   698  		fmt.Println("Here?", err)
   699  		return nil, err
   700  	}
   701  	return a.MakeArgs(source, kwargs)
   702  }
   703  
   704  func asAttrValue(
   705  	source *Label,
   706  	name string,
   707  	attr *Attr,
   708  	value starlark.Value,
   709  ) (starlark.Value, error) {
   710  	errField := func(msg string) error {
   711  		return fmt.Errorf(
   712  			"%s %s(%s): %v", msg, name, attr.Typ, value,
   713  		)
   714  	}
   715  	errError := func(err error) error {
   716  		return fmt.Errorf(
   717  			"invalid %s(%s): %v: %v",
   718  			name, attr.Typ, value, err,
   719  		)
   720  	}
   721  	toLabel := func(v starlark.Value) (*Label, error) {
   722  		switch v := (v).(type) {
   723  		case starlark.String:
   724  			l, err := source.Parse(string(v))
   725  			if err != nil {
   726  				return nil, errError(err)
   727  			}
   728  			return l, nil
   729  		case *Label:
   730  			return v, nil
   731  		default:
   732  			return nil, errField("invalid")
   733  		}
   734  	}
   735  
   736  	if attr.IsValidType(value) {
   737  		return value, nil
   738  	}
   739  
   740  	switch attr.Typ {
   741  	case AttrTypeLabel:
   742  		if value == starlark.None {
   743  			return value, nil
   744  		}
   745  
   746  		l, err := toLabel(value)
   747  		if err != nil {
   748  			return nil, err
   749  		}
   750  		return l, nil
   751  	//case attrTypeLabelKeyedStringDict:
   752  	case AttrTypeLabelList:
   753  		if value == starlark.None {
   754  			return value, nil
   755  		}
   756  
   757  		list, ok := (value).(*starlark.List)
   758  		if !ok {
   759  			return nil, errField("type")
   760  		}
   761  
   762  		var elems []starlark.Value
   763  		for i, n := 0, list.Len(); i < n; i++ {
   764  			val := list.Index(i)
   765  
   766  			l, err := toLabel(val)
   767  			if err != nil {
   768  				return nil, err
   769  			}
   770  			elems = append(elems, l)
   771  		}
   772  		return starlark.NewList(elems), nil
   773  	default:
   774  		return nil, errField("undefined")
   775  	}
   776  }
   777  
   778  type AttrArgs struct {
   779  	attrs *Attrs
   780  	starlarkstruct.Struct
   781  }
   782  
   783  func attrArgsEqual(x, y *AttrArgs, depth int) (bool, error) {
   784  	if ok, err := attrsEqual(x.attrs, y.attrs, depth-1); !ok || err != nil {
   785  		return ok, err
   786  	}
   787  	return x.Struct.CompareSameType(syntax.EQL, &y.Struct, depth-1)
   788  }
   789  
   790  func (x *AttrArgs) CompareSameType(op syntax.Token, y_ starlark.Value, depth int) (bool, error) {
   791  	y := y_.(*AttrArgs)
   792  	switch op {
   793  	case syntax.EQL:
   794  		return attrArgsEqual(x, y, depth)
   795  	case syntax.NEQ:
   796  		eq, err := attrArgsEqual(x, y, depth)
   797  		return !eq, err
   798  	default:
   799  		return false, fmt.Errorf("%s %s %s not implemented", x.Type(), op, y.Type())
   800  	}
   801  }
   802  
   803  func (a *AttrArgs) Attrs() *Attrs { return a.attrs }
   804  
   805  func (a *AttrArgs) Clone() *AttrArgs {
   806  	osd := starext.NewOrderedStringDict(a.attrs.Len())
   807  	a.ToOrderedStringDict(osd)
   808  	s := starlarkstruct.OrderedStringDictAsStruct(AttrArgsConstructor, osd)
   809  	return &AttrArgs{
   810  		attrs:  a.attrs,
   811  		Struct: *s,
   812  	}
   813  }
   814  
   815  var _ (starlark.Callable) = (*Attrs)(nil)
   816  
   817  //go:embed info.star
   818  var infoSrc string
   819  
   820  var (
   821  	DefaultInfo   *Attrs
   822  	ContainerInfo *Attrs
   823  )
   824  
   825  func init() {
   826  	info, err := starlark.ExecFile(
   827  		&starlark.Thread{Name: "internal"},
   828  		"rule/info.star",
   829  		infoSrc,
   830  		starlark.StringDict{
   831  			"attr":  NewAttrModule(),
   832  			"attrs": starext.MakeBuiltin("rule.attrs", MakeAttrs),
   833  		},
   834  	)
   835  	if err != nil {
   836  		panic(err)
   837  	}
   838  	DefaultInfo = info["DefaultInfo"].(*Attrs)
   839  	ContainerInfo = info["ContainerInfo"].(*Attrs)
   840  }