lang: Add function types to the yacc type parser

Hopefully our type unification algorithm will be sufficiently good that
you never need to actually specify the function type, but it's useful
for testing and completeness.
This commit is contained in:
James Shubin
2019-06-12 19:13:53 -04:00
parent da8cb40242
commit 6643a3d937

View File

@@ -24,6 +24,7 @@ import (
"github.com/purpleidea/mgmt/lang/interfaces" "github.com/purpleidea/mgmt/lang/interfaces"
"github.com/purpleidea/mgmt/lang/types" "github.com/purpleidea/mgmt/lang/types"
"github.com/purpleidea/mgmt/util"
) )
const ( const (
@@ -1177,6 +1178,45 @@ type:
posLast(yylex, yyDollar) // our pos posLast(yylex, yyDollar) // our pos
$$.typ = types.NewType(fmt.Sprintf("%s{%s}", $1.str, strings.Join($3.strSlice, "; "))) $$.typ = types.NewType(fmt.Sprintf("%s{%s}", $1.str, strings.Join($3.strSlice, "; ")))
} }
| FUNC_IDENTIFIER OPEN_PAREN type_func_args CLOSE_PAREN type
// XXX: should we allow named args in the type signature?
// func: func() float or func(bool) str or func(a bool, bb int) float
{
posLast(yylex, yyDollar) // our pos
m := make(map[string]*types.Type)
ord := []string{}
for i, a := range $4.args {
if a.Type == nil {
// at least one is unknown, can't run SetType...
// this means there is a programming error here!
err := fmt.Errorf("type is unspecified for arg #%d", i)
// this will ultimately cause a parser error to occur...
yylex.Error(fmt.Sprintf("%s: %+v", ErrParseSetType, err))
break // safety
}
name := a.Name
if name == "" {
name = util.NumToAlpha(i) // if unspecified...
}
if util.StrInList(name, ord) {
// duplicate arg name used
err := fmt.Errorf("duplicate arg name of `%s`", name)
// this will ultimately cause a parser error to occur...
yylex.Error(fmt.Sprintf("%s: %+v", ErrParseSetType, err))
break // safety
}
m[name] = a.Type
ord = append(ord, name)
}
$$.typ = &types.Type{
Kind: types.KindFunc,
Map: m,
Ord: ord,
Out: $5.typ,
}
}
| VARIANT_IDENTIFIER | VARIANT_IDENTIFIER
{ {
posLast(yylex, yyDollar) // our pos posLast(yylex, yyDollar) // our pos
@@ -1207,6 +1247,42 @@ type_struct_field:
$$.str = fmt.Sprintf("%s %s", $1.str, $2.typ.String()) $$.str = fmt.Sprintf("%s %s", $1.str, $2.typ.String())
} }
; ;
type_func_args:
/* end of list */
{
posLast(yylex, yyDollar) // our pos
$$.args = []*Arg{}
}
| type_func_args COMMA type_func_arg
{
posLast(yylex, yyDollar) // our pos
$$.args = append($1.args, $3.arg)
}
| type_func_arg
{
posLast(yylex, yyDollar) // our pos
$$.args = append([]*Arg{}, $1.arg)
//$$.args = []*Arg{$1.arg} // TODO: is this equivalent?
}
;
type_func_arg:
// `<type>`
type
{
$$.arg = &Arg{
Type: $1.typ,
}
}
// `$x <type>`
// XXX: should we allow specifying the arg name here?
| VAR_IDENTIFIER type
{
$$.arg = &Arg{
Name: $1.str,
Type: $2.typ,
}
}
;
dotted_identifier: dotted_identifier:
IDENTIFIER IDENTIFIER
{ {