-
Notifications
You must be signed in to change notification settings - Fork 1.5k
oracle: Refactor oracle to be more extensible #8105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
oracle: Refactor oracle to be more extensible #8105
Conversation
✅ Deploy Preview for openpolicyagent ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
5c0c667 to
61828c6
Compare
johanfylling
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This approach makes sense to me 👍
v1/ast/oracle/find/locator.go
Outdated
| // Locator wraps functionality for finding specific AST contructs | ||
| type Locator interface { | ||
| // Applicable returns true if this handler can process the given stack | ||
| Applicable(stack []ast.Node) bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a need for this extra check if each Locator impl also goes through similar motions in Find()?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah it's almost identical now you mention it. I have removed in c7ccd66.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea was that I'd clearly define when each was applicable, and test that, but I am not sure if adds enough value. We can test the Find functions in time and that'll have the same result.
v1/ast/oracle/oracle.go
Outdated
| return &Oracle{} | ||
| manager := find.NewManager() | ||
|
|
||
| manager.Register(find.NewRefLocator()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think your refactoring actually changes this behaviour, but I find it strange that we lookup refs before vars. E.g. if a user queries the location of a var that happens to be inside a ref (except for the first ref term), then I think they'd expect to find the definition of that var, not the ref it happens to be inside.
Or am I misunderstanding this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that makes sense to me too. I had just kept the original order. The tests still seem to pass with the var locator first so I'll update it to that.
v1/ast/oracle/find/variables.go
Outdated
| } | ||
|
|
||
| func (v *VarLocator) FindVarOccurrence(stack []ast.Node, name ast.Var) *ast.Location { | ||
| for i := range stack { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also something I don't think this PR changes, but isn't this backwards? The stack starts from the outer most body, right? So if we start matching from that end, then we won't find shadowed variables in nested bodies, e.g.
p if {
x = 5 # 3. but I'll find this
every y in [1, 2] {
x := 0 # 2. which should be this
y > x # 1. I want to find the definition of this
}
x == 5
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm .. I could imagine this working if we had let the compiler run the RewriteLocalVars stage, but we stop at the SetRuleTree stage just before it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes! this was a bug, I have a fix for it in 2a989c7ca3d7d8705fa436483fa63777a1f9f5a1
with some more tests to check my thinking
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Screen.Recording.2025-12-04.at.12.41.15.mov
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a great example. 👾
v1/ast/oracle/find/some.go
Outdated
| } | ||
| } | ||
|
|
||
| if sd, ok := stack[len(stack)-1].(*ast.SomeDecl); ok { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is mutually exclusive to the check above, right? Consider adding an else, or using a type-switch instead.
|
|
||
| type SomeLocator struct { | ||
| varLocator *VarLocator | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we also let the SomeLocator be an instance of VarLocator?
type SomeLocator struct {
VarLocator
}2a989c7 to
48b9976
Compare
johanfylling
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
Oracle is going to get some updates with the upcoming string interpolation work and I'd like to make it easier to work on with tests etc. I have restructured this into a 'Manager', with a number of 'Locators' for different ast constructs. I have tried to add some basic tests for the locators but pausing here for feedback. I hope to continue to improve this as I add support for string interp. Signed-off-by: Charlie Egan <[email protected]>
Signed-off-by: Charlie Egan <[email protected]>
This was meant to be easy to test and show what each locator was for, but in the end is mostly just duplicated in Find(). Signed-off-by: Charlie Egan <[email protected]>
c7ccd66 to
f80ef7d
Compare
|
Thanks Johan |
In open-policy-agent#8105, I made some improvements I hoped would help make the oracle code easier to work on. Having spent some time trying to address a bug in the GTD of some/every vars I settled on this implementation instead. 1. Build a list of Nodes, with some special cases to include bodies of some / every. 2. Find what we are looking for, and create a target term (ref or var) 3. walk down the stack of nodes looking for the target once with a generic matcher returning matches from more specific to least. Walking into bodies where needed. 4. select and return the most specific match.
In open-policy-agent#8105, I made some improvements I hoped would help make the oracle code easier to work on. Having spent some time trying to address a bug in the GTD of some/every vars I settled on this implementation instead. 1. Build a list of Nodes, with some special cases to include bodies of some / every. 2. Find what we are looking for, and create a target term (ref or var) 3. walk down the stack of nodes looking for the target once with a generic matcher returning matches from more specific to least. Walking into bodies where needed. 4. select and return the most specific match.
In open-policy-agent#8105, I made some improvements I hoped would help make the oracle code easier to work on. Having spent some time trying to address a bug in the GTD of some/every vars I settled on this implementation instead. 1. Build a list of Nodes, with some special cases to include bodies of some / every. 2. Find what we are looking for, and create a target term (ref or var) 3. walk down the stack of nodes looking for the target once with a generic matcher returning matches from more specific to least. Walking into bodies where needed. 4. select and return the most specific match.
In open-policy-agent#8105, I made some improvements I hoped would help make the oracle code easier to work on. Having spent some time trying to address a bug in the GTD of some/every vars I settled on this implementation instead. 1. Build a list of Nodes, with some special cases to include bodies of some / every. 2. Find what we are looking for, and create a target term (ref or var) 3. walk down the stack of nodes looking for the target once with a generic matcher returning matches from more specific to least. Walking into bodies where needed. 4. select and return the most specific match.
In open-policy-agent#8105, I made some improvements I hoped would help make the oracle code easier to work on. Having spent some time trying to address a bug in the GTD of some/every vars I settled on this implementation instead. 1. Build a list of Nodes, with some special cases to include bodies of some / every. 2. Find what we are looking for, and create a target term (ref or var) 3. walk down the stack of nodes looking for the target once with a generic matcher tracking the var or ref found. 4. return the most specific ref or var. Signed-off-by: Charlie Egan <[email protected]>
In open-policy-agent#8105, I made some improvements I hoped would help make the oracle code easier to work on. Having spent some time trying to address a bug in the GTD of some/every vars I settled on this implementation instead. 1. Build a list of Nodes, with some special cases to include bodies of some / every. 2. Find what we are looking for, and create a target term (ref or var) 3. walk down the stack of nodes looking for the target once with a generic matcher tracking the var or ref found. 4. return the most specific ref or var. This was originally done to make sure we could support string interpolation, but actually that worked almost out of the box. Review the oracle tests I've added here to see the new functionality. Signed-off-by: Charlie Egan <[email protected]>
In open-policy-agent#8105, I made some improvements I hoped would help make the oracle code easier to work on. Having spent some time trying to address a bug in the GTD of some/every vars I settled on this implementation instead. 1. Build a list of Nodes, with some special cases to include bodies of some / every. 2. Find what we are looking for, and create a target term (ref or var) 3. walk down the stack of nodes looking for the target once with a generic matcher tracking the var or ref found. 4. return the most specific ref or var. This was originally done to make sure we could support string interpolation, but actually that worked almost out of the box. Review the oracle tests I've added here to see the new functionality. Signed-off-by: Charlie Egan <[email protected]>
In open-policy-agent#8105, I made some improvements I hoped would help make the oracle code easier to work on. Having spent some time trying to address a bug in the GTD of some/every vars I settled on this implementation instead. 1. Build a list of Nodes, with some special cases to include bodies of some / every. 2. Find what we are looking for, and create a target term (ref or var) 3. walk down the stack of nodes looking for the target once with a generic matcher tracking the var or ref found. 4. return the most specific ref or var. This was originally done to make sure we could support string interpolation, but actually that worked almost out of the box. Review the oracle tests I've added here to see the new functionality. Signed-off-by: Charlie Egan <[email protected]>
In open-policy-agent#8105, I made some improvements I hoped would help make the oracle code easier to work on. Having spent some time trying to address a bug in the GTD of some/every vars I settled on this implementation instead. 1. Build a list of Nodes, with some special cases to include bodies of some / every. 2. Find what we are looking for, and create a target term (ref or var) 3. walk down the stack of nodes looking for the target once with a generic matcher tracking the var or ref found. 4. return the most specific ref or var. This was originally done to make sure we could support string interpolation, but actually that worked almost out of the box. Review the oracle tests I've added here to see the new functionality. Signed-off-by: Charlie Egan <[email protected]>
In #8105, I made some improvements I hoped would help make the oracle code easier to work on. Having spent some time trying to address a bug in the GTD of some/every vars I settled on this implementation instead. 1. Build a list of Nodes, with some special cases to include bodies of some / every. 2. Find what we are looking for, and create a target term (ref or var) 3. walk down the stack of nodes looking for the target once with a generic matcher tracking the var or ref found. 4. return the most specific ref or var. This was originally done to make sure we could support string interpolation, but actually that worked almost out of the box. Review the oracle tests I've added here to see the new functionality. Signed-off-by: Charlie Egan <[email protected]>
Oracle is going to get some updates with the upcoming string interpolation work and I'd like to make it easier to work on with tests etc.
I have restructured this into a 'Manager', with a number of 'Locators' for different ast constructs. I have tried to add some basic tests for the locators but pausing here for feedback.
I hope to continue to improve this as I add support for string interp.
Ref #4733