Skip to content

Commit ac6e5a3

Browse files
authored
Improve types pkg (#668)
1 parent a31b1fe commit ac6e5a3

File tree

7 files changed

+150
-59
lines changed

7 files changed

+150
-59
lines changed

checker/checker_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1074,7 +1074,7 @@ func TestCheck_types(t *testing.T) {
10741074
env := types.Map{
10751075
"foo": types.StrictMap{
10761076
"bar": types.Map{
1077-
"baz": "",
1077+
"baz": types.String,
10781078
},
10791079
},
10801080
}

checker/nature/of.go

Lines changed: 0 additions & 47 deletions
This file was deleted.

conf/config.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"github.com/expr-lang/expr/ast"
88
"github.com/expr-lang/expr/builtin"
99
"github.com/expr-lang/expr/checker/nature"
10-
"github.com/expr-lang/expr/types"
1110
"github.com/expr-lang/expr/vm/runtime"
1211
)
1312

@@ -53,11 +52,7 @@ func New(env any) *Config {
5352
func (c *Config) WithEnv(env any) {
5453
c.Strict = true
5554
c.EnvObject = env
56-
c.Env = nature.Of(env)
57-
c.Env.Strict = true // To keep backward compatibility with expr.AllowUndefinedVariables()
58-
if _, ok := env.(types.Map); ok {
59-
c.Env.Strict = false
60-
}
55+
c.Env = Env(env)
6156
}
6257

6358
func (c *Config) ConstExpr(name string) {

conf/env.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package conf
2+
3+
import (
4+
"fmt"
5+
"reflect"
6+
7+
. "github.com/expr-lang/expr/checker/nature"
8+
"github.com/expr-lang/expr/internal/deref"
9+
"github.com/expr-lang/expr/types"
10+
)
11+
12+
func Env(env any) Nature {
13+
if env == nil {
14+
return Nature{
15+
Type: reflect.TypeOf(map[string]any{}),
16+
Strict: true,
17+
}
18+
}
19+
20+
switch env := env.(type) {
21+
case types.Map:
22+
return env.Nature()
23+
24+
case types.StrictMap:
25+
return env.Nature()
26+
}
27+
28+
v := reflect.ValueOf(env)
29+
d := deref.Value(v)
30+
31+
switch d.Kind() {
32+
case reflect.Struct:
33+
return Nature{
34+
Type: v.Type(),
35+
Strict: true,
36+
}
37+
38+
case reflect.Map:
39+
n := Nature{
40+
Type: v.Type(),
41+
Fields: make(map[string]Nature, v.Len()),
42+
}
43+
44+
for _, key := range v.MapKeys() {
45+
elem := v.MapIndex(key)
46+
if !elem.IsValid() || !elem.CanInterface() {
47+
panic(fmt.Sprintf("invalid map value: %s", key))
48+
}
49+
50+
face := elem.Interface()
51+
52+
switch face.(type) {
53+
case types.Map:
54+
n.Fields[key.String()] = face.(types.Map).Nature()
55+
56+
case types.StrictMap:
57+
n.Fields[key.String()] = face.(types.StrictMap).Nature()
58+
59+
default:
60+
if face == nil {
61+
n.Fields[key.String()] = Nature{Nil: true}
62+
continue
63+
}
64+
n.Fields[key.String()] = Nature{Type: reflect.TypeOf(face)}
65+
}
66+
67+
}
68+
69+
return n
70+
}
71+
72+
panic(fmt.Sprintf("unknown type %T", env))
73+
}

docgen/docgen.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"strings"
77

88
"github.com/expr-lang/expr/checker/nature"
9+
"github.com/expr-lang/expr/conf"
910
"github.com/expr-lang/expr/internal/deref"
1011
)
1112

@@ -84,7 +85,7 @@ func CreateDoc(i any) *Context {
8485
PkgPath: deref.Type(reflect.TypeOf(i)).PkgPath(),
8586
}
8687

87-
for name, t := range nature.Of(i).All() {
88+
for name, t := range conf.Env(i).All() {
8889
if _, ok := c.Variables[Identifier(name)]; ok {
8990
continue
9091
}

expr_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2705,7 +2705,7 @@ func TestExpr_nil_op_str(t *testing.T) {
27052705
func TestExpr_env_types_map(t *testing.T) {
27062706
envTypes := types.Map{
27072707
"foo": types.StrictMap{
2708-
"bar": "value",
2708+
"bar": types.String,
27092709
},
27102710
}
27112711

@@ -2726,7 +2726,7 @@ func TestExpr_env_types_map(t *testing.T) {
27262726
func TestExpr_env_types_map_error(t *testing.T) {
27272727
envTypes := types.Map{
27282728
"foo": types.StrictMap{
2729-
"bar": "value",
2729+
"bar": types.String,
27302730
},
27312731
}
27322732

types/types.go

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,74 @@
11
package types
22

3-
type Map map[string]any
3+
import (
4+
"reflect"
45

5-
type StrictMap map[string]any
6+
. "github.com/expr-lang/expr/checker/nature"
7+
)
8+
9+
func TypeOf(v any) Type {
10+
return rtype{t: reflect.TypeOf(v)}
11+
}
12+
13+
var (
14+
Int = TypeOf(0)
15+
Int8 = TypeOf(int8(0))
16+
Int16 = TypeOf(int16(0))
17+
Int32 = TypeOf(int32(0))
18+
Int64 = TypeOf(int64(0))
19+
Uint = TypeOf(uint(0))
20+
Uint8 = TypeOf(uint8(0))
21+
Uint16 = TypeOf(uint16(0))
22+
Uint32 = TypeOf(uint32(0))
23+
Uint64 = TypeOf(uint64(0))
24+
Float = TypeOf(float32(0))
25+
Float64 = TypeOf(float64(0))
26+
String = TypeOf("")
27+
Bool = TypeOf(true)
28+
Nil = nilType{}
29+
)
30+
31+
type Type interface {
32+
Nature() Nature
33+
}
34+
35+
type nilType struct{}
36+
37+
func (nilType) Nature() Nature {
38+
return Nature{Nil: true}
39+
}
40+
41+
type rtype struct {
42+
t reflect.Type
43+
}
44+
45+
func (r rtype) Nature() Nature {
46+
return Nature{Type: r.t}
47+
}
48+
49+
type Map map[string]Type
50+
51+
func (m Map) Nature() Nature {
52+
nt := Nature{
53+
Type: reflect.TypeOf(map[string]any{}),
54+
Fields: make(map[string]Nature, len(m)),
55+
}
56+
for k, v := range m {
57+
nt.Fields[k] = v.Nature()
58+
}
59+
return nt
60+
}
61+
62+
type StrictMap map[string]Type
63+
64+
func (m StrictMap) Nature() Nature {
65+
nt := Nature{
66+
Type: reflect.TypeOf(map[string]any{}),
67+
Fields: make(map[string]Nature, len(m)),
68+
Strict: true,
69+
}
70+
for k, v := range m {
71+
nt.Fields[k] = v.Nature()
72+
}
73+
return nt
74+
}

0 commit comments

Comments
 (0)