Skip to content

Commit a70bd89

Browse files
committed
Add constant folding optimization
1 parent b16885f commit a70bd89

File tree

13 files changed

+468
-391
lines changed

13 files changed

+468
-391
lines changed

ast/location.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ func (n *StringNode) GetLocation() file.Location {
5252
return n.l
5353
}
5454

55+
func (n *ConstantNode) SetLocation(l file.Location) {
56+
n.l = l
57+
}
58+
59+
func (n *ConstantNode) GetLocation() file.Location {
60+
return n.l
61+
}
62+
5563
func (n *UnaryNode) SetLocation(l file.Location) {
5664
n.l = l
5765
}

ast/node.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ type StringNode struct {
5454
Value string
5555
}
5656

57+
type ConstantNode struct {
58+
l file.Location
59+
t reflect.Type
60+
61+
Value interface{}
62+
}
63+
5764
type UnaryNode struct {
5865
l file.Location
5966
t reflect.Type

ast/type.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ func (n *StringNode) GetType() reflect.Type {
5050
return n.t
5151
}
5252

53+
func (n *ConstantNode) SetType(t reflect.Type) {
54+
n.t = t
55+
}
56+
57+
func (n *ConstantNode) GetType() reflect.Type {
58+
return n.t
59+
}
60+
5361
func (n *UnaryNode) SetType(t reflect.Type) {
5462
n.t = t
5563
}

ast/visitor.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ func (w *walker) walk(node *Node) {
3434
w.visitor.Exit(node)
3535
case *StringNode:
3636
w.visitor.Exit(node)
37+
case *ConstantNode:
38+
w.visitor.Exit(node)
3739
case *UnaryNode:
3840
w.walk(&n.Node)
3941
w.visitor.Exit(node)
@@ -53,8 +55,12 @@ func (w *walker) walk(node *Node) {
5355
w.walk(&n.Index)
5456
w.visitor.Exit(node)
5557
case *SliceNode:
56-
w.walk(&n.From)
57-
w.walk(&n.To)
58+
if n.From != nil {
59+
w.walk(&n.From)
60+
}
61+
if n.To != nil {
62+
w.walk(&n.To)
63+
}
5864
w.visitor.Exit(node)
5965
case *MethodNode:
6066
w.walk(&n.Node)

cmd/exe/debugger.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"fmt"
55
"github.com/antonmedv/expr/compiler"
6+
"github.com/antonmedv/expr/optimizer"
67
"github.com/antonmedv/expr/parser"
78
. "github.com/antonmedv/expr/vm"
89
"github.com/gdamore/tcell"
@@ -18,6 +19,10 @@ func debugger() {
1819
tree, err := parser.Parse(input())
1920
check(err)
2021

22+
if opt {
23+
optimizer.Optimize(&tree.Node)
24+
}
25+
2126
program, err := compiler.Compile(tree, nil)
2227
check(err)
2328

cmd/exe/main.go

Lines changed: 14 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ import (
44
"bufio"
55
"flag"
66
"fmt"
7+
"github.com/antonmedv/expr"
78
"github.com/antonmedv/expr/checker"
89
"github.com/antonmedv/expr/compiler"
10+
"github.com/antonmedv/expr/optimizer"
911
"github.com/antonmedv/expr/parser"
10-
"github.com/antonmedv/expr/vm"
1112
"github.com/sanity-io/litter"
1213
"io/ioutil"
1314
"os"
@@ -20,6 +21,7 @@ var (
2021
ast bool
2122
dot bool
2223
repl bool
24+
opt bool
2325
)
2426

2527
func init() {
@@ -29,6 +31,7 @@ func init() {
2931
flag.BoolVar(&ast, "ast", false, "print ast")
3032
flag.BoolVar(&dot, "dot", false, "dot format")
3133
flag.BoolVar(&repl, "repl", false, "start repl")
34+
flag.BoolVar(&opt, "opt", true, "do optimization")
3235
}
3336

3437
func main() {
@@ -82,6 +85,10 @@ func printAst() {
8285
return
8386
}
8487

88+
if opt {
89+
optimizer.Optimize(&tree.Node)
90+
}
91+
8592
dotAst(tree.Node)
8693
}
8794

@@ -92,23 +99,18 @@ func printDisassemble() {
9299
_, err = checker.Check(tree, nil)
93100
check(err)
94101

102+
if opt {
103+
optimizer.Optimize(&tree.Node)
104+
}
105+
95106
program, err := compiler.Compile(tree, nil)
96107
check(err)
97108

98109
_, _ = fmt.Fprintf(os.Stdout, program.Disassemble())
99110
}
100111

101112
func runProgram() {
102-
tree, err := parser.Parse(input())
103-
check(err)
104-
105-
_, err = checker.Check(tree, nil)
106-
check(err)
107-
108-
program, err := compiler.Compile(tree, nil)
109-
check(err)
110-
111-
out, err := vm.Run(program, nil)
113+
out, err := expr.Eval(input(), nil)
112114
check(err)
113115

114116
litter.Dump(out)
@@ -118,35 +120,9 @@ func startRepl() {
118120
scanner := bufio.NewScanner(os.Stdin)
119121
fmt.Print("> ")
120122

121-
var (
122-
err error
123-
tree *parser.Tree
124-
program *vm.Program
125-
out interface{}
126-
)
127-
128123
for scanner.Scan() {
129124
line := scanner.Text()
130-
131-
tree, err = parser.Parse(line)
132-
if err != nil {
133-
fmt.Printf("%v\n", err)
134-
goto prompt
135-
}
136-
137-
_, err = checker.Check(tree, nil)
138-
if err != nil {
139-
fmt.Printf("%v\n", err)
140-
goto prompt
141-
}
142-
143-
program, err = compiler.Compile(tree, nil)
144-
if err != nil {
145-
fmt.Printf("%v\n", err)
146-
goto prompt
147-
}
148-
149-
out, err = vm.Run(program, nil)
125+
out, err := expr.Eval(line, nil)
150126
if err != nil {
151127
fmt.Printf("%v\n", err)
152128
goto prompt

compiler/compiler.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ func (c *compiler) compile(node ast.Node) {
126126
c.BoolNode(n)
127127
case *ast.StringNode:
128128
c.StringNode(n)
129+
case *ast.ConstantNode:
130+
c.ConstantNode(n)
129131
case *ast.UnaryNode:
130132
c.UnaryNode(n)
131133
case *ast.BinaryNode:
@@ -228,6 +230,10 @@ func (c *compiler) StringNode(node *ast.StringNode) {
228230
c.emitPush(node.Value)
229231
}
230232

233+
func (c *compiler) ConstantNode(node *ast.ConstantNode) {
234+
c.emitPush(node.Value)
235+
}
236+
231237
func (c *compiler) UnaryNode(node *ast.UnaryNode) {
232238
c.compile(node.Node)
233239

expr.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"github.com/antonmedv/expr/checker"
55
"github.com/antonmedv/expr/compiler"
66
"github.com/antonmedv/expr/internal/conf"
7+
"github.com/antonmedv/expr/optimizer"
78
"github.com/antonmedv/expr/parser"
89
"github.com/antonmedv/expr/vm"
910
"reflect"
@@ -70,6 +71,13 @@ func AsFloat64() conf.Option {
7071
}
7172
}
7273

74+
// Optimize turns optimizations on or off.
75+
func Optimize(b bool) conf.Option {
76+
return func(c *conf.Config) {
77+
c.Optimize = b
78+
}
79+
}
80+
7381
// Compile parses and compiles given input expression to bytecode program.
7482
func Compile(input string, ops ...conf.Option) (*vm.Program, error) {
7583
config := &conf.Config{Operators: make(map[string][]string)}
@@ -95,6 +103,8 @@ func Compile(input string, ops ...conf.Option) (*vm.Program, error) {
95103
checker.PatchOperators(tree, config)
96104
}
97105

106+
optimizer.Optimize(&tree.Node)
107+
98108
program, err := compiler.Compile(tree, config)
99109
if err != nil {
100110
return nil, err

0 commit comments

Comments
 (0)