golang.org/x/arch@v0.17.0/internal/unify/domain.go (about)

     1  // Copyright 2025 The Go Authors. 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 unify
     6  
     7  import (
     8  	"fmt"
     9  	"iter"
    10  	"maps"
    11  	"reflect"
    12  	"regexp"
    13  	"slices"
    14  	"strconv"
    15  	"strings"
    16  )
    17  
    18  // A Domain is a non-empty set of values, all of the same kind.
    19  //
    20  // Domain may be a scalar:
    21  //
    22  //   - [String] - Represents string-typed values.
    23  //
    24  // Or a composite:
    25  //
    26  //   - [Def] - A mapping from fixed keys to [Domain]s.
    27  //
    28  //   - [Tuple] - A fixed-length sequence of [Domain]s or
    29  //     all possible lengths repeating a [Domain].
    30  //
    31  // Or top or bottom:
    32  //
    33  //   - [Top] - Represents all possible values of all kinds.
    34  //
    35  //   - nil - Represents no values.
    36  //
    37  // Or a variable:
    38  //
    39  //   - [Var] - A value captured in the environment.
    40  type Domain interface {
    41  	Exact() bool
    42  
    43  	// decode stores this value in a Go value. If this value is not exact, this
    44  	// returns a potentially wrapped *inexactError.
    45  	decode(reflect.Value) error
    46  }
    47  
    48  type inexactError struct {
    49  	valueType string
    50  	goType    string
    51  }
    52  
    53  func (e *inexactError) Error() string {
    54  	return fmt.Sprintf("cannot store inexact %s value in %s", e.valueType, e.goType)
    55  }
    56  
    57  type decodeError struct {
    58  	path string
    59  	err  error
    60  }
    61  
    62  func newDecodeError(path string, err error) *decodeError {
    63  	if err, ok := err.(*decodeError); ok {
    64  		return &decodeError{path: path + "." + err.path, err: err.err}
    65  	}
    66  	return &decodeError{path: path, err: err}
    67  }
    68  
    69  func (e *decodeError) Unwrap() error {
    70  	return e.err
    71  }
    72  
    73  func (e *decodeError) Error() string {
    74  	return fmt.Sprintf("%s: %s", e.path, e.err)
    75  }
    76  
    77  // Top represents all possible values of all possible types.
    78  type Top struct{}
    79  
    80  func (t Top) Exact() bool { return false }
    81  
    82  func (t Top) decode(rv reflect.Value) error {
    83  	// We can decode Top into a pointer-typed value as nil.
    84  	if rv.Kind() != reflect.Pointer {
    85  		return &inexactError{"top", rv.Type().String()}
    86  	}
    87  	rv.SetZero()
    88  	return nil
    89  }
    90  
    91  // A Def is a mapping from field names to [Value]s. Any fields not explicitly
    92  // listed have [Value] [Top].
    93  type Def struct {
    94  	fields map[string]*Value
    95  }
    96  
    97  // NewDef creates a new [Def].
    98  //
    99  // The fields and values slices must have the same length.
   100  func NewDef(fields []string, values []*Value) Def {
   101  	if len(fields) != len(values) {
   102  		panic("fields and values must have the same length")
   103  	}
   104  	m := make(map[string]*Value, len(fields))
   105  	for i := range fields {
   106  		if _, ok := m[fields[i]]; ok {
   107  			panic(fmt.Sprintf("duplicate field %q", fields[i]))
   108  		}
   109  		m[fields[i]] = values[i]
   110  	}
   111  	return Def{m}
   112  }
   113  
   114  // Exact returns true if all field Values are exact.
   115  func (d Def) Exact() bool {
   116  	for _, v := range d.fields {
   117  		if !v.Exact() {
   118  			return false
   119  		}
   120  	}
   121  	return true
   122  }
   123  
   124  func (d Def) decode(rv reflect.Value) error {
   125  	rv, err := preDecode(rv, reflect.Struct, "Def")
   126  	if err != nil {
   127  		return err
   128  	}
   129  	var lowered map[string]string // Lower case -> canonical for d.fields.
   130  	rt := rv.Type()
   131  	for fi := range rv.NumField() {
   132  		fType := rt.Field(fi)
   133  		if fType.PkgPath != "" {
   134  			continue
   135  		}
   136  		v := d.fields[fType.Name]
   137  		if v == nil {
   138  			v = topValue
   139  
   140  			// Try a case-insensitive match
   141  			canon, ok := d.fields[strings.ToLower(fType.Name)]
   142  			if ok {
   143  				v = canon
   144  			} else {
   145  				if lowered == nil {
   146  					lowered = make(map[string]string, len(d.fields))
   147  					for k := range d.fields {
   148  						l := strings.ToLower(k)
   149  						if k != l {
   150  							lowered[l] = k
   151  						}
   152  					}
   153  				}
   154  				canon, ok := lowered[strings.ToLower(fType.Name)]
   155  				if ok {
   156  					v = d.fields[canon]
   157  				}
   158  			}
   159  		}
   160  		if err := v.Domain.decode(rv.Field(fi)); err != nil {
   161  			return newDecodeError(fType.Name, err)
   162  		}
   163  	}
   164  	return nil
   165  }
   166  
   167  func (d Def) keys() []string {
   168  	return slices.Sorted(maps.Keys(d.fields))
   169  }
   170  
   171  func (d Def) All() iter.Seq2[string, *Value] {
   172  	// TODO: We call All fairly often. It's probably bad to sort this every
   173  	// time.
   174  	keys := slices.Sorted(maps.Keys(d.fields))
   175  	return func(yield func(string, *Value) bool) {
   176  		for _, k := range keys {
   177  			if !yield(k, d.fields[k]) {
   178  				return
   179  			}
   180  		}
   181  	}
   182  }
   183  
   184  // A Tuple is a sequence of Values in one of two forms: 1. a fixed-length tuple,
   185  // where each Value can be different or 2. a "repeated tuple", which is a Value
   186  // repeated 0 or more times.
   187  type Tuple struct {
   188  	vs []*Value
   189  
   190  	// repeat, if non-nil, means this Tuple consists of an element repeated 0 or
   191  	// more times. If repeat is non-nil, vs must be nil. This is a generator
   192  	// function because we don't necessarily want *exactly* the same Value
   193  	// repeated. For example, in YAML encoding, a !sum in a repeated tuple needs
   194  	// a fresh variable in each instance.
   195  	repeat []func(nonDetEnv) (*Value, nonDetEnv)
   196  }
   197  
   198  func NewTuple(vs ...*Value) Tuple {
   199  	return Tuple{vs: vs}
   200  }
   201  
   202  func NewRepeat(gens ...func(nonDetEnv) (*Value, nonDetEnv)) Tuple {
   203  	return Tuple{repeat: gens}
   204  }
   205  
   206  func (d Tuple) Exact() bool {
   207  	if d.repeat != nil {
   208  		return false
   209  	}
   210  	for _, v := range d.vs {
   211  		if !v.Exact() {
   212  			return false
   213  		}
   214  	}
   215  	return true
   216  }
   217  
   218  func (d Tuple) decode(rv reflect.Value) error {
   219  	if d.repeat != nil {
   220  		return &inexactError{"repeated tuple", rv.Type().String()}
   221  	}
   222  	// TODO: We could also do arrays.
   223  	rv, err := preDecode(rv, reflect.Slice, "Tuple")
   224  	if err != nil {
   225  		return err
   226  	}
   227  	if rv.IsNil() || rv.Cap() < len(d.vs) {
   228  		rv.Set(reflect.MakeSlice(rv.Type(), len(d.vs), len(d.vs)))
   229  	} else {
   230  		rv.SetLen(len(d.vs))
   231  	}
   232  	for i, v := range d.vs {
   233  		if err := v.Domain.decode(rv.Index(i)); err != nil {
   234  			return newDecodeError(fmt.Sprintf("%d", i), err)
   235  		}
   236  	}
   237  	return nil
   238  }
   239  
   240  // A String represents a set of strings. It can represent the intersection of a
   241  // set of regexps, or a single exact string. In general, the domain of a String
   242  // is non-empty, but we do not attempt to prove emptiness of a regexp value.
   243  type String struct {
   244  	kind  stringKind
   245  	re    []*regexp.Regexp // Intersection of regexps
   246  	exact string
   247  }
   248  
   249  type stringKind int
   250  
   251  const (
   252  	stringRegex stringKind = iota
   253  	stringExact
   254  )
   255  
   256  func NewStringRegex(exprs ...string) (String, error) {
   257  	if len(exprs) == 0 {
   258  		exprs = []string{""}
   259  	}
   260  	v := String{kind: -1}
   261  	for _, expr := range exprs {
   262  		re, err := regexp.Compile(`\A(?:` + expr + `)\z`)
   263  		if err != nil {
   264  			return String{}, fmt.Errorf("parsing value: %s", err)
   265  		}
   266  
   267  		// An exact value narrows the whole domain to exact, so we're done, but
   268  		// should keep parsing.
   269  		if v.kind == stringExact {
   270  			continue
   271  		}
   272  
   273  		if _, complete := re.LiteralPrefix(); complete {
   274  			v = String{kind: stringExact, exact: expr}
   275  		} else {
   276  			v.kind = stringRegex
   277  			v.re = append(v.re, re)
   278  		}
   279  	}
   280  	return v, nil
   281  }
   282  
   283  func NewStringExact(s string) String {
   284  	return String{kind: stringExact, exact: s}
   285  }
   286  
   287  // Exact returns whether this Value is known to consist of a single string.
   288  func (d String) Exact() bool {
   289  	return d.kind == stringExact
   290  }
   291  
   292  func (d String) decode(rv reflect.Value) error {
   293  	if d.kind != stringExact {
   294  		return &inexactError{"regex", rv.Type().String()}
   295  	}
   296  	rv2, err := preDecode(rv, reflect.String, "String")
   297  	if err == nil {
   298  		rv2.SetString(d.exact)
   299  		return nil
   300  	}
   301  	rv2, err = preDecode(rv, reflect.Int, "String")
   302  	if err == nil {
   303  		i, err := strconv.Atoi(d.exact)
   304  		if err != nil {
   305  			return fmt.Errorf("cannot decode String into %s: %s", rv.Type(), err)
   306  		}
   307  		rv2.SetInt(int64(i))
   308  		return nil
   309  	}
   310  	return err
   311  }