forked from aquasecurity/trivy-iac
-
Notifications
You must be signed in to change notification settings - Fork 0
/
node.go
123 lines (106 loc) · 3.13 KB
/
node.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package expressions
import (
"github.com/nordcloud/trivy-iac/pkg/scanners/azure/functions"
)
type Node interface {
Evaluate(deploymentProvider functions.DeploymentData) interface{}
Evaluate1(generalFuncs map[string]func(...interface{}) interface{}) interface{}
}
type expressionValue struct {
val interface{}
}
func (e expressionValue) Evaluate(deploymentProvider functions.DeploymentData) interface{} {
if f, ok := e.val.(expression); ok {
return f.Evaluate(deploymentProvider)
}
return e.val
}
func (e expressionValue) Evaluate1(generalFuncs map[string]func(...interface{}) interface{}) interface{} {
if f, ok := e.val.(expression); ok {
return f.Evaluate1(generalFuncs)
}
return e.val
}
type expression struct {
name string
args []Node
}
func (f expression) Evaluate(deploymentProvider functions.DeploymentData) interface{} {
args := make([]interface{}, len(f.args))
for i, arg := range f.args {
args[i] = arg.Evaluate(deploymentProvider)
}
return functions.Evaluate(deploymentProvider, f.name, args...)
}
func (f expression) Evaluate1(generalFuncs map[string]func(...interface{}) interface{}) interface{} {
args := make([]interface{}, len(f.args))
for i, arg := range f.args {
args[i] = arg.Evaluate1(generalFuncs)
}
return functions.Evaluate1(generalFuncs, f.name, args...)
}
func NewExpressionTree(code string) (Node, error) {
tokens, err := lex(code)
if err != nil {
return nil, err
}
// create a walker for the nodes
tw := newTokenWalker(tokens)
// generate the root function
return newFunctionNode(tw), nil
}
func newFunctionNode(tw *tokenWalker) Node {
funcNode := &expression{
name: tw.pop().Data.(string),
}
tokenCloseParenCount := 0
tokenOpenBracketCount := 0
for tw.hasNext() {
token := tw.pop()
if token == nil {
break
}
switch token.Type {
case TokenCloseParen:
if funcNode.name != "parameters" && funcNode.name != "variables" {
return funcNode
} else if tokenCloseParenCount == 1 {
tw.unPop()
return funcNode
}
tokenCloseParenCount++
case TokenComma:
if funcNode.name == "parameters" || funcNode.name == "variables" {
return funcNode
}
case TokenName:
if tw.peek().Type == TokenOpenParen {
// this is a function, unwind 1
tw.unPop()
funcNode.args = append(funcNode.args, newFunctionNode(tw))
} else {
funcNode.args = append(funcNode.args, expressionValue{token.Data})
}
case TokenLiteralString, TokenLiteralInteger, TokenLiteralFloat:
funcNode.args = append(funcNode.args, expressionValue{token.Data})
case TokenCloseBracket:
if funcNode.name == "parameters" || funcNode.name == "variables" {
if tokenOpenBracketCount == 0 {
tw.unPop()
return funcNode
}
funcNode.args = append(funcNode.args, expressionValue{token.Data})
}
case TokenOpenBracket:
if funcNode.name == "parameters" || funcNode.name == "variables" {
funcNode.args = append(funcNode.args, expressionValue{token.Data})
tokenOpenBracketCount++
}
case TokenDot:
if funcNode.name == "parameters" || funcNode.name == "variables" {
funcNode.args = append(funcNode.args, expressionValue{token.Data})
}
}
}
return funcNode
}