-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Add bitwise operators after bits.
.
#2160
Add bitwise operators after bits.
.
#2160
Conversation
909cd40
to
e2a59b1
Compare
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.
Nicely done! 👏 🚀 Thanks
topdown/bits_test.go
Outdated
@@ -0,0 +1,94 @@ | |||
// Copyright 2019 The OPA Authors. All rights reserved. |
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.
[nit]
// Copyright 2019 The OPA Authors. All rights reserved. | |
// Copyright 2020 The OPA Authors. All rights reserved. |
I guess? 😉
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.
Done!
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.
Changes look good! Just a couple comments on some test improvements we could make.
docs/content/policy-reference.md
Outdated
|
||
| Built-in | Description | | ||
| --- | --- | | ||
| <span class="opa-keep-it-together">``z := bits.or(x, y)``</span> | ``z`` is the bitwise or of ``x`` and ``y`` | |
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.
It might be good to be explicit and mention that x
and y
must be integers
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.
Do the updates look okay here?
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.
Yep, perfect!
expected interface{} | ||
}{ | ||
{"basic bitwise-or", []string{`p[x] { x := bits.or(7, 9) }`}, `[15]`}, | ||
{"or with zero is value", []string{`p[x] { x := bits.or(50, 0) }`}, `[50]`}, |
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.
Please add some negative tests for the builtins with invalid types passed in both for the function signature check like passing in a string or something and then for passing in a valid ast.Number
but a float that fails to convert to an integer.
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.
Done!
rules []string | ||
expected interface{} | ||
}{ | ||
{"basic shift-left", []string{`p[x] { x := bits.lsh(1, 3) }`}, `[8]`}, |
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.
It might be worthwhile to add a test case that would cause something smaller than big.int's to overflow to ensure that we don't regress anywhere in the future by transitioning through something smaller (like golang 32 or 64 bit int) and lose bits.
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.
@patrick-east, I'm at a bit of an impasse here and could use assistance, if you have any recommendations.
I tested MaxInt32
shifted left by one (which would cause issues if we were just using int32s) and everything worked okay.
I went to try MaxInt64
using a test like the following
{
"shift of max int64 doesn't overflow",
[]string{fmt.Sprintf(`p = x { x := bits.lsh(%d, 1) }`, math.MaxInt64)},
`18446744073709551614`,
},
However, since the ast's using json.Number
under the hood (seems to just be a type definition wrapping string
), math.MaxInt64
gets stored as "9.223372037e+18"
. Then later, when I try to parse it using NumberToInt
which uses the following under-the hood
new(big.Int).SetString(string(n), 10)
big.Int
can't parse it.
Any ideas? Am I missing something?
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.
Hmmm, yea so I guess other places we always use big.Float
's which has a Parse
helper https://golang.org/pkg/math/big/#Float.Parse so it "just works". What we might need to do is something like:
- Get
ast.Number
operand (iejson.Number
) - Get
big.Float
by parsing the number - Get a
big.Int
from thebig.Float
via https://golang.org/pkg/math/big/#Float.Int and validate that the returned accuracy isExact
(otherwise we didn't get a valid int to start with).
So maybe if we update NumberToInt
to be more like:
func NumberToInt(n ast.Number) (*big.Int, error) {
f := NumberToFloat(n)
r, accuracy := f.Int(nil)
if accuracy != big.Exact {
return nil, fmt.Errorf("illegal value")
}
return r, nil
}
Does that work?
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.
@patrick-east that almost works.
The test I posted is outputting the following
Got: 18446744074000000000
Exp: 18446744073709551614
I believe that something odd is happening with big integers in general here. I totally could be wrong but I think go's JSON library is actually lossy in that it's converting big integers to exponent-notation.
For example, here's another test (just using modulus to try to recover a digit that I believe is being lost)
{
"big numbers JSON?",
[]string{fmt.Sprintf(`p = x { x := [%d %% 10, %d] }`, math.MaxInt64, math.MaxInt64)},
fmt.Sprintf("[%d, %d]", math.MaxInt64%10, math.MaxInt64),
},
It outputs a failure of
Got: [0 9.223372037e+18]
Exp:
[7 9223372036854775807]
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.
Hmm yea for sure we do lossy things when we transition between them in the builtin helpers, for example:
opa/topdown/builtins/builtins.go
Lines 154 to 157 in db922a7
// FloatToNumber converts f to a number. | |
func FloatToNumber(f *big.Float) ast.Number { | |
return ast.Number(f.String()) | |
} |
.String()
method that defaults to limit the precision to 10
in https://golang.org/pkg/math/big/#Float.String when it calls https://golang.org/pkg/math/big/#Float.Text (similar for the int's)
I think the golang JSON library just keeps numbers as strings so it might be ok if we fix how we convert them and just give longer strings.
This reminded me that we have #501 which has been open for a long time.
I guess for now maybe we just add a note to document this behavior with large numbers and add test cases for the truncated results (they'll need to be updated when #501 is addressed). I don't want to block this going in for this kind of systematic problem with large numbers in opa.
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.
@patrick-east, that sounds good. I added that test.
e2a59b1
to
7344c81
Compare
💭Makes me wonder if we could use binary/hexadecimal/octal literals... |
I think the compatibility is basically that it must be valid JSON, and AFAIK those types of numbers are not supported. You get base 10 with optional It might be another good "low hanging fruit" feature to extend Edit: Updating the language itself to recognize them might also be useful, as-is they are parse errors if you try and drop in |
Fixes open-policy-agent#1919 Signed-off-by: Michael "Gilli" Gilliland <mjg.py3@gmail.com>
7344c81
to
06540eb
Compare
Yup, that's what I had in mind. |
I'm interested in this project and thought it'd be fun to tackle a "low-hanging-fruit" issue.
Fixes #1919
Sign off in commit.