Skip to content

Commit c9abd32

Browse files
committed
support ParseAst and EnableAstCache
1 parent 3351f78 commit c9abd32

File tree

2 files changed

+55
-24
lines changed

2 files changed

+55
-24
lines changed

spiker.go

+42-24
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
package spiker
22

3-
import "strings"
3+
import (
4+
"crypto/sha1"
5+
"strings"
6+
"sync"
7+
)
48

5-
// Execute return the computed result of a string expression
6-
func Execute(code string) (val interface{}, err error) {
7-
code = padSemicolon(code)
8-
9-
lexer := NewLexer(code)
10-
p := Parser{Lexer: lexer}
9+
// EnableAstCache enable ast cache, default is false
10+
var EnableAstCache = false
1111

12-
stmts, err := p.Statements()
13-
if err != nil {
14-
return
15-
}
12+
// cachedAst cached ast node map
13+
var cachedAst = sync.Map{}
1614

17-
ast, err := Transform(stmts)
15+
// Execute return the computed result of a string expression
16+
func Execute(code string) (val interface{}, err error) {
17+
ast, err := ParseAst(code)
1818
if err != nil {
1919
return
2020
}
@@ -24,42 +24,60 @@ func Execute(code string) (val interface{}, err error) {
2424

2525
// ExecuteWithScope return the execute result with scope
2626
func ExecuteWithScope(code string, scope *VariableScope) (val interface{}, err error) {
27-
code = padSemicolon(code)
28-
29-
lexer := NewLexer(code)
30-
p := Parser{Lexer: lexer}
31-
32-
stmts, err := p.Statements()
27+
ast, err := ParseAst(code)
3328
if err != nil {
3429
return
3530
}
3631

37-
ast, err := Transform(stmts)
32+
return EvaluateWithScope(ast, scope)
33+
}
34+
35+
// Format return the formatted expression
36+
func Format(code string) (s string, err error) {
37+
ast, err := ParseAst(code)
3838
if err != nil {
3939
return
4040
}
4141

42-
return EvaluateWithScope(ast, scope)
42+
return FormatAst(ast)
4343
}
4444

45-
// Format return the formatted expression
46-
func Format(code string) (s string, err error) {
45+
// ParseAst lexer, statements, transform, and return the ast nodes
46+
// if EnableAstCache is true, it will cache the ast nodes
47+
func ParseAst(code string) (ast []AstNode, err error) {
48+
// get cached ast nodes
49+
hashKey := sha1.Sum([]byte(code))
50+
if EnableAstCache {
51+
if ast, ok := cachedAst.Load(hashKey); ok {
52+
return ast.([]AstNode), nil
53+
}
54+
}
55+
56+
// padding semicolon
4757
code = padSemicolon(code)
4858

59+
// lexer, parser, transform
4960
lexer := NewLexer(code)
5061
p := Parser{Lexer: lexer}
5162

63+
// parse statements
5264
stmts, err := p.Statements()
5365
if err != nil {
5466
return
5567
}
5668

57-
ast, err := Transform(stmts)
69+
// transform to ast nodes
70+
ast, err = Transform(stmts)
5871
if err != nil {
5972
return
6073
}
6174

62-
return FormatAst(ast)
75+
// cache ast nodes
76+
if EnableAstCache {
77+
cachedAst.Store(hashKey, ast)
78+
}
79+
80+
return
6381
}
6482

6583
// padding semicolon

spiker_test.go

+13
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,19 @@ func BenchmarkExecute(b *testing.B) {
103103
}
104104
}
105105

106+
func BenchmarkParseAst(b *testing.B) {
107+
spiker.EnableAstCache = true // enable ast cache
108+
src := readFile("testdata/collect.src")
109+
110+
b.ResetTimer()
111+
for n := 0; n < b.N; n++ {
112+
if _, err := spiker.ParseAst(src); err != nil {
113+
b.Log(err)
114+
b.Fail()
115+
}
116+
}
117+
}
118+
106119
func TestFormat(t *testing.T) {
107120
tests := []struct {
108121
input string

0 commit comments

Comments
 (0)