Source file src/simd/archsimd/_gen/unify/reflect.go

     1  // Copyright 2026 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  	"reflect"
    10  	"regexp"
    11  	"strconv"
    12  	"strings"
    13  	"sync"
    14  	"unicode"
    15  )
    16  
    17  // Decode decodes v into a Go value.
    18  //
    19  // v must be exact, except that it can include Top. into must be a pointer.
    20  // [Def]s are decoded into structs. [Tuple]s are decoded into slices. [String]s
    21  // are decoded into strings or ints. Any field can itself be a pointer to one of
    22  // these types. Top can be decoded into a pointer-typed field and will set the
    23  // field to nil. Anything else will allocate a value if necessary.
    24  //
    25  // Any type may implement [DecoderEncoder], in which case its DecodeUnified
    26  // method will be called instead of using the default decoding scheme.
    27  func (v *Value) Decode(into any) error {
    28  	rv := reflect.ValueOf(into)
    29  	if rv.Kind() != reflect.Pointer {
    30  		return fmt.Errorf("cannot decode into non-pointer %T", into)
    31  	}
    32  	return decodeReflect(v, rv.Elem())
    33  }
    34  
    35  // Encode constructs a Value from a Go value. It is the inverse of
    36  // [Value.Decode].
    37  //
    38  // If a struct has an "Encode<Field>" field, it will be used for encoding the
    39  // field named by <Field>, overriding the default field. This behavior is useful
    40  // when a single type is used as an input and an output from unification, but
    41  // the input and output have different requirements (e.g., optionality or
    42  // strings vs regexps).
    43  func Encode(gv any) *Value {
    44  	rv := reflect.ValueOf(gv)
    45  	return encodeReflect(rv)
    46  }
    47  
    48  // DecoderEncoder can be implemented by types as a custom implementation of
    49  // [Decode] and [Encode] for that type. These must be inverses.
    50  type DecoderEncoder interface {
    51  	DecodeUnified(v *Value) error
    52  	EncodeUnified() *Value
    53  }
    54  
    55  var decoderEncoder = reflect.TypeFor[DecoderEncoder]()
    56  
    57  func decodeReflect(v *Value, rv reflect.Value) error {
    58  	var ptr reflect.Value
    59  	if rv.Kind() == reflect.Pointer {
    60  		if rv.IsNil() {
    61  			// Transparently allocate through pointers, *except* for Top, which
    62  			// wants to set the pointer to nil.
    63  			//
    64  			// TODO: Drop this condition if I switch to an explicit Optional[T]
    65  			// or move the Top logic into Def.
    66  			if _, ok := v.Domain.(Top); !ok {
    67  				// Allocate the value to fill in, but don't actually store it in
    68  				// the pointer until we successfully decode.
    69  				ptr = rv
    70  				rv = reflect.New(rv.Type().Elem()).Elem()
    71  			}
    72  		} else {
    73  			rv = rv.Elem()
    74  		}
    75  	}
    76  
    77  	var err error
    78  	if reflect.PointerTo(rv.Type()).Implements(decoderEncoder) {
    79  		// Use the custom decoder.
    80  		err = rv.Addr().Interface().(DecoderEncoder).DecodeUnified(v)
    81  	} else {
    82  		err = v.Domain.decode(rv)
    83  	}
    84  	if err == nil && ptr.IsValid() {
    85  		ptr.Set(rv.Addr())
    86  	}
    87  	return err
    88  }
    89  
    90  type inexactError struct {
    91  	valueType string
    92  	goType    string
    93  }
    94  
    95  func (e *inexactError) Error() string {
    96  	return fmt.Sprintf("cannot store inexact %s value in %s", e.valueType, e.goType)
    97  }
    98  
    99  type decodeError struct {
   100  	path string
   101  	err  error
   102  }
   103  
   104  func newDecodeError(path string, err error) *decodeError {
   105  	if err, ok := err.(*decodeError); ok {
   106  		return &decodeError{path: path + "." + err.path, err: err.err}
   107  	}
   108  	return &decodeError{path: path, err: err}
   109  }
   110  
   111  func (e *decodeError) Unwrap() error {
   112  	return e.err
   113  }
   114  
   115  func (e *decodeError) Error() string {
   116  	return fmt.Sprintf("%s: %s", e.path, e.err)
   117  }
   118  
   119  func (d Var) decode(rv reflect.Value) error {
   120  	return &inexactError{"var", rv.Type().String()}
   121  }
   122  
   123  func encodeReflect(rv reflect.Value) *Value {
   124  	if rv.Kind() == reflect.Pointer {
   125  		// Transparently read through non-nil pointers
   126  		if rv.IsNil() {
   127  			return topValue
   128  		}
   129  		if re, ok := rv.Interface().(*regexp.Regexp); ok {
   130  			if exact, complete := re.LiteralPrefix(); complete {
   131  				return NewValue(NewStringExact(exact))
   132  			}
   133  			return NewValue(String{kind: stringRegex, re: []*regexp.Regexp{re}})
   134  		}
   135  		rv = rv.Elem()
   136  	}
   137  
   138  	if reflect.PointerTo(rv.Type()).Implements(decoderEncoder) {
   139  		// Use the custom encoder.
   140  		return rv.Addr().Interface().(DecoderEncoder).EncodeUnified()
   141  	}
   142  
   143  	switch rv.Kind() {
   144  	default:
   145  		panic(fmt.Sprintf("cannot encode type %s to a unify.Value", rv.Type()))
   146  
   147  	case reflect.Struct:
   148  		var db DefBuilder
   149  		fieldMap := canonStructFields(rv.Type())
   150  		for defName, f := range fieldMap {
   151  			if f.encode.Index == nil {
   152  				continue
   153  			}
   154  			fVal := rv.FieldByIndex(f.encode.Index)
   155  			if fVal.Kind() == reflect.Pointer && fVal.IsNil() {
   156  				// Omit nil pointers from def (equivalent to setting them to
   157  				// "top")
   158  				continue
   159  			}
   160  			uv := encodeReflect(fVal)
   161  			db.Add(defName, uv)
   162  		}
   163  		return NewValue(db.Build())
   164  
   165  	case reflect.Slice:
   166  		uvs := make([]*Value, rv.Len())
   167  		for i := range rv.Len() {
   168  			uvs[i] = encodeReflect(rv.Index(i))
   169  		}
   170  		return NewValue(NewTuple(uvs...))
   171  
   172  	case reflect.String, reflect.Int, reflect.Bool:
   173  		return NewValue(NewStringExact(fmt.Sprint(rv)))
   174  	}
   175  }
   176  
   177  func (t Top) decode(rv reflect.Value) error {
   178  	// We can decode Top into a pointer-typed value as nil.
   179  	if rv.Kind() != reflect.Pointer {
   180  		return &inexactError{"top", rv.Type().String()}
   181  	}
   182  	rv.SetZero()
   183  	return nil
   184  }
   185  
   186  func (d Def) decode(rv reflect.Value) error {
   187  	if rv.Kind() != reflect.Struct {
   188  		return fmt.Errorf("cannot decode Def into %s", rv.Type())
   189  	}
   190  
   191  	fieldMap := canonStructFields(rv.Type())
   192  	for defName, f := range fieldMap {
   193  		if f.decode.Index == nil {
   194  			continue
   195  		}
   196  		v := d.fields[defName]
   197  		if v == nil {
   198  			v = topValue
   199  		}
   200  		if err := decodeReflect(v, rv.FieldByIndex(f.decode.Index)); err != nil {
   201  			return newDecodeError(f.decode.Name, err)
   202  		}
   203  	}
   204  	return nil
   205  }
   206  
   207  type structFieldPair struct {
   208  	decode reflect.StructField
   209  	encode reflect.StructField
   210  }
   211  
   212  var structFieldsCache sync.Map /*[reflect.Type, map[string]structFieldPair]*/
   213  
   214  // canonStructFields canonicalizes the name of all exported fields in rt from
   215  // Go-style exported names to YAML-style lower-case names. If the Go name starts
   216  // with N upper-case letters, then if N==1, it lower-cases just the first
   217  // letter; if N=len, it lower-cases the whole name; otherwise it lower-cases the
   218  // first N-1 letters.
   219  //
   220  // It produces two maps: one for encoding and one for decoding. By default,
   221  // these are the same, but if a field has form "EncodeX", then it's used for
   222  // encoding x.
   223  //
   224  // It returns a map from Def field name to a pair of decode/encode struct
   225  // fields. The mapping between Go field names and Def names is a bijection, so
   226  // it can be used for encoding and decoding.
   227  //
   228  // For example:
   229  //
   230  //	YAML field        Go field
   231  //	asmPos        <=> AsmPos
   232  //	cpuFeatures   <=> CPUFeatures
   233  //	goarch        <=> GOARCH
   234  //	bits          <=> Bits (decode) & EncodeBits (encode)
   235  //
   236  // rt must be a struct type.
   237  func canonStructFields(rt reflect.Type) map[string]structFieldPair {
   238  	type fieldMap = map[string]structFieldPair
   239  	if fields, ok := structFieldsCache.Load(rt); ok {
   240  		return fields.(fieldMap)
   241  	}
   242  
   243  	fm := make(fieldMap)
   244  	for f := range rt.Fields() {
   245  		if !f.IsExported() {
   246  			continue
   247  		}
   248  		if isEncodeOverride(f.Name) {
   249  			defName := lowerGoName(f.Name[6:])
   250  			pair := fm[defName]
   251  			pair.encode = f
   252  			fm[defName] = pair
   253  		} else {
   254  			defName := lowerGoName(f.Name)
   255  			pair := fm[defName]
   256  			if pair.decode.Index != nil {
   257  				panic(fmt.Sprintf("multiple fields in type %s map to %q", rt, defName))
   258  			}
   259  			pair.decode = f
   260  			if pair.encode.Index == nil {
   261  				pair.encode = f
   262  			}
   263  			fm[defName] = pair
   264  		}
   265  	}
   266  
   267  	res, _ := structFieldsCache.LoadOrStore(rt, fm)
   268  	return res.(fieldMap)
   269  }
   270  
   271  func isEncodeOverride(name string) bool {
   272  	return strings.HasPrefix(name, "Encode") && len(name) > 6 && unicode.IsUpper(rune(name[6]))
   273  }
   274  
   275  func lowerGoName(goName string) string {
   276  	prefixBytes := -1
   277  	prevBytes := 0
   278  	allUpper := true
   279  	for pos, ch := range goName {
   280  		if !unicode.IsUpper(ch) {
   281  			allUpper = false
   282  			prefixBytes = pos
   283  			break
   284  		}
   285  		prevBytes = pos
   286  	}
   287  	if allUpper {
   288  		// The whole name is upper-case.
   289  		return strings.ToLower(goName)
   290  	}
   291  	if prevBytes == 0 {
   292  		// The name starts with a single upper-case letter. Lower-case just it.
   293  		prevBytes = prefixBytes
   294  	}
   295  	// Lower case the first n-1 upper-case letters.
   296  	return strings.ToLower(goName[:prevBytes]) + goName[prevBytes:]
   297  }
   298  
   299  func (d Tuple) decode(rv reflect.Value) error {
   300  	if d.repeat != nil {
   301  		return &inexactError{"repeated tuple", rv.Type().String()}
   302  	}
   303  	// TODO: We could also do arrays.
   304  	if rv.Kind() != reflect.Slice {
   305  		return fmt.Errorf("cannot decode Tuple into %s", rv.Type())
   306  	}
   307  	if rv.IsNil() || rv.Cap() < len(d.vs) {
   308  		rv.Set(reflect.MakeSlice(rv.Type(), len(d.vs), len(d.vs)))
   309  	} else {
   310  		rv.SetLen(len(d.vs))
   311  	}
   312  	for i, v := range d.vs {
   313  		if err := decodeReflect(v, rv.Index(i)); err != nil {
   314  			return newDecodeError(fmt.Sprintf("%d", i), err)
   315  		}
   316  	}
   317  	return nil
   318  }
   319  
   320  func (d String) decode(rv reflect.Value) error {
   321  	if d.kind != stringExact {
   322  		return &inexactError{"regex", rv.Type().String()}
   323  	}
   324  	switch rv.Kind() {
   325  	default:
   326  		return fmt.Errorf("cannot decode String into %s", rv.Type())
   327  	case reflect.String:
   328  		rv.SetString(d.exact)
   329  	case reflect.Int:
   330  		i, err := strconv.Atoi(d.exact)
   331  		if err != nil {
   332  			return fmt.Errorf("cannot decode String into %s: %s", rv.Type(), err)
   333  		}
   334  		rv.SetInt(int64(i))
   335  	case reflect.Bool:
   336  		b, err := strconv.ParseBool(d.exact)
   337  		if err != nil {
   338  			return fmt.Errorf("cannot decode String into %s: %s", rv.Type(), err)
   339  		}
   340  		rv.SetBool(b)
   341  	}
   342  	return nil
   343  }
   344  

View as plain text