Skip to content

Commit 73cb42d

Browse files
authored
Refactor checker to use Nature (#665)
This PR introduces a new concept inside Expr's type checker - Nature. It's an abstraction other reflect.Type which carries additional information about possible type, methods and builtin function. I was able to find and fix a few bugs in type checker and optimizer. Implementation of nature concept has proven itself. As well nature will allow to bring more feature for type checker in future. Why Nature? I was looking for a name to replace Type. Type name already carries much information, as well can be confused with reflect.Type. Nature name should be understood as "nature of the node", same as "type of the node".
1 parent 7e6e6f5 commit 73cb42d

28 files changed

+1218
-901
lines changed

ast/node.go

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,21 @@ package ast
33
import (
44
"reflect"
55

6+
"github.com/expr-lang/expr/checker/nature"
67
"github.com/expr-lang/expr/file"
78
)
89

10+
var (
11+
anyType = reflect.TypeOf(new(any)).Elem()
12+
)
13+
914
// Node represents items of abstract syntax tree.
1015
type Node interface {
1116
Location() file.Location
1217
SetLocation(file.Location)
18+
Nature() nature.Nature
19+
SetNature(nature.Nature)
20+
Kind() reflect.Kind
1321
Type() reflect.Type
1422
SetType(reflect.Type)
1523
String() string
@@ -25,8 +33,8 @@ func Patch(node *Node, newNode Node) {
2533

2634
// base is a base struct for all nodes.
2735
type base struct {
28-
loc file.Location
29-
nodeType reflect.Type
36+
loc file.Location
37+
nature nature.Nature
3038
}
3139

3240
// Location returns the location of the node in the source code.
@@ -39,14 +47,36 @@ func (n *base) SetLocation(loc file.Location) {
3947
n.loc = loc
4048
}
4149

50+
// Nature returns the nature of the node.
51+
func (n *base) Nature() nature.Nature {
52+
return n.nature
53+
}
54+
55+
// SetNature sets the nature of the node.
56+
func (n *base) SetNature(nature nature.Nature) {
57+
n.nature = nature
58+
}
59+
60+
// Kind returns the kind of the node.
61+
// If the type is nil (meaning unknown) then it returns reflect.Interface.
62+
func (n *base) Kind() reflect.Kind {
63+
if n.nature.Type == nil {
64+
return reflect.Interface
65+
}
66+
return n.nature.Type.Kind()
67+
}
68+
4269
// Type returns the type of the node.
4370
func (n *base) Type() reflect.Type {
44-
return n.nodeType
71+
if n.nature.Type == nil {
72+
return anyType
73+
}
74+
return n.nature.Type
4575
}
4676

4777
// SetType sets the type of the node.
4878
func (n *base) SetType(t reflect.Type) {
49-
n.nodeType = t
79+
n.nature.Type = t
5080
}
5181

5282
// NilNode represents nil.

builtin/builtin_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ func TestBuiltin_errors(t *testing.T) {
235235
{`bitushr(-5, -2)`, "invalid operation: negative shift count -2 (type int) (1:1)"},
236236
{`now(nil)`, "invalid number of arguments (expected 0, got 1)"},
237237
{`date(nil)`, "interface {} is nil, not string (1:1)"},
238-
{`timezone(nil)`, "interface {} is nil, not string (1:1)"},
238+
{`timezone(nil)`, "cannot use nil as argument (type string) to call timezone (1:10)"},
239239
}
240240
for _, test := range errorTests {
241241
t.Run(test.input, func(t *testing.T) {

0 commit comments

Comments
 (0)