lang: funcs: Rename the lookup functions

This will make things more consistent with future use.
This commit is contained in:
James Shubin
2023-10-11 19:53:25 -04:00
parent 1dc6ebbffc
commit d1c15bd0b7
13 changed files with 78 additions and 81 deletions

View File

@@ -2,7 +2,7 @@ import "fmt"
import "sys"
$env = sys.env()
$m = maplookup($env, "GOPATH", "")
$m = map_lookup_optional($env, "GOPATH", "")
print "print0" {
msg => if sys.hasenv("GOPATH") {

View File

@@ -2,13 +2,13 @@ import "fmt"
$m = {"k1" => 42, "k2" => 13,}
$found = maplookup($m, "k1", 99)
$found = map_lookup_optional($m, "k1", 99)
print "print1" {
msg => fmt.printf("found value of: %d", $found),
}
$notfound = maplookup($m, "k3", 99)
$notfound = map_lookup_optional($m, "k3", 99)
print "print2" {
msg => fmt.printf("notfound value of: %d", $notfound),

View File

@@ -3,7 +3,7 @@ import "world"
$ns = "estate"
$exchanged = world.kvlookup($ns)
$state = maplookup($exchanged, $hostname, "default")
$state = map_lookup_optional($exchanged, $hostname, "default")
exec "exec0" {
cmd => "echo hello world && echo goodbye world 1>&2", # to stdout && stderr

View File

@@ -2,7 +2,7 @@ import "world"
$ns = "estate"
$exchanged = world.kvlookup($ns)
$state = maplookup($exchanged, $hostname, "default")
$state = map_lookup_optional($exchanged, $hostname, "default")
if $state == "one" or $state == "default" {

View File

@@ -28,26 +28,25 @@ import (
)
const (
// ListLookupFuncName is the name this function is registered as. This
// starts with an underscore so that it cannot be used from the lexer.
// XXX: change to _listlookup and add syntax in the lexer/parser
ListLookupFuncName = "listlookup"
// ListLookupDefaultFuncName is the name this function is registered as.
ListLookupDefaultFuncName = "list_lookup_default"
// arg names...
listLookupArgNameList = "list"
listLookupArgNameIndex = "index"
listLookupArgNameDefault = "default"
listLookupDefaultArgNameList = "list"
listLookupDefaultArgNameIndex = "index"
listLookupDefaultArgNameDefault = "default"
)
func init() {
Register(ListLookupFuncName, func() interfaces.Func { return &ListLookupFunc{} }) // must register the func and name
Register(ListLookupDefaultFuncName, func() interfaces.Func { return &ListLookupDefaultFunc{} }) // must register the func and name
}
var _ interfaces.PolyFunc = &ListLookupFunc{} // ensure it meets this expectation
var _ interfaces.PolyFunc = &ListLookupDefaultFunc{} // ensure it meets this expectation
// ListLookupFunc is a list index lookup function. If you provide a negative
// index, then it will return the default value you specified for this function.
type ListLookupFunc struct {
// ListLookupDefaultFunc is a list index lookup function. If you provide a
// negative index, then it will return the default value you specified for this
// function.
type ListLookupDefaultFunc struct {
Type *types.Type // Kind == List, that is used as the list we lookup in
init *interfaces.Init
@@ -58,13 +57,13 @@ type ListLookupFunc struct {
// String returns a simple name for this function. This is needed so this struct
// can satisfy the pgraph.Vertex interface.
func (obj *ListLookupFunc) String() string {
return ListLookupFuncName
func (obj *ListLookupDefaultFunc) String() string {
return ListLookupDefaultFuncName
}
// ArgGen returns the Nth arg name for this function.
func (obj *ListLookupFunc) ArgGen(index int) (string, error) {
seq := []string{listLookupArgNameList, listLookupArgNameIndex, listLookupArgNameDefault}
func (obj *ListLookupDefaultFunc) ArgGen(index int) (string, error) {
seq := []string{listLookupDefaultArgNameList, listLookupDefaultArgNameIndex, listLookupDefaultArgNameDefault}
if l := len(seq); index >= l {
return "", fmt.Errorf("index %d exceeds arg length of %d", index, l)
}
@@ -72,7 +71,7 @@ func (obj *ListLookupFunc) ArgGen(index int) (string, error) {
}
// Unify returns the list of invariants that this func produces.
func (obj *ListLookupFunc) Unify(expr interfaces.Expr) ([]interfaces.Invariant, error) {
func (obj *ListLookupDefaultFunc) Unify(expr interfaces.Expr) ([]interfaces.Invariant, error) {
var invariants []interfaces.Invariant
var invar interfaces.Invariant
@@ -346,7 +345,7 @@ func (obj *ListLookupFunc) Unify(expr interfaces.Expr) ([]interfaces.Invariant,
// 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 *ListLookupFunc) Build(typ *types.Type) (*types.Type, error) {
func (obj *ListLookupDefaultFunc) Build(typ *types.Type) (*types.Type, error) {
// typ is the KindFunc signature we're trying to build...
if typ.Kind != types.KindFunc {
return nil, fmt.Errorf("input type must be of kind func")
@@ -394,7 +393,7 @@ func (obj *ListLookupFunc) Build(typ *types.Type) (*types.Type, error) {
}
// Validate tells us if the input struct takes a valid form.
func (obj *ListLookupFunc) Validate() error {
func (obj *ListLookupDefaultFunc) Validate() error {
if obj.Type == nil { // build must be run first
return fmt.Errorf("type is still unspecified")
}
@@ -406,7 +405,7 @@ func (obj *ListLookupFunc) Validate() error {
// Info returns some static info about itself. Build must be called before this
// will return correct data.
func (obj *ListLookupFunc) Info() *interfaces.Info {
func (obj *ListLookupDefaultFunc) Info() *interfaces.Info {
var sig *types.Type
if obj.Type != nil { // don't panic if called speculatively
// TODO: can obj.Type.Key or obj.Type.Val be nil (a partial) ?
@@ -421,19 +420,19 @@ func (obj *ListLookupFunc) Info() *interfaces.Info {
}
// helper
func (obj *ListLookupFunc) sig() *types.Type {
func (obj *ListLookupDefaultFunc) sig() *types.Type {
v := obj.Type.Val.String()
return types.NewType(fmt.Sprintf("func(%s %s, %s int, %s %s) %s", listLookupArgNameList, obj.Type.String(), listLookupArgNameIndex, listLookupArgNameDefault, v, v))
return types.NewType(fmt.Sprintf("func(%s %s, %s int, %s %s) %s", listLookupDefaultArgNameList, obj.Type.String(), listLookupDefaultArgNameIndex, listLookupDefaultArgNameDefault, v, v))
}
// Init runs some startup code for this function.
func (obj *ListLookupFunc) Init(init *interfaces.Init) error {
func (obj *ListLookupDefaultFunc) Init(init *interfaces.Init) error {
obj.init = init
return nil
}
// Stream returns the changing values that this func has over time.
func (obj *ListLookupFunc) Stream(ctx context.Context) error {
func (obj *ListLookupDefaultFunc) Stream(ctx context.Context) error {
defer close(obj.init.Output) // the sender closes
for {
select {
@@ -450,9 +449,9 @@ func (obj *ListLookupFunc) Stream(ctx context.Context) error {
}
obj.last = input // store for next
l := (input.Struct()[listLookupArgNameList]).(*types.ListValue)
index := input.Struct()[listLookupArgNameIndex].Int()
def := input.Struct()[listLookupArgNameDefault]
l := (input.Struct()[listLookupDefaultArgNameList]).(*types.ListValue)
index := input.Struct()[listLookupDefaultArgNameIndex].Int()
def := input.Struct()[listLookupDefaultArgNameDefault]
// TODO: should we handle overflow by returning default?
if index > math.MaxInt { // max int size varies by arch

View File

@@ -27,25 +27,24 @@ import (
)
const (
// MapLookupFuncName is the name this function is registered as. This
// starts with an underscore so that it cannot be used from the lexer.
// XXX: change to _maplookup and add syntax in the lexer/parser
MapLookupFuncName = "maplookup"
// MapLookupDefaultFuncName is the name this function is registered as.
MapLookupDefaultFuncName = "map_lookup_default"
// arg names...
mapLookupArgNameMap = "map"
mapLookupArgNameKey = "key"
mapLookupArgNameDef = "default"
mapLookupDefaultArgNameMap = "map"
mapLookupDefaultArgNameKey = "key"
mapLookupDefaultArgNameDef = "default"
)
func init() {
Register(MapLookupFuncName, func() interfaces.Func { return &MapLookupFunc{} }) // must register the func and name
Register(MapLookupDefaultFuncName, func() interfaces.Func { return &MapLookupDefaultFunc{} }) // must register the func and name
}
var _ interfaces.PolyFunc = &MapLookupFunc{} // ensure it meets this expectation
var _ interfaces.PolyFunc = &MapLookupDefaultFunc{} // ensure it meets this expectation
// MapLookupFunc is a key map lookup function.
type MapLookupFunc struct {
// MapLookupDefaultFunc is a key map lookup function. If you provide a missing
// key, then it will return the default value you specified for this function.
type MapLookupDefaultFunc struct {
Type *types.Type // Kind == Map, that is used as the map we lookup
init *interfaces.Init
@@ -56,13 +55,13 @@ type MapLookupFunc struct {
// String returns a simple name for this function. This is needed so this struct
// can satisfy the pgraph.Vertex interface.
func (obj *MapLookupFunc) String() string {
return MapLookupFuncName
func (obj *MapLookupDefaultFunc) String() string {
return MapLookupDefaultFuncName
}
// ArgGen returns the Nth arg name for this function.
func (obj *MapLookupFunc) ArgGen(index int) (string, error) {
seq := []string{mapLookupArgNameMap, mapLookupArgNameKey, mapLookupArgNameDef}
func (obj *MapLookupDefaultFunc) ArgGen(index int) (string, error) {
seq := []string{mapLookupDefaultArgNameMap, mapLookupDefaultArgNameKey, mapLookupDefaultArgNameDef}
if l := len(seq); index >= l {
return "", fmt.Errorf("index %d exceeds arg length of %d", index, l)
}
@@ -70,7 +69,7 @@ func (obj *MapLookupFunc) ArgGen(index int) (string, error) {
}
// Unify returns the list of invariants that this func produces.
func (obj *MapLookupFunc) Unify(expr interfaces.Expr) ([]interfaces.Invariant, error) {
func (obj *MapLookupDefaultFunc) Unify(expr interfaces.Expr) ([]interfaces.Invariant, error) {
var invariants []interfaces.Invariant
var invar interfaces.Invariant
@@ -370,7 +369,7 @@ func (obj *MapLookupFunc) Unify(expr interfaces.Expr) ([]interfaces.Invariant, e
// Polymorphisms returns the list of possible function signatures available for
// this static polymorphic function. It relies on type and value hints to limit
// the number of returned possibilities.
func (obj *MapLookupFunc) Polymorphisms(partialType *types.Type, partialValues []types.Value) ([]*types.Type, error) {
func (obj *MapLookupDefaultFunc) Polymorphisms(partialType *types.Type, partialValues []types.Value) ([]*types.Type, error) {
// TODO: return `variant` as arg for now -- maybe there's a better way?
variant := []*types.Type{types.NewType("func(map variant, key variant, default variant) variant")}
@@ -435,20 +434,20 @@ func (obj *MapLookupFunc) Polymorphisms(partialType *types.Type, partialValues [
typFunc := &types.Type{
Kind: types.KindFunc, // function type
Map: make(map[string]*types.Type),
Ord: []string{mapLookupArgNameMap, mapLookupArgNameKey, mapLookupArgNameDef},
Ord: []string{mapLookupDefaultArgNameMap, mapLookupDefaultArgNameKey, mapLookupDefaultArgNameDef},
Out: nil,
}
typFunc.Map[mapLookupArgNameMap] = typ
typFunc.Map[mapLookupArgNameKey] = typ.Key
typFunc.Map[mapLookupArgNameDef] = typ.Val
typFunc.Map[mapLookupDefaultArgNameMap] = typ
typFunc.Map[mapLookupDefaultArgNameKey] = typ.Key
typFunc.Map[mapLookupDefaultArgNameDef] = typ.Val
typFunc.Out = typ.Val
// TODO: don't include partial internal func map's for now, allow in future?
if typ.Key == nil || typ.Val == nil {
typFunc.Map = make(map[string]*types.Type) // erase partial
typFunc.Map[mapLookupArgNameMap] = types.TypeVariant
typFunc.Map[mapLookupArgNameKey] = types.TypeVariant
typFunc.Map[mapLookupArgNameDef] = types.TypeVariant
typFunc.Map[mapLookupDefaultArgNameMap] = types.TypeVariant
typFunc.Map[mapLookupDefaultArgNameKey] = types.TypeVariant
typFunc.Map[mapLookupDefaultArgNameDef] = types.TypeVariant
}
if typ.Val == nil {
typFunc.Out = types.TypeVariant
@@ -469,7 +468,7 @@ func (obj *MapLookupFunc) Polymorphisms(partialType *types.Type, partialValues [
// 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 *MapLookupFunc) Build(typ *types.Type) (*types.Type, error) {
func (obj *MapLookupDefaultFunc) Build(typ *types.Type) (*types.Type, error) {
// typ is the KindFunc signature we're trying to build...
if typ.Kind != types.KindFunc {
return nil, fmt.Errorf("input type must be of kind func")
@@ -517,7 +516,7 @@ func (obj *MapLookupFunc) Build(typ *types.Type) (*types.Type, error) {
}
// Validate tells us if the input struct takes a valid form.
func (obj *MapLookupFunc) Validate() error {
func (obj *MapLookupDefaultFunc) Validate() error {
if obj.Type == nil { // build must be run first
return fmt.Errorf("type is still unspecified")
}
@@ -529,7 +528,7 @@ func (obj *MapLookupFunc) Validate() error {
// Info returns some static info about itself. Build must be called before this
// will return correct data.
func (obj *MapLookupFunc) Info() *interfaces.Info {
func (obj *MapLookupDefaultFunc) Info() *interfaces.Info {
var sig *types.Type
if obj.Type != nil { // don't panic if called speculatively
// TODO: can obj.Type.Key or obj.Type.Val be nil (a partial) ?
@@ -544,20 +543,20 @@ func (obj *MapLookupFunc) Info() *interfaces.Info {
}
// helper
func (obj *MapLookupFunc) sig() *types.Type {
func (obj *MapLookupDefaultFunc) sig() *types.Type {
k := obj.Type.Key.String()
v := obj.Type.Val.String()
return types.NewType(fmt.Sprintf("func(%s %s, %s %s, %s %s) %s", mapLookupArgNameMap, obj.Type.String(), mapLookupArgNameKey, k, mapLookupArgNameDef, v, v))
return types.NewType(fmt.Sprintf("func(%s %s, %s %s, %s %s) %s", mapLookupDefaultArgNameMap, obj.Type.String(), mapLookupDefaultArgNameKey, k, mapLookupDefaultArgNameDef, v, v))
}
// Init runs some startup code for this function.
func (obj *MapLookupFunc) Init(init *interfaces.Init) error {
func (obj *MapLookupDefaultFunc) Init(init *interfaces.Init) error {
obj.init = init
return nil
}
// Stream returns the changing values that this func has over time.
func (obj *MapLookupFunc) Stream(ctx context.Context) error {
func (obj *MapLookupDefaultFunc) Stream(ctx context.Context) error {
defer close(obj.init.Output) // the sender closes
for {
select {
@@ -574,9 +573,9 @@ func (obj *MapLookupFunc) Stream(ctx context.Context) error {
}
obj.last = input // store for next
m := (input.Struct()[mapLookupArgNameMap]).(*types.MapValue)
key := input.Struct()[mapLookupArgNameKey]
def := input.Struct()[mapLookupArgNameDef]
m := (input.Struct()[mapLookupDefaultArgNameMap]).(*types.MapValue)
key := input.Struct()[mapLookupDefaultArgNameKey]
def := input.Struct()[mapLookupDefaultArgNameDef]
var result types.Value
val, exists := m.Lookup(key)

View File

@@ -29,8 +29,7 @@ import (
const (
// StructLookupFuncName is the name this function is registered as. This
// starts with an underscore so that it cannot be used from the lexer.
// XXX: change to _structlookup and add syntax in the lexer/parser
StructLookupFuncName = "structlookup"
StructLookupFuncName = "_struct_lookup"
// arg names...
structLookupArgNameStruct = "struct"

View File

@@ -4,7 +4,7 @@ import "world"
$ns = "estate"
$exchanged = world.kvlookup($ns)
$state = maplookup($exchanged, $hostname, "default")
$state = map_lookup_optional($exchanged, $hostname, "default")
if $state == "one" or $state == "default" {

View File

@@ -18,8 +18,8 @@ $foo = iter.map([$id1, $id2,], $generate)
#test $foo[0] {}
#test $foo[1] {}
test listlookup($foo, 0, "fail") {} # TODO: add syntactic sugar for listlookup
test listlookup($foo, 1, "fail") {} # TODO: add syntactic sugar for listlookup
test list_lookup_optional($foo, 0, "fail") {} # TODO: add syntactic sugar for list_lookup_optional
test list_lookup_optional($foo, 1, "fail") {} # TODO: add syntactic sugar for list_lookup_optional
-- OUTPUT --
Vertex: test[foo]
Vertex: test[foofoo]

View File

@@ -5,10 +5,10 @@ $l2 = [$l1, ["hello", "world",],]
#test $l1[0] {}
#test $l1[1] {}
test listlookup($l1, 0, "fail") {} # TODO: add syntactic sugar for listlookup
test listlookup($l1, 2, "fail") {} # TODO: add syntactic sugar for listlookup
test listlookup($l1, 3, "pass") {} # TODO: add syntactic sugar for listlookup
test listlookup($l2, 1, ["fail",]) {} # TODO: add syntactic sugar for listlookup
test list_lookup_optional($l1, 0, "fail") {} # TODO: add syntactic sugar for list_lookup_optional
test list_lookup_optional($l1, 2, "fail") {} # TODO: add syntactic sugar for list_lookup_optional
test list_lookup_optional($l1, 3, "pass") {} # TODO: add syntactic sugar for list_lookup_optional
test list_lookup_optional($l2, 1, ["fail",]) {} # TODO: add syntactic sugar for list_lookup_optional
-- OUTPUT --
Vertex: test[a]
Vertex: test[c]

View File

@@ -1,15 +1,15 @@
-- main.mcl --
$map1 map{int: str} = {42 => "hello1",}
test maplookup($map1, 42, "not found") {}
test map_lookup_optional($map1, 42, "not found") {}
$map2 map{int: str} = {42 => "hello2",}
test maplookup($map2, 13, "world2") {}
test map_lookup_optional($map2, 13, "world2") {}
$map3 = {42 => "hello3",}
test maplookup($map3, 42, "not found") {}
test map_lookup_optional($map3, 42, "not found") {}
$map4 = {42 => "hello4",}
test maplookup($map4, 13, "world4") {}
test map_lookup_optional($map4, 13, "world4") {}
-- OUTPUT --
Vertex: test[hello1]
Vertex: test[hello3]

View File

@@ -73,6 +73,6 @@ $generate = func($idn) {
$foo = iter.map([$id1, $id2,], $generate)
#test $foo[0] {}
test listlookup($foo, 0, "fail") {} # TODO: add syntactic sugar for listlookup
test list_lookup_optional($foo, 0, "fail") {} # TODO: add syntactic sugar for list_lookup_optional
-- OUTPUT --
# err: errUnify: can't unify, invariant illogicality with equals: base kind does not match (Str != Int)

View File

@@ -15,7 +15,7 @@ $t = sys.hasenv("TEST")
$f = sys.hasenv("DOESNOTEXIST")
$env = sys.env()
$m = maplookup($env, "TEST", "321")
$m = map_lookup_optional($env, "TEST", "321")
file "${tmpdir}/environ" {
state => $const.res.file.state.exists,