golang.org/x/arch@v0.17.0/internal/unify/value.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 "reflect" 11 ) 12 13 // A Value represents a structured, non-deterministic value consisting of 14 // strings, tuples of Values, and string-keyed maps of Values. A 15 // non-deterministic Value will also contain variables, which are resolved via 16 // an environment as part of a [Closure]. 17 // 18 // For debugging, a Value can also track the source position it was read from in 19 // an input file, and its provenance from other Values. 20 type Value struct { 21 Domain Domain 22 23 // A Value has either a pos or parents (or neither). 24 pos *Pos 25 parents *[2]*Value 26 } 27 28 var ( 29 topValue = &Value{Domain: Top{}} 30 bottomValue = &Value{Domain: nil} 31 ) 32 33 // NewValue returns a new [Value] with the given domain and no position 34 // information. 35 func NewValue(d Domain) *Value { 36 return &Value{Domain: d} 37 } 38 39 // NewValuePos returns a new [Value] with the given domain at position p. 40 func NewValuePos(d Domain, p Pos) *Value { 41 return &Value{Domain: d, pos: &p} 42 } 43 44 // newValueFrom returns a new [Value] with the given domain that copies the 45 // position information of p. 46 func newValueFrom(d Domain, p *Value) *Value { 47 return &Value{Domain: d, pos: p.pos, parents: p.parents} 48 } 49 50 func unified(d Domain, p1, p2 *Value) *Value { 51 return &Value{Domain: d, parents: &[2]*Value{p1, p2}} 52 } 53 54 func (v *Value) Pos() Pos { 55 if v.pos == nil { 56 return Pos{} 57 } 58 return *v.pos 59 } 60 61 func (v *Value) PosString() string { 62 var b []byte 63 for root := range v.Provenance() { 64 if len(b) > 0 { 65 b = append(b, ' ') 66 } 67 b, _ = root.pos.AppendText(b) 68 } 69 return string(b) 70 } 71 72 func (v *Value) Exact() bool { 73 if v.Domain == nil { 74 return false 75 } 76 return v.Domain.Exact() 77 } 78 79 // Decode decodes v into a Go value. 80 // 81 // v must be exact, except that it can include Top. into must be a pointer. 82 // [Def]s are decoded into structs. [Tuple]s are decoded into slices. [String]s 83 // are decoded into strings or ints. Any field can itself be a pointer to one of 84 // these types. Top can be decoded into a pointer-typed field and will set the 85 // field to nil. Anything else will allocate a value if necessary. 86 func (v *Value) Decode(into any) error { 87 rv := reflect.ValueOf(into) 88 if rv.Kind() != reflect.Pointer { 89 return fmt.Errorf("cannot decode into non-pointer %T", into) 90 } 91 return v.Domain.decode(rv) 92 } 93 94 func preDecode(rv reflect.Value, kind reflect.Kind, name string) (reflect.Value, error) { 95 if rv.Kind() == kind { 96 return rv, nil 97 } 98 if rv.Kind() == reflect.Pointer && rv.Type().Elem().Kind() == kind { 99 if rv.IsNil() { 100 rv.Set(reflect.New(rv.Type().Elem())) 101 } 102 return rv.Elem(), nil 103 } 104 return reflect.Value{}, fmt.Errorf("cannot decode %s into %s", name, rv.Type()) 105 } 106 107 // Provenance iterates over all of the source Values that have contributed to 108 // this Value. 109 func (v *Value) Provenance() iter.Seq[*Value] { 110 return func(yield func(*Value) bool) { 111 var rec func(d *Value) bool 112 rec = func(d *Value) bool { 113 if d.pos != nil { 114 if !yield(d) { 115 return false 116 } 117 } 118 if d.parents != nil { 119 for _, p := range d.parents { 120 if !rec(p) { 121 return false 122 } 123 } 124 } 125 return true 126 } 127 rec(v) 128 } 129 }