lang: Update the Build signature to return a type

This returns the type with the arg names we'll actually use. This is
helpful so we can pass values to the right places. We have named edges
so you can actually see what's going on.

Co-authored-by: Samuel Gélineau <gelisam@gmail.com>
This commit is contained in:
James Shubin
2023-08-08 21:59:42 -04:00
parent 31c7144fff
commit c06c391461
12 changed files with 283 additions and 153 deletions

View File

@@ -41,6 +41,8 @@ func init() {
Register(StructLookupFuncName, func() interfaces.Func { return &StructLookupFunc{} }) // must register the func and name
}
var _ interfaces.PolyFunc = &StructLookupFunc{} // ensure it meets this expectation
// StructLookupFunc is a struct field lookup function.
type StructLookupFunc struct {
Type *types.Type // Kind == Struct, that is used as the struct we lookup
@@ -394,33 +396,33 @@ func (obj *StructLookupFunc) Polymorphisms(partialType *types.Type, partialValue
// and must be run before Info() and any of the other Func interface methods are
// used. This function is idempotent, as long as the arg isn't changed between
// runs.
func (obj *StructLookupFunc) Build(typ *types.Type) error {
func (obj *StructLookupFunc) Build(typ *types.Type) (*types.Type, error) {
// typ is the KindFunc signature we're trying to build...
if typ.Kind != types.KindFunc {
return fmt.Errorf("input type must be of kind func")
return nil, fmt.Errorf("input type must be of kind func")
}
if len(typ.Ord) != 2 {
return fmt.Errorf("the structlookup function needs exactly two args")
return nil, fmt.Errorf("the structlookup function needs exactly two args")
}
if typ.Out == nil {
return fmt.Errorf("return type of function must be specified")
return nil, fmt.Errorf("return type of function must be specified")
}
if typ.Map == nil {
return fmt.Errorf("invalid input type")
return nil, fmt.Errorf("invalid input type")
}
tStruct, exists := typ.Map[typ.Ord[0]]
if !exists || tStruct == nil {
return fmt.Errorf("first arg must be specified")
return nil, fmt.Errorf("first arg must be specified")
}
tField, exists := typ.Map[typ.Ord[1]]
if !exists || tField == nil {
return fmt.Errorf("second arg must be specified")
return nil, fmt.Errorf("second arg must be specified")
}
if err := tField.Cmp(types.TypeStr); err != nil {
return errwrap.Wrapf(err, "field must be an str")
return nil, errwrap.Wrapf(err, "field must be an str")
}
// NOTE: We actually don't know which field this is, only its type! we
@@ -429,7 +431,8 @@ func (obj *StructLookupFunc) Build(typ *types.Type) error {
// struct.
obj.Type = tStruct // struct type
obj.Out = typ.Out // type of return value
return nil
return obj.sig(), nil
}
// Validate tells us if the input struct takes a valid form.
@@ -458,7 +461,7 @@ func (obj *StructLookupFunc) Info() *interfaces.Info {
var sig *types.Type
if obj.Type != nil { // don't panic if called speculatively
// TODO: can obj.Out be nil (a partial) ?
sig = types.NewType(fmt.Sprintf("func(%s %s, %s str) %s", structLookupArgNameStruct, obj.Type.String(), structLookupArgNameField, obj.Out.String()))
sig = obj.sig() // helper
}
return &interfaces.Info{
Pure: true,
@@ -468,6 +471,11 @@ func (obj *StructLookupFunc) Info() *interfaces.Info {
}
}
// helper
func (obj *StructLookupFunc) sig() *types.Type {
return types.NewType(fmt.Sprintf("func(%s %s, %s str) %s", structLookupArgNameStruct, obj.Type.String(), structLookupArgNameField, obj.Out.String()))
}
// Init runs some startup code for this function.
func (obj *StructLookupFunc) Init(init *interfaces.Init) error {
obj.init = init