Skip to content

Add support for floats #34

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

Closed
wants to merge 23 commits into from
Closed

Add support for floats #34

wants to merge 23 commits into from

Conversation

pierd
Copy link
Contributor

@pierd pierd commented Sep 30, 2021

Addresses: #3
Spec: https://github.com/bazelbuild/starlark/blob/689f54426951638ef5b7c41a14d8fc48e65c5f77/spec.md#floating-point-numbers

Changes:

  • adds lexer support for float literal
  • adds / and /= operators for division
  • adds floats and division operators support to parser
  • adds float function
  • updates int arithmetic and comparisons to account for the other operand being float
  • implements SimpleValue for float (backed by f64)
  • adds assert_lt implementation (required for some conformance tests)
  • adds float.star from starlark-go (with some formatting for easier nonconformant line removal)

Known issues:

  • str for floats doesn't conform to the spec
  • string interpolation is not implemented for floats

@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Sep 30, 2021
Copy link
Contributor

@ndmitchell ndmitchell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code looks really good! Thanks so much for taking the time. A few minor minor comments, and then I'll start the merge. So you are aware, the merge process requires someone else at Facebook to look at this diff with our internal tooling and CI, and if they have any comments that are minor I'll make the small tweaks, but if they have larger comments I'll come back to you. I don't foresee any issues though, since I've reviewed it thoroughly, and it really is excellent.

Ok(if b { 1.0 } else { 0.0 })
} else {
Err(anyhow!(
"float() argument must be a string or a number, not '{}'",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We tend to use backticks around fragments of stuff in an error message.

"int() cannot convert non-string with explicit base '{}'",
base.to_repr()
))
} else if let Some(Num::Float(f)) = a.unpack_num() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add some more test cases above for int on float


//! Helpers for numerical values.

use super::Value;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We tend to avoid use super

use super::Value;

#[derive(Clone, Copy, Debug)]
pub enum Num {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have some comments as to the purpose of this type, since it is both subtle and fundamental to this patch. My understanding is that we introduce Num so that things that operate on any numeric types (e.g. add) can easily be written in a way that deals with both. I imagine one day we'll have a BigInt type which also lives in this region. Is that accurate?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's exactly the idea. I was even thinking if I should move the arithmetic operations from int and float to Num. It could be done in this PR or with some future work on BigInt.

@facebook-github-bot
Copy link
Contributor

@ndmitchell has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

//! The floating point number type (3.14, 4e2).

use std::cmp::Ordering;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete the blank line

Comment on lines +90 to +99
"NaN".to_string()
} else if self.is_infinite() {
if self.is_sign_positive() {
"Infinity"
} else {
"-Infinity"
}
.to_string()
} else {
self.to_string()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

every branch as a to_string, you can pull that out and do if ... else { ... }.to_string()

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The to_string in the final branch is a different to_string, since it is going from f64, not a &str. As it happens, I changed these to to_owned in the mirror I put up, since one of our linters requests that - but left the positioning the same.

Comment on lines +178 to +179
// This shouldn't happen as we handle potential NaNs above
ValueError::unsupported_with(self, "==", other)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is unreachable more appropriate here, since logically, we should never hit the case where f64's partial_cmp returns Non

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't trust floating point values enough. There are so many weird special cases, i think having a default be an anyhow error rather than an unreachable is safer.

Comment on lines +52 to +58
assert.eq(float(p53+1), p53+0) #
assert.eq(float(p53+2), p53+2)
assert.eq(float(p53+3), p53+4) #
assert.eq(float(p53+4), p53+4)
assert.eq(float(p53+5), p53+4) #
assert.eq(float(p53+6), p53+6)
assert.eq(float(p53+7), p53+8) #
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do these lines end with a trailing #, did you intend on adding some comments?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those come directly from https://github.com/google/starlark-go/blob/87f333178d5942de51b193111d6f636c79833ea5/starlark/testdata/float.star#L49 I think the original author wanted to point out the cases where float loses precision.

I did only some formatting changes to that file to allow for easier discarding of nonconformant lines:

0a1,3
> # @generated
> # Copied from https://github.com/google/starlark-go/blob/87f333178d5942de51b193111d6f636c79833ea5/starlark/testdata/
>
237,239c240
< assert.eq(
<     str(sorted([inf, neginf, nan, 1e300, -1e300, 1.0, -1.0, 1, -1, 1e-300, -1e-300, 0, 0.0, negzero, 1e-300, -1e-300])),
<     "[-inf, -1e+300, -1.0, -1, -1e-300, -1e-300, 0, 0.0, -0.0, 1e-300, 1e-300, 1.0, 1, 1e+300, +inf, nan]")
---
> assert.eq(str(sorted([inf, neginf, nan, 1e300, -1e300, 1.0, -1.0, 1, -1, 1e-300, -1e-300, 0, 0.0, negzero, 1e-300, -1e-300])), "[-inf, -1e+300, -1.0, -1, -1e-300, -1e-300, 0, 0.0, -0.0, 1e-300, 1e-300, 1.0, 1, 1e+300, +inf, nan]")
384,385c385,390
<   for a in [1.23e100, 1.23e10, 1.23e1, 1.23,
<             1, 4294967295, 8589934591, 9223372036854775807]:
---
>   for a in [
>             1.23e100,   # int overflow in starlark-rust
>             1.23e10,    # int overflow in starlark-rust
>             1.23e1, 1.23, 1,
>             4294967295, 8589934591, 9223372036854775807, # int overflow in starlark-rust
>             ]:

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is from Bazel, so nothing to do with us :)

@ndmitchell
Copy link
Contributor

@pierd - leave those changes from @bobyangyf with me - I'll make them on the internal copy I mirrored, as I had to make a few small formatting fixes in the import.

@ndmitchell
Copy link
Contributor

To keep you updated, it was in the process of being merged when the current Facebook outage happened, which has delayed the merge. I made a few formatting and whitespace tweaks, fixed some error messages, but very little. Hopefully this will land tomorrow.

@pierd
Copy link
Contributor Author

pierd commented Oct 4, 2021

No worries, thanks for the update.

@ndmitchell
Copy link
Contributor

All merged! There was one last remark about -0.0 and 0.0 need to hash to the same thing which I tweaked, but otherwise it's the same.

After that, as part of the move to have repr be Display (which encourages Rust authors to give a good repr) I had to make the f64 wrapped to be a StarlarkFloat, so we can customise the Display instance - but it was pretty simple and mechanical to change.

Thanks very much for your contribution 🥇

@pierd pierd deleted the floats branch October 5, 2021 11:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants