Skip to content

Commit 7772449

Browse files
committed
Add in array optimization
1 parent 36418e3 commit 7772449

File tree

3 files changed

+84
-19
lines changed

3 files changed

+84
-19
lines changed

compiler/compiler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func (c *compiler) emitPush(value interface{}) int {
7474
func (c *compiler) makeConstant(i interface{}) []byte {
7575
hashable := true
7676
switch reflect.TypeOf(i).Kind() {
77-
case reflect.Slice:
77+
case reflect.Slice, reflect.Map:
7878
hashable = false
7979
}
8080

optimizer/optimizer.go

Lines changed: 67 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,75 @@ import (
55
"math"
66
)
77

8+
type inArray struct{}
89
type fold struct {
910
applied bool
1011
}
1112
type inRange struct{}
1213
type constRange struct{}
1314

14-
func patch(node *Node, newNode Node) {
15-
newNode.SetType((*node).GetType())
16-
newNode.SetLocation((*node).GetLocation())
17-
*node = newNode
15+
func Optimize(node *Node) {
16+
Walk(node, &inArray{})
17+
limit := 1000
18+
for {
19+
fold := &fold{}
20+
Walk(node, fold)
21+
limit--
22+
if !fold.applied || limit == 0 {
23+
break
24+
}
25+
}
26+
Walk(node, &inRange{})
27+
Walk(node, &constRange{})
28+
}
29+
30+
func (*inArray) Enter(node *Node) {}
31+
func (*inArray) Exit(node *Node) {
32+
switch n := (*node).(type) {
33+
case *BinaryNode:
34+
if n.Operator == "in" || n.Operator == "not in" {
35+
if array, ok := n.Right.(*ArrayNode); ok {
36+
if len(array.Nodes) > 0 {
37+
38+
for _, a := range array.Nodes {
39+
if _, ok := a.(*IntegerNode); !ok {
40+
goto string
41+
}
42+
}
43+
{
44+
value := make(map[int]bool)
45+
for _, a := range array.Nodes {
46+
value[a.(*IntegerNode).Value] = true
47+
}
48+
patch(node, &BinaryNode{
49+
Operator: n.Operator,
50+
Left: n.Left,
51+
Right: &ConstantNode{Value: value},
52+
})
53+
}
54+
55+
string:
56+
for _, a := range array.Nodes {
57+
if _, ok := a.(*StringNode); !ok {
58+
return
59+
}
60+
}
61+
{
62+
value := make(map[string]bool)
63+
for _, a := range array.Nodes {
64+
value[a.(*StringNode).Value] = true
65+
}
66+
patch(node, &BinaryNode{
67+
Operator: n.Operator,
68+
Left: n.Left,
69+
Right: &ConstantNode{Value: value},
70+
})
71+
}
72+
73+
}
74+
}
75+
}
76+
}
1877
}
1978

2079
func (*fold) Enter(node *Node) {}
@@ -171,16 +230,8 @@ func (*constRange) Exit(node *Node) {
171230
}
172231
}
173232

174-
func Optimize(node *Node) {
175-
limit := 1000
176-
for {
177-
fold := &fold{}
178-
Walk(node, fold)
179-
limit--
180-
if !fold.applied || limit == 0 {
181-
break
182-
}
183-
}
184-
Walk(node, &inRange{})
185-
Walk(node, &constRange{})
233+
func patch(node *Node, newNode Node) {
234+
newNode.SetType((*node).GetType())
235+
newNode.SetLocation((*node).GetLocation())
236+
*node = newNode
186237
}

optimizer/optimizer_test.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,29 @@ import (
1111
)
1212

1313
func TestOptimize_constant_folding(t *testing.T) {
14-
tree, err := parser.Parse(`v in [1,2,3,4,5]`)
14+
tree, err := parser.Parse(`[1,2,3][5*5-25]`)
15+
require.NoError(t, err)
16+
17+
optimizer.Optimize(&tree.Node)
18+
19+
expected := &ast.IndexNode{
20+
Node: &ast.ConstantNode{Value: []int{1, 2, 3}},
21+
Index: &ast.IntegerNode{Value: 0},
22+
}
23+
24+
assert.Equal(t, litter.Sdump(expected), litter.Sdump(tree.Node))
25+
}
26+
27+
func TestOptimize_in_array(t *testing.T) {
28+
tree, err := parser.Parse(`v in [1,2,3]`)
1529
require.NoError(t, err)
1630

1731
optimizer.Optimize(&tree.Node)
1832

1933
expected := &ast.BinaryNode{
2034
Operator: "in",
2135
Left: &ast.IdentifierNode{Value: "v"},
22-
Right: &ast.ConstantNode{Value: []int{1, 2, 3, 4, 5}},
36+
Right: &ast.ConstantNode{Value: map[int]bool{1: true, 2: true, 3: true}},
2337
}
2438

2539
assert.Equal(t, litter.Sdump(expected), litter.Sdump(tree.Node))

0 commit comments

Comments
 (0)