mirror of
https://github.com/hanzoai/expr.git
synced 2026-09-24 16:58:58 +00:00
Drop types.StrictMap and add types.Extra to define additional keys
This commit is contained in:
@@ -1072,14 +1072,16 @@ func TestCheck_builtin_without_call(t *testing.T) {
|
||||
|
||||
func TestCheck_types(t *testing.T) {
|
||||
env := types.Map{
|
||||
"foo": types.StrictMap{
|
||||
"foo": types.Map{
|
||||
"bar": types.Map{
|
||||
"baz": types.String,
|
||||
"baz": types.String,
|
||||
types.Extra: types.String,
|
||||
},
|
||||
},
|
||||
"arr": types.Array(types.StrictMap{
|
||||
"arr": types.Array(types.Map{
|
||||
"value": types.String,
|
||||
}),
|
||||
types.Extra: types.Any,
|
||||
}
|
||||
|
||||
noerr := "no error"
|
||||
@@ -1102,7 +1104,8 @@ func TestCheck_types(t *testing.T) {
|
||||
tree, err := parser.Parse(test.code)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = checker.Check(tree, conf.New(env))
|
||||
config := conf.New(env)
|
||||
_, err = checker.Check(tree, config)
|
||||
if test.err == noerr {
|
||||
require.NoError(t, err)
|
||||
} else {
|
||||
|
||||
@@ -20,9 +20,6 @@ func Env(env any) Nature {
|
||||
switch env := env.(type) {
|
||||
case types.Map:
|
||||
return env.Nature()
|
||||
|
||||
case types.StrictMap:
|
||||
return env.Nature()
|
||||
}
|
||||
|
||||
v := reflect.ValueOf(env)
|
||||
@@ -53,9 +50,6 @@ func Env(env any) Nature {
|
||||
case types.Map:
|
||||
n.Fields[key.String()] = face.(types.Map).Nature()
|
||||
|
||||
case types.StrictMap:
|
||||
n.Fields[key.String()] = face.(types.StrictMap).Nature()
|
||||
|
||||
default:
|
||||
if face == nil {
|
||||
n.Fields[key.String()] = Nature{Nil: true}
|
||||
|
||||
+2
-2
@@ -2704,7 +2704,7 @@ func TestExpr_nil_op_str(t *testing.T) {
|
||||
|
||||
func TestExpr_env_types_map(t *testing.T) {
|
||||
envTypes := types.Map{
|
||||
"foo": types.StrictMap{
|
||||
"foo": types.Map{
|
||||
"bar": types.String,
|
||||
},
|
||||
}
|
||||
@@ -2725,7 +2725,7 @@ func TestExpr_env_types_map(t *testing.T) {
|
||||
|
||||
func TestExpr_env_types_map_error(t *testing.T) {
|
||||
envTypes := types.Map{
|
||||
"foo": types.StrictMap{
|
||||
"foo": types.Map{
|
||||
"bar": types.String,
|
||||
},
|
||||
}
|
||||
|
||||
+8
-45
@@ -94,16 +94,22 @@ func (r rtype) String() string {
|
||||
return r.t.String()
|
||||
}
|
||||
|
||||
// Map returns a type that represents a map of the given type.
|
||||
// The map is not strict, meaning that it can contain keys not defined in the map.
|
||||
// Map represents a map[string]any type with defined keys.
|
||||
type Map map[string]Type
|
||||
|
||||
const Extra = "[[__extra_keys__]]"
|
||||
|
||||
func (m Map) Nature() Nature {
|
||||
nt := Nature{
|
||||
Type: reflect.TypeOf(map[string]any{}),
|
||||
Fields: make(map[string]Nature, len(m)),
|
||||
Strict: true,
|
||||
}
|
||||
for k, v := range m {
|
||||
if k == Extra {
|
||||
nt.Strict = false
|
||||
continue
|
||||
}
|
||||
nt.Fields[k] = v.Nature()
|
||||
}
|
||||
return nt
|
||||
@@ -136,49 +142,6 @@ func (m Map) String() string {
|
||||
return fmt.Sprintf("Map{%s}", strings.Join(pairs, ", "))
|
||||
}
|
||||
|
||||
// StrictMap returns a type that represents a map of the given type.
|
||||
// The map is strict, meaning that it can only contain keys defined in the map.
|
||||
type StrictMap map[string]Type
|
||||
|
||||
func (m StrictMap) Nature() Nature {
|
||||
nt := Nature{
|
||||
Type: reflect.TypeOf(map[string]any{}),
|
||||
Fields: make(map[string]Nature, len(m)),
|
||||
Strict: true,
|
||||
}
|
||||
for k, v := range m {
|
||||
nt.Fields[k] = v.Nature()
|
||||
}
|
||||
return nt
|
||||
}
|
||||
|
||||
func (m StrictMap) Equal(t Type) bool {
|
||||
if t == Any {
|
||||
return true
|
||||
}
|
||||
mt, ok := t.(StrictMap)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if len(m) != len(mt) {
|
||||
return false
|
||||
}
|
||||
for k, v := range m {
|
||||
if !v.Equal(mt[k]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (m StrictMap) String() string {
|
||||
pairs := make([]string, 0, len(m))
|
||||
for k, v := range m {
|
||||
pairs = append(pairs, fmt.Sprintf("%s: %s", k, v.String()))
|
||||
}
|
||||
return fmt.Sprintf("StrictMap{%s}", strings.Join(pairs, ", "))
|
||||
}
|
||||
|
||||
// Array returns a type that represents an array of the given type.
|
||||
func Array(of Type) Type {
|
||||
return array{of}
|
||||
|
||||
+1
-7
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
func TestType_Equal(t *testing.T) {
|
||||
tests := []struct {
|
||||
index string
|
||||
index string // Index added for IDEA to show green test marker per test.
|
||||
a, b Type
|
||||
want bool
|
||||
}{
|
||||
@@ -22,15 +22,11 @@ func TestType_Equal(t *testing.T) {
|
||||
{"7", Int, Nil, false},
|
||||
{"8", Int, Array(Int), false},
|
||||
{"9", Int, Map{"foo": Int}, false},
|
||||
{"10", Int, StrictMap{"foo": Int}, false},
|
||||
{"11", Int, Array(Int), false},
|
||||
{"12", Array(Int), Array(Int), true},
|
||||
{"13", Array(Int), Array(Float), false},
|
||||
{"14", Map{"foo": Int}, Map{"foo": Int}, true},
|
||||
{"15", Map{"foo": Int}, Map{"foo": Float}, false},
|
||||
{"16", Map{"foo": Int}, StrictMap{"foo": Int}, false},
|
||||
{"17", StrictMap{"foo": Int}, StrictMap{"foo": Int}, true},
|
||||
{"18", StrictMap{"foo": Int}, StrictMap{"foo": Float}, false},
|
||||
{"19", Map{"foo": Map{"bar": Int}}, Map{"foo": Map{"bar": Int}}, true},
|
||||
{"20", Map{"foo": Map{"bar": Int}}, Map{"foo": Map{"bar": Float}}, false},
|
||||
{"21", Any, Any, true},
|
||||
@@ -38,8 +34,6 @@ func TestType_Equal(t *testing.T) {
|
||||
{"23", Int, Any, true},
|
||||
{"24", Any, Map{"foo": Int}, true},
|
||||
{"25", Map{"foo": Int}, Any, true},
|
||||
{"26", Any, StrictMap{"foo": Int}, true},
|
||||
{"27", StrictMap{"foo": Int}, Any, true},
|
||||
{"28", Any, Array(Int), true},
|
||||
{"29", Array(Int), Any, true},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user