1
1
package spiker
2
2
3
- import "strings"
3
+ import (
4
+ "crypto/sha1"
5
+ "strings"
6
+ "sync"
7
+ )
4
8
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
11
11
12
- stmts , err := p .Statements ()
13
- if err != nil {
14
- return
15
- }
12
+ // cachedAst cached ast node map
13
+ var cachedAst = sync.Map {}
16
14
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 )
18
18
if err != nil {
19
19
return
20
20
}
@@ -24,42 +24,60 @@ func Execute(code string) (val interface{}, err error) {
24
24
25
25
// ExecuteWithScope return the execute result with scope
26
26
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 )
33
28
if err != nil {
34
29
return
35
30
}
36
31
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 )
38
38
if err != nil {
39
39
return
40
40
}
41
41
42
- return EvaluateWithScope (ast , scope )
42
+ return FormatAst (ast )
43
43
}
44
44
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
47
57
code = padSemicolon (code )
48
58
59
+ // lexer, parser, transform
49
60
lexer := NewLexer (code )
50
61
p := Parser {Lexer : lexer }
51
62
63
+ // parse statements
52
64
stmts , err := p .Statements ()
53
65
if err != nil {
54
66
return
55
67
}
56
68
57
- ast , err := Transform (stmts )
69
+ // transform to ast nodes
70
+ ast , err = Transform (stmts )
58
71
if err != nil {
59
72
return
60
73
}
61
74
62
- return FormatAst (ast )
75
+ // cache ast nodes
76
+ if EnableAstCache {
77
+ cachedAst .Store (hashKey , ast )
78
+ }
79
+
80
+ return
63
81
}
64
82
65
83
// padding semicolon
0 commit comments