-
Notifications
You must be signed in to change notification settings - Fork 21
BigInt
support and refactors
#5
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
BigInt
support and refactors
#5
Conversation
In the commit above I also fixed the |
I think it may be possible to decrease amount of |
I guess I'll just do it to improve readability. An extra dependency won't do much harm. |
src/model.rs
Outdated
Value::False => false, | ||
_ => true, | ||
pub fn is_truthy(&self) -> bool { | ||
!matches!(self, Value::List(List::NIL) | Value::False) // Matches not those values |
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.
Better yet would be:
self == &Value::False || self == &Value::NIL
More straightforward, and I imagine it might also be more performant
Hi, so I was wondering what was up with all the reformatting at first, and then I realized you ran it through Several things that I noticed in here seem reasonable, but it's tough to review in this state. Now that trunk has been reformatted, I was wondering if you could rebase so the diff will be cleaner? I will also say I'm concerned about adding dependencies; I really like the fact that this crate currently has zero dependencies. I don't know how important that actually is, per se, but it feels nice. With that said I appreciate the build-time flag for the main dependency, and the other two seem like they would have little to no runtime footprint, so I might be willing to merge the BigInt stuff. I'd definitely be willing to merge |
I rebased the thing, I also excluded functions I added to |
src/parser.rs
Outdated
if !stack.is_empty() { | ||
if let ParseTree::List { vec, quoted: _ } = stack.last_mut().unwrap() { |
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.
Even better might be:
if let Some(last) = stack.last_mut() {
if let ParseTree::List { vec, quoted: _ } = last {
src/default_environment.rs
Outdated
|
||
Ok(Value::List(res.into_iter().map(Value::Int).collect::<List>())) | ||
} else { | ||
Ok(Value::List((start..=end).map(Value::Int).collect::<List>())) |
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.
Oh wow, was this logic broken before? (start..end
vs start..=end
)
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.
Actually- I think the exclusive behavior was intended, since this is how ranges tend to work in other languages:
(range 0 10)
'(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
So let's remove the =
here, and also change the <=
to <
in the BigInt
version
src/default_environment.rs
Outdated
let mut i = start.clone(); | ||
let mut res = Vec::with_capacity((end.clone() - start) | ||
.to_usize() | ||
.ok_or(RuntimeError::new("Failed converting `BigInt` to `usize`"))? | ||
); | ||
|
||
while i <= end { | ||
res.push(i.clone()); | ||
i += 1; | ||
} | ||
|
||
Ok(Value::List(res.into_iter().map(Value::Int).collect::<List>())) |
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's weird that BigInt
doesn't seem to implement Step
. Still, I can't help but feel there might be a simpler way to do this? If not, this is probably fine
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.
Ah hmm, that's disappointing
rust-num/num-bigint#68
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, I asked about it in Rust discord server, they gave me the same answer
argnames, | ||
body, | ||
})) | ||
} | ||
|
||
Value::Symbol(symbol) if symbol == "quote" => { | ||
let exp = list.cdr().car()?.clone(); | ||
let exp = list.cdr().car()?; |
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.
Just curious, did you have some sort of tool that helped you find all these unneeded Rc .clone()
s? I suspected there were some but had no way to identify them all en masse
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.
cargo clippy
, I use NeoVim with Ale to run this command every time I save a file
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.
Huh. My editor shows clippy hints inline, but I've never seen that particular rule
One final general comment: I don't love all the special-casing for BigInt (and I see that you don't either), but since it happens at compile-time I think I can live with it, and I also suspect there might be some opportunities to eliminate it via traits; not sure. I'll take a whack at that after this is merged. Assuming there isn't a way to eliminate it, though, I'm concerned about making sure it gets tested. Do you know if it's possible to test code under different |
Yeah, it's possible to run feature-dependant tests. With cfg_if! {
if #[cfg(feature = "bigint")] {
#[test]
fn bigint_specific_test() {
// Do some tests with BigInt
}
} else {
#[test]
fn general_test() {
// Do some tests in general
}
}
} or with vanilla #[cfg(feature = "bigint")]
#[test]
fn bigint_specific_test() {
// Some tests here
}
#[cfg(not(feature = "bigint"))]
#[test]
fn general_test() {
// Some tests there
} |
Yeah- so that runs the test if the flag is enabled, but what I'd like is to run existing tests as if those feature flags were set, as part of the normal I won't let it hold up the merge, but if you know a way to do that I'd love to hear about it |
Once those first two changes I suggested have been made, this should be good to go! |
I don't think that's possible because then compiler would have to test 2 separate versions of the program (one with and one without |
Added
BigInt
support, along with compile-time configurable types forValue::Int
andValue::Float
. I did some code refactoring in form of addingnew(impl Into<String>)
method to error types and changing manual error constructions with constructions with the saidnew
method. Also, I've addedfactorial
function in order to testBigInt
, but to be honest I just like seeing big numbers draw over my screen :DIn order to do some of the crazy shit I did in order to make
BigInt
work nicely (and kill readability), I addedcfg-if
,num-traits
andnum-bigint
as dependencies. Thenum-traits
andnum-bigint
are compiled if and only if featurebigint
is set. I am relatively new to Rust and if you have any suggestions and/or corrections, I'd like to hear them!