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 }