mirror of
https://github.com/hanzoai/expr.git
synced 2026-09-24 16:58:58 +00:00
Improve types pkg (#668)
This commit is contained in:
@@ -1074,7 +1074,7 @@ func TestCheck_types(t *testing.T) {
|
||||
env := types.Map{
|
||||
"foo": types.StrictMap{
|
||||
"bar": types.Map{
|
||||
"baz": "",
|
||||
"baz": types.String,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user