Source file src/simd/_gen/unify/value.go

     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) WhyNotExact() string {
    73  	if v.Domain == nil {
    74  		return "v.Domain is nil"
    75  	}
    76  	return v.Domain.WhyNotExact()
    77  }
    78  
    79  func (v *Value) Exact() bool {
    80  	if v.Domain == nil {
    81  		return false
    82  	}
    83  	return v.Domain.Exact()
    84  }
    85  
    86  // Decode decodes v into a Go value.
    87  //
    88  // v must be exact, except that it can include Top. into must be a pointer.
    89  // [Def]s are decoded into structs. [Tuple]s are decoded into slices. [String]s
    90  // are decoded into strings or ints. Any field can itself be a pointer to one of
    91  // these types. Top can be decoded into a pointer-typed field and will set the
    92  // field to nil. Anything else will allocate a value if necessary.
    93  //
    94  // Any type may implement [Decoder], in which case its DecodeUnified method will
    95  // be called instead of using the default decoding scheme.
    96  func (v *Value) Decode(into any) error {
    97  	rv := reflect.ValueOf(into)
    98  	if rv.Kind() != reflect.Pointer {
    99  		return fmt.Errorf("cannot decode into non-pointer %T", into)
   100  	}
   101  	return decodeReflect(v, rv.Elem())
   102  }
   103  
   104  func decodeReflect(v *Value, rv reflect.Value) error {
   105  	var ptr reflect.Value
   106  	if rv.Kind() == reflect.Pointer {
   107  		if rv.IsNil() {
   108  			// Transparently allocate through pointers, *except* for Top, which
   109  			// wants to set the pointer to nil.
   110  			//
   111  			// TODO: Drop this condition if I switch to an explicit Optional[T]
   112  			// or move the Top logic into Def.
   113  			if _, ok := v.Domain.(Top); !ok {
   114  				// Allocate the value to fill in, but don't actually store it in
   115  				// the pointer until we successfully decode.
   116  				ptr = rv
   117  				rv = reflect.New(rv.Type().Elem()).Elem()
   118  			}
   119  		} else {
   120  			rv = rv.Elem()
   121  		}
   122  	}
   123  
   124  	var err error
   125  	if reflect.PointerTo(rv.Type()).Implements(decoderType) {
   126  		// Use the custom decoder.
   127  		err = rv.Addr().Interface().(Decoder).DecodeUnified(v)
   128  	} else {
   129  		err = v.Domain.decode(rv)
   130  	}
   131  	if err == nil && ptr.IsValid() {
   132  		ptr.Set(rv.Addr())
   133  	}
   134  	return err
   135  }
   136  
   137  // Decoder can be implemented by types as a custom implementation of [Decode]
   138  // for that type.
   139  type Decoder interface {
   140  	DecodeUnified(v *Value) error
   141  }
   142  
   143  var decoderType = reflect.TypeOf((*Decoder)(nil)).Elem()
   144  
   145  // Provenance iterates over all of the source Values that have contributed to
   146  // this Value.
   147  func (v *Value) Provenance() iter.Seq[*Value] {
   148  	return func(yield func(*Value) bool) {
   149  		var rec func(d *Value) bool
   150  		rec = func(d *Value) bool {
   151  			if d.pos != nil {
   152  				if !yield(d) {
   153  					return false
   154  				}
   155  			}
   156  			if d.parents != nil {
   157  				for _, p := range d.parents {
   158  					if !rec(p) {
   159  						return false
   160  					}
   161  				}
   162  			}
   163  			return true
   164  		}
   165  		rec(v)
   166  	}
   167  }
   168  

View as plain text