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  }