Improve types pkg (#668)

This commit is contained in:
Anton Medvedev
2024-06-05 01:14:25 +02:00
committed by GitHub
parent c953d0dde1
commit d0aa2e9136
7 changed files with 150 additions and 59 deletions
+1 -1
View File
@@ -1074,7 +1074,7 @@ func TestCheck_types(t *testing.T) {
env := types.Map{
"foo": types.StrictMap{
"bar": types.Map{
"baz": "",
"baz": types.String,
},
},
}
-47
View File
@@ -1,47 +0,0 @@
package nature
import (
"fmt"
"reflect"
"github.com/expr-lang/expr/types"
)
func Of(value any) Nature {
if value == nil {
return Nature{Nil: true}
}
v := reflect.ValueOf(value)
switch v.Kind() {
case reflect.Map:
_, strict := value.(types.StrictMap)
fields := make(map[string]Nature, v.Len())
for _, key := range v.MapKeys() {
elem := v.MapIndex(key)
if !elem.IsValid() || !elem.CanInterface() {
panic(fmt.Sprintf("invalid map value: %s", key))
}
face := elem.Interface()
switch face.(type) {
case types.Map, types.StrictMap:
fields[key.String()] = Of(face)
default:
if face == nil {
fields[key.String()] = Nature{Nil: true}
continue
}
fields[key.String()] = Nature{Type: reflect.TypeOf(face)}
}
}
return Nature{
Type: v.Type(),
Fields: fields,
Strict: strict,
}
}
return Nature{Type: v.Type()}
}
+1 -6
View File
@@ -7,7 +7,6 @@ import (
"github.com/expr-lang/expr/ast"
"github.com/expr-lang/expr/builtin"
"github.com/expr-lang/expr/checker/nature"
"github.com/expr-lang/expr/types"
"github.com/expr-lang/expr/vm/runtime"
)
@@ -53,11 +52,7 @@ func New(env any) *Config {
func (c *Config) WithEnv(env any) {
c.Strict = true
c.EnvObject = env
c.Env = nature.Of(env)
c.Env.Strict = true // To keep backward compatibility with expr.AllowUndefinedVariables()
if _, ok := env.(types.Map); ok {
c.Env.Strict = false
}
c.Env = Env(env)
}
func (c *Config) ConstExpr(name string) {
+73
View File
@@ -0,0 +1,73 @@
package conf
import (
"fmt"
"reflect"
. "github.com/expr-lang/expr/checker/nature"
"github.com/expr-lang/expr/internal/deref"
"github.com/expr-lang/expr/types"
)
func Env(env any) Nature {
if env == nil {
return Nature{
Type: reflect.TypeOf(map[string]any{}),
Strict: true,
}
}
switch env := env.(type) {
case types.Map:
return env.Nature()
case types.StrictMap:
return env.Nature()
}
v := reflect.ValueOf(env)
d := deref.Value(v)
switch d.Kind() {
case reflect.Struct:
return Nature{
Type: v.Type(),
Strict: true,
}
case reflect.Map:
n := Nature{
Type: v.Type(),
Fields: make(map[string]Nature, v.Len()),
}
for _, key := range v.MapKeys() {
elem := v.MapIndex(key)
if !elem.IsValid() || !elem.CanInterface() {
panic(fmt.Sprintf("invalid map value: %s", key))
}
face := elem.Interface()
switch face.(type) {
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}
continue
}
n.Fields[key.String()] = Nature{Type: reflect.TypeOf(face)}
}
}
return n
}
panic(fmt.Sprintf("unknown type %T", env))
}
+2 -1
View File
@@ -6,6 +6,7 @@ import (
"strings"
"github.com/expr-lang/expr/checker/nature"
"github.com/expr-lang/expr/conf"
"github.com/expr-lang/expr/internal/deref"
)
@@ -84,7 +85,7 @@ func CreateDoc(i any) *Context {
PkgPath: deref.Type(reflect.TypeOf(i)).PkgPath(),
}
for name, t := range nature.Of(i).All() {
for name, t := range conf.Env(i).All() {
if _, ok := c.Variables[Identifier(name)]; ok {
continue
}
+2 -2
View File
@@ -2705,7 +2705,7 @@ func TestExpr_nil_op_str(t *testing.T) {
func TestExpr_env_types_map(t *testing.T) {
envTypes := types.Map{
"foo": types.StrictMap{
"bar": "value",
"bar": types.String,
},
}
@@ -2726,7 +2726,7 @@ func TestExpr_env_types_map(t *testing.T) {
func TestExpr_env_types_map_error(t *testing.T) {
envTypes := types.Map{
"foo": types.StrictMap{
"bar": "value",
"bar": types.String,
},
}
+71 -2
View File
@@ -1,5 +1,74 @@
package types
type Map map[string]any
import (
"reflect"
type StrictMap map[string]any
. "github.com/expr-lang/expr/checker/nature"
)
func TypeOf(v any) Type {
return rtype{t: reflect.TypeOf(v)}
}
var (
Int = TypeOf(0)
Int8 = TypeOf(int8(0))
Int16 = TypeOf(int16(0))
Int32 = TypeOf(int32(0))
Int64 = TypeOf(int64(0))
Uint = TypeOf(uint(0))
Uint8 = TypeOf(uint8(0))
Uint16 = TypeOf(uint16(0))
Uint32 = TypeOf(uint32(0))
Uint64 = TypeOf(uint64(0))
Float = TypeOf(float32(0))
Float64 = TypeOf(float64(0))
String = TypeOf("")
Bool = TypeOf(true)
Nil = nilType{}
)
type Type interface {
Nature() Nature
}
type nilType struct{}
func (nilType) Nature() Nature {
return Nature{Nil: true}
}
type rtype struct {
t reflect.Type
}
func (r rtype) Nature() Nature {
return Nature{Type: r.t}
}
type Map map[string]Type
func (m Map) Nature() Nature {
nt := Nature{
Type: reflect.TypeOf(map[string]any{}),
Fields: make(map[string]Nature, len(m)),
}
for k, v := range m {
nt.Fields[k] = v.Nature()
}
return nt
}
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
}