Skip to content

Improve types pkg #668

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion checker/checker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1074,7 +1074,7 @@ func TestCheck_types(t *testing.T) {
env := types.Map{
"foo": types.StrictMap{
"bar": types.Map{
"baz": "",
"baz": types.String,
},
},
}
Expand Down
47 changes: 0 additions & 47 deletions checker/nature/of.go

This file was deleted.

7 changes: 1 addition & 6 deletions conf/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -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) {
Expand Down
73 changes: 73 additions & 0 deletions conf/env.go
Original file line number Diff line number Diff line change
@@ -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))
}
3 changes: 2 additions & 1 deletion docgen/docgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -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
}
Expand Down
4 changes: 2 additions & 2 deletions expr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
}

Expand All @@ -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,
},
}

Expand Down
73 changes: 71 additions & 2 deletions types/types.go
Original file line number Diff line number Diff line change
@@ -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
}
Loading