diff --git a/examples/lang/env1.mcl b/examples/lang/env1.mcl index aa57c2cb..e1beafcd 100644 --- a/examples/lang/env1.mcl +++ b/examples/lang/env1.mcl @@ -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") { diff --git a/examples/lang/maplookup1.mcl b/examples/lang/maplookup1.mcl index 12f1a366..7843673e 100644 --- a/examples/lang/maplookup1.mcl +++ b/examples/lang/maplookup1.mcl @@ -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), diff --git a/examples/lang/sendrecv1.mcl b/examples/lang/sendrecv1.mcl index 076846b2..4bb29f82 100644 --- a/examples/lang/sendrecv1.mcl +++ b/examples/lang/sendrecv1.mcl @@ -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 diff --git a/examples/lang/states0.mcl b/examples/lang/states0.mcl index db856860..f7c3dc65 100644 --- a/examples/lang/states0.mcl +++ b/examples/lang/states0.mcl @@ -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" { diff --git a/lang/funcs/listlookup_func.go b/lang/funcs/list_lookup_default_func.go similarity index 88% rename from lang/funcs/listlookup_func.go rename to lang/funcs/list_lookup_default_func.go index f4066554..ca1d512a 100644 --- a/lang/funcs/listlookup_func.go +++ b/lang/funcs/list_lookup_default_func.go @@ -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 diff --git a/lang/funcs/maplookup_func.go b/lang/funcs/map_lookup_default_func.go similarity index 87% rename from lang/funcs/maplookup_func.go rename to lang/funcs/map_lookup_default_func.go index 106223bb..1848d27c 100644 --- a/lang/funcs/maplookup_func.go +++ b/lang/funcs/map_lookup_default_func.go @@ -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) diff --git a/lang/funcs/structlookup_func.go b/lang/funcs/struct_lookup_func.go similarity index 99% rename from lang/funcs/structlookup_func.go rename to lang/funcs/struct_lookup_func.go index ebed6cc4..e5a27847 100644 --- a/lang/funcs/structlookup_func.go +++ b/lang/funcs/struct_lookup_func.go @@ -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" diff --git a/lang/interpret_test/TestAstFunc1/slow_unification0.txtar b/lang/interpret_test/TestAstFunc1/slow_unification0.txtar index d13216a8..0afe342b 100644 --- a/lang/interpret_test/TestAstFunc1/slow_unification0.txtar +++ b/lang/interpret_test/TestAstFunc1/slow_unification0.txtar @@ -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" { diff --git a/lang/interpret_test/TestAstFunc2/complex-example.txtar b/lang/interpret_test/TestAstFunc2/complex-example.txtar index 197e7612..f073a967 100644 --- a/lang/interpret_test/TestAstFunc2/complex-example.txtar +++ b/lang/interpret_test/TestAstFunc2/complex-example.txtar @@ -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] diff --git a/lang/interpret_test/TestAstFunc2/listlookup.txtar b/lang/interpret_test/TestAstFunc2/listlookup.txtar index 2a258d70..ab6a92db 100644 --- a/lang/interpret_test/TestAstFunc2/listlookup.txtar +++ b/lang/interpret_test/TestAstFunc2/listlookup.txtar @@ -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] diff --git a/lang/interpret_test/TestAstFunc2/maplookup0.txtar b/lang/interpret_test/TestAstFunc2/maplookup0.txtar index d1bb0890..cfda5f69 100644 --- a/lang/interpret_test/TestAstFunc2/maplookup0.txtar +++ b/lang/interpret_test/TestAstFunc2/maplookup0.txtar @@ -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] diff --git a/lang/interpret_test/TestAstFunc2/very-complex-example.txtar b/lang/interpret_test/TestAstFunc2/very-complex-example.txtar index 94843f0a..1e60037c 100644 --- a/lang/interpret_test/TestAstFunc2/very-complex-example.txtar +++ b/lang/interpret_test/TestAstFunc2/very-complex-example.txtar @@ -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) diff --git a/test/shell/env0.mcl b/test/shell/env0.mcl index 26fec8f2..a3730087 100644 --- a/test/shell/env0.mcl +++ b/test/shell/env0.mcl @@ -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,