-
Notifications
You must be signed in to change notification settings - Fork 0
/
ast1.rego
124 lines (92 loc) · 2.73 KB
/
ast1.rego
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
124
package regal.ast
import future.keywords.contains
import future.keywords.every
import future.keywords.if
import future.keywords.in
is_path(path, x) if path[count(path) - 1] == x
is_terms(path) if is_path(path, "terms")
is_symbols(path) if is_path(path, "symbols")
# simple assignment, i.e. `x := 100` returns `x`
# always returns a single var, but wrapped in an
# array for consistency
_find_assign_vars(path, value) := var if {
is_terms(path)
is_array(value)
value[0].type == "ref"
value[0].value[0].type == "var"
value[0].value[0].value == "assign"
value[1].type == "var"
var := [value[1]]
}
# 'destructuring' assignment, i.e. [a, b, c] := [1, 2, 3]
_find_assign_vars(path, value) := var if {
is_terms(path)
is_array(value)
value[0].type == "ref"
value[0].value[0].type == "var"
value[0].value[0].value == "assign"
value[1].type == "array"
var := [v | some v in value[1].value]
}
# var declared via `some`, i.e. `some x` or `some x, y`
_find_some_decl_vars(path, value) := var if {
is_symbols(path)
value[0].type != "call"
var := [v |
some v in value
v.type == "var"
]
}
# Note: the `some` vars check currently does not account for constructs like:
# p := x if some {"x": x} in [{"x": 12}]
# Where `x` _is_ declared inside of an object/array
# single var declared via `some in`, i.e. `some x in y`
_find_some_in_decl_vars(path, value) := var if {
is_symbols(path)
value[0].type == "call"
arr := value[0].value
count(arr) == 3
arr[1].type == "var"
var := [arr[1]]
}
# two vars declared via `some in`, i.e. `some x, y in z`
_find_some_in_decl_vars(path, value) := var if {
is_symbols(path)
value[0].type == "call"
arr := value[0].value
count(arr) == 4
var := [v |
some i in [1, 2]
v := arr[i]
v.type == "var"
]
}
# one var declared via `every`, i.e. `every x in y {}`
_find_every_vars(path, value) := var if {
is_terms(path)
value.domain
value.key == null
value.value.type == "var"
var := [value.value]
}
# two vars declared via `every`, i.e. `every x, y in y {}`
_find_every_vars(path, value) := var if {
is_terms(path)
value.domain
value.key != null
key_var := [v | v := value.key; v.type == "var"]
val_var := [v | v := value.value; v.type == "var"]
var := array.concat(key_var, val_var)
}
_find_vars(path, value) := _find_assign_vars(path, value)
_find_vars(path, value) := _find_some_decl_vars(path, value)
_find_vars(path, value) := _find_some_in_decl_vars(path, value)
_find_vars(path, value) := _find_every_vars(path, value)
# METADATA
# description: |
# traverses all nodes under provided path (using `walk`), and returns an array with
# all variables declared via assignment (:=), `some` or `every`
find_vars(path) := [var |
[_path, _value] := walk(path)
some var in _find_vars(_path, _value)
]