-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
lsp/hover: Show example links (#906)
* lsp/hover: Show example links Where examples to https://docs.styra.com/opa/rego-by-example are available, then show the links to these pages. Signed-off-by: Charlie Egan <[email protected]> * Improve keyword performance Signed-off-by: Charlie Egan <[email protected]> * Remove comment Signed-off-by: Charlie Egan <[email protected]> * Tidy _determine_keywords for every Signed-off-by: Charlie Egan <[email protected]> * inst * Improve if keyword performance Results of benchmarking: old median 28.986063 old mean 99.36704471 new median 20.632625 new mean 84.75417271 new old 170.351834 165.913458 15.080667 18.174667 722.364416 14.838167 144.308166 40.304292 24.4045 22.223417 61.691458 548.937375 171.228291 349.011583 14.812834 19.470125 14.869208 18.471875 46.716167 78.956167 16.760459 15.528125 14.35275 15.014083 14.8865 35.748709 20.632625 48.546583 14.898875 25.510542 15.363084 70.541459 168.860167 17.247625 14.956 These results were tested by disabling all other keyword rule heads and measuring the total time to get the list of keywords in go. Signed-off-by: Charlie Egan <[email protected]> * Remove time stmt * Add exprs rule to ast package This is to be used when a list of expressions is needed in rules and for keyword operations. Signed-off-by: Charlie Egan <[email protected]> * Handle values in heads --------- Signed-off-by: Charlie Egan <[email protected]>
- Loading branch information
1 parent
a6e97af
commit 1efd82c
Showing
16 changed files
with
670 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
package regal.ast | ||
|
||
import rego.v1 | ||
|
||
keywords[row] contains keyword if { | ||
some idx, line in input.regal.file.lines | ||
|
||
col := indexof(line, " if ") | ||
col > 0 | ||
|
||
row := idx + 1 | ||
|
||
not row in _comment_row_index | ||
|
||
keyword := { | ||
"name": "if", | ||
"location": { | ||
"row": idx + 1, | ||
"col": col + 2, | ||
}, | ||
} | ||
} | ||
|
||
keywords[pkg.location.row] contains keyword if { | ||
pkg := input["package"] | ||
|
||
keyword := { | ||
"name": "package", | ||
"location": { | ||
"row": pkg.location.row, | ||
"col": pkg.location.col, | ||
}, | ||
} | ||
} | ||
|
||
keywords[imp.location.row] contains keyword if { | ||
some imp in input.imports | ||
|
||
keyword := { | ||
"name": "import", | ||
"location": { | ||
"row": imp.location.row, | ||
"col": imp.location.col, | ||
}, | ||
} | ||
} | ||
|
||
keywords[loc.row] contains keyword if { | ||
some rule in input.rules | ||
|
||
loc := rule.head.location | ||
|
||
col := indexof(base64.decode(loc.text), " contains ") | ||
|
||
col > 0 | ||
|
||
keyword := { | ||
"name": "contains", | ||
"location": { | ||
"row": loc.row, | ||
"col": col + 2, | ||
}, | ||
} | ||
} | ||
|
||
keywords[value.row] contains keyword if { | ||
some expr in exprs[_] | ||
|
||
walk(expr.terms, [path, value]) | ||
|
||
value.col | ||
value.row | ||
|
||
name := _keyword_b64s[value.text] | ||
|
||
parent_path := array.slice(path, 0, count(path) - 1) | ||
context := object.get(expr.terms, parent_path, {}) | ||
|
||
some keyword in _determine_keywords(context, value, name) | ||
} | ||
|
||
keywords[value.row] contains keyword if { | ||
some rule in input.rules | ||
rule.head.assign | ||
|
||
walk(rule.head.value, [path, value]) | ||
|
||
value.col | ||
value.row | ||
|
||
name := _keyword_b64s[value.text] | ||
|
||
parent_path := array.slice(path, 0, count(path) - 1) | ||
context := object.get(rule.head.value, parent_path, {}) | ||
|
||
some keyword in _determine_keywords(context, value, name) | ||
} | ||
|
||
_determine_keywords(_, value, name) := {keyword} if { | ||
name in {"in", "some"} | ||
|
||
keyword := { | ||
"name": name, | ||
"location": { | ||
"row": value.row, | ||
"col": value.col, | ||
}, | ||
} | ||
} | ||
|
||
_determine_keywords(context, value, "every") := keywords if { | ||
text := base64.decode(context.value.location.text) | ||
|
||
keywords := { | ||
{ | ||
"name": "every", | ||
"location": { | ||
"row": value.row, | ||
"col": value.col, | ||
}, | ||
}, | ||
{ | ||
"name": "in", | ||
"location": { | ||
"row": value.row, | ||
"col": (context.value.location.col + count(text)) + 1, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
_comment_row_index contains comment.Location.row if { | ||
some comment in object.get(input, "comments", []) | ||
} | ||
|
||
_keyword_b64s := { | ||
"aW4=": "in", | ||
"c29tZQ==": "some", | ||
"ZXZlcnk=": "every", | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,223 @@ | ||
package regal.ast_test | ||
|
||
import rego.v1 | ||
|
||
import data.regal.ast | ||
|
||
test_keywords_package if { | ||
policy := `package policy` | ||
|
||
kwds := ast.keywords with input as regal.parse_module("p.rego", policy) | ||
|
||
count(kwds) == 1 # lines with keywords | ||
|
||
_keyword_on_row( | ||
kwds, | ||
1, | ||
{ | ||
"name": "package", | ||
"location": {"row": 1, "col": 1}, | ||
}, | ||
) | ||
} | ||
|
||
test_keywords_import if { | ||
policy := `package policy | ||
import rego.v1` | ||
|
||
kwds := ast.keywords with input as regal.parse_module("p.rego", policy) | ||
|
||
count(kwds) == 2 # lines with keywords | ||
|
||
_keyword_on_row( | ||
kwds, | ||
3, | ||
{ | ||
"name": "import", | ||
"location": {"row": 3, "col": 1}, | ||
}, | ||
) | ||
} | ||
|
||
test_keywords_if if { | ||
policy := `package policy | ||
import rego.v1 | ||
allow if { | ||
# if things | ||
true | ||
} | ||
` | ||
|
||
kwds := ast.keywords with input as object.union( | ||
regal.parse_module("p.rego", policy), | ||
{"regal": {"file": {"lines": split(policy, "\n")}}}, | ||
) | ||
|
||
count(kwds) == 3 # lines with keywords | ||
|
||
_keyword_on_row( | ||
kwds, | ||
5, | ||
{ | ||
"name": "if", | ||
"location": {"row": 5, "col": 7}, | ||
}, | ||
) | ||
} | ||
|
||
test_keywords_if_on_another_line if { | ||
policy := `package policy | ||
import rego.v1 | ||
allow contains { | ||
"foo": true, | ||
} if { | ||
# if things | ||
true | ||
} | ||
` | ||
|
||
kwds := ast.keywords with input as object.union( | ||
regal.parse_module("p.rego", policy), | ||
{"regal": {"file": {"lines": split(policy, "\n")}}}, | ||
) | ||
|
||
count(kwds) == 4 # lines with keywords | ||
|
||
_keyword_on_row( | ||
kwds, | ||
7, | ||
{ | ||
"name": "if", | ||
"location": {"row": 7, "col": 3}, | ||
}, | ||
) | ||
} | ||
|
||
test_keywords_some_in if { | ||
policy := ast.with_rego_v1(` | ||
allow if { | ||
some e in [1,2,3] | ||
}`) | ||
|
||
kwds := ast.keywords with input as policy | ||
|
||
count(kwds) == 4 # lines with keywords | ||
|
||
_keyword_on_row( | ||
kwds, | ||
7, | ||
{"name": "some", "location": {"row": 7, "col": 2}}, | ||
) | ||
|
||
_keyword_on_row( | ||
kwds, | ||
7, | ||
{"name": "in", "location": {"row": 7, "col": 9}}, | ||
) | ||
} | ||
|
||
test_keywords_some_no_body if { | ||
policy := ast.with_rego_v1(`list := [e| | ||
some e in [1,2,3] | ||
]`) | ||
|
||
kwds := ast.keywords with input as policy | ||
|
||
count(kwds) == 3 # lines with keywords | ||
|
||
_keyword_on_row( | ||
kwds, | ||
6, | ||
{"name": "some", "location": {"row": 6, "col": 2}}, | ||
) | ||
|
||
_keyword_on_row( | ||
kwds, | ||
6, | ||
{"name": "in", "location": {"row": 6, "col": 9}}, | ||
) | ||
} | ||
|
||
test_keywords_some_in_func_arg if { | ||
policy := ast.with_rego_v1(`foo := concat(".", [part | | ||
some part in ["a","b","c"] | ||
])`) | ||
|
||
kwds := ast.keywords with input as policy | ||
|
||
count(kwds) == 3 # lines with keywords | ||
|
||
_keyword_on_row( | ||
kwds, | ||
6, | ||
{"name": "some", "location": {"row": 6, "col": 2}}, | ||
) | ||
|
||
_keyword_on_row( | ||
kwds, | ||
6, | ||
{"name": "in", "location": {"row": 6, "col": 12}}, | ||
) | ||
} | ||
|
||
test_keywords_contains if { | ||
policy := ast.with_rego_v1(` | ||
messages contains "hello" if { | ||
1 == 1 | ||
}`) | ||
|
||
kwds := ast.keywords with input as policy | ||
|
||
count(kwds) == 3 # lines with keywords | ||
|
||
_keyword_on_row( | ||
kwds, | ||
6, | ||
{"name": "contains", "location": {"row": 6, "col": 10}}, | ||
) | ||
|
||
_keyword_on_row( | ||
kwds, | ||
6, | ||
{"name": "if", "location": {"row": 6, "col": 27}}, | ||
) | ||
} | ||
|
||
test_keywords_every if { | ||
policy := ast.with_rego_v1(` | ||
allow if { | ||
every k in [1,2,3] { | ||
k == "foo" | ||
v == 1 | ||
} | ||
}`) | ||
|
||
kwds := ast.keywords with input as policy | ||
|
||
count(kwds) == 4 # lines with keywords | ||
|
||
_keyword_on_row( | ||
kwds, | ||
7, | ||
{"name": "every", "location": {"row": 7, "col": 2}}, | ||
) | ||
|
||
_keyword_on_row( | ||
kwds, | ||
7, | ||
{"name": "in", "location": {"row": 7, "col": 10}}, | ||
) | ||
} | ||
|
||
_keyword_on_row(kwds, row, keyword) if { | ||
some kwd in object.get(kwds, row, {}) | ||
|
||
kwd.name == keyword.name | ||
kwd.location.row == keyword.location.row | ||
kwd.location.col == keyword.location.col | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.