Skip to content

Commit 4e8dda0

Browse files
authored
Release 0.3.0 (#2)
1 parent 752554a commit 4e8dda0

File tree

11 files changed

+198
-39
lines changed

11 files changed

+198
-39
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "val"
3-
version = "0.2.0"
3+
version = "0.3.0"
44
authors = ["Liam <[email protected]>"]
55
categories = ["science", "parser-implementations", "command-line-interface"]
66
description = "An arbitrary precision calculator language"

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ program. The tool supports executing arbitrary expressions inline using the
9191

9292
```bash
9393
val -p 53 -e 'sin(2) * e ^ pi * cos(sum([1, 2, 3]))'
94-
1.6481455793912883588e+1
94+
16.481455793912883588
9595
```
9696

9797
**n.b.** The `--expression` option and `filename` argument are mutually
@@ -161,15 +161,17 @@ complex operations:
161161
162162
#### Number
163163
164-
Numeric values are represented as arbitrary floating point numbers:
164+
Numeric values are represented as arbitrary floating point numbers (using
165+
[astro_float(https://docs.rs/astro-float/latest/astro_float/index.html)] under
166+
the hood):
165167
166168
```rust
167169
> pi
168-
3.141592653589793115997963468544185161590576171875e+0
170+
3.141592653589793115997963468544185161590576171875
169171
> e
170-
2.718281828459045090795598298427648842334747314453125e+0
172+
2.718281828459045090795598298427648842334747314453125
171173
> sin(2) * e ^ pi * cos(sum([1, 2, 3]))
172-
1.64814557939128835908118223753548409318930600432600320575175542910885566534716862696709583557263450637540094805515971245058657340687939442764118452427864231041058959960049996970569867866035825048029794926250103816423751837050040821914044725396611746570949840536443560831710407959633707222226883928822125018008e+1
174+
16.4814557939128835908118223753548409318930600432600320575175542910885566534716862696709583557263450637540094805515971245058657340687939442764118452427864231041058959960049996970569867866035825048029794926250103816423751837050040821914044725396611746570949840536443560831710407959633707222226883928822125018007
173175
>
174176
```
175177

src/ast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ impl Display for Expression<'_> {
261261
Expression::ListAccess(list, index) => {
262262
write!(f, "list_access({}, {})", list.0, index.0)
263263
}
264-
Expression::Number(number) => write!(f, "number({})", number),
264+
Expression::Number(number) => write!(f, "number({})", number.display()),
265265
Expression::String(string) => write!(f, "string(\"{}\")", string),
266266
Expression::UnaryOp(op, expr) => {
267267
write!(f, "unary_op({}, {})", op, expr.0)

src/environment.rs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,7 @@ impl<'src> Environment<'src> {
572572

573573
let number = payload.arguments[0].number(payload.span)?;
574574

575-
if number < BigFloat::from(0.0) {
575+
if number.is_negative() {
576576
return Err(Error::new(
577577
payload.span,
578578
"Cannot take square root of negative number",
@@ -718,7 +718,20 @@ impl<'src> Environment<'src> {
718718
));
719719
}
720720

721-
process::exit(0);
721+
let code = match payload.arguments[0]
722+
.number(payload.span)?
723+
.to_f64(payload.config.rounding_mode)
724+
{
725+
Some(n) if n.is_finite() && n >= 0.0 => n as usize,
726+
_ => {
727+
return Err(Error::new(
728+
payload.span,
729+
"Argument to `exit` must be a non-negative finite number",
730+
));
731+
}
732+
};
733+
734+
process::exit(code as i32);
722735
}),
723736
);
724737

@@ -739,7 +752,20 @@ impl<'src> Environment<'src> {
739752
));
740753
}
741754

742-
process::exit(0);
755+
let code = match payload.arguments[0]
756+
.number(payload.span)?
757+
.to_f64(payload.config.rounding_mode)
758+
{
759+
Some(n) if n.is_finite() && n >= 0.0 => n as usize,
760+
_ => {
761+
return Err(Error::new(
762+
payload.span,
763+
"Argument to `quit` must be a non-negative finite number",
764+
));
765+
}
766+
};
767+
768+
process::exit(code as i32);
743769
}),
744770
);
745771

src/evaluator.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ impl<'a> Evaluator<'a> {
300300

301301
match (&lhs_val, &rhs_val) {
302302
(Value::Number(a), Value::Number(b)) => Ok(Value::Number(a.add(
303-
&b,
303+
b,
304304
self.environment.config.precision,
305305
self.environment.config.rounding_mode,
306306
))),

src/float_ext.rs

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,55 +2,146 @@ use super::*;
22

33
pub trait FloatExt {
44
fn to_f64(&self, rounding_mode: astro_float::RoundingMode) -> Option<f64>;
5+
fn display(&self) -> String;
56
}
67

78
impl FloatExt for BigFloat {
9+
fn display(&self) -> String {
10+
if let Some(parts) = self.as_raw_parts() {
11+
let number =
12+
BigFloat::from_raw_parts(parts.0, parts.1, parts.2, parts.3, parts.4);
13+
14+
if number.is_nan() {
15+
return "NaN".into();
16+
}
17+
18+
if number.is_inf_pos() {
19+
return "Inf".into();
20+
}
21+
22+
if number.is_inf_neg() {
23+
return "-Inf".into();
24+
}
25+
26+
if number.is_zero() {
27+
return "0".into();
28+
}
29+
30+
let formatted = number
31+
.format(
32+
Radix::Dec,
33+
astro_float::RoundingMode::None,
34+
&mut Consts::new().expect("BigFloat constants cache"),
35+
)
36+
.unwrap();
37+
38+
if !formatted.contains('e') {
39+
return formatted;
40+
}
41+
42+
let (mant, exp) = {
43+
let mut parts = formatted.split('e');
44+
(parts.next().unwrap(), parts.next().unwrap())
45+
};
46+
47+
let exp: i32 = exp.parse().unwrap();
48+
49+
let (sign, mant) =
50+
mant.split_at(if mant.starts_with('-') { 1 } else { 0 });
51+
52+
let digits = mant.replace('.', "");
53+
54+
let new_int_len = mant.find('.').unwrap_or(mant.len()) as i32 + exp;
55+
56+
let result = if new_int_len <= 0 {
57+
format!(
58+
"{}0.{}{}",
59+
sign,
60+
"0".repeat((-new_int_len) as usize),
61+
digits
62+
)
63+
} else if new_int_len as usize >= digits.len() {
64+
format!(
65+
"{}{}{}",
66+
sign,
67+
digits,
68+
"0".repeat(new_int_len as usize - digits.len())
69+
)
70+
} else {
71+
let (left, right) = digits.split_at(new_int_len as usize);
72+
format!("{}{}.{}", sign, left, right)
73+
};
74+
75+
if result.find('.').is_some() {
76+
result
77+
.trim_end_matches('0')
78+
.trim_end_matches('.')
79+
.to_string()
80+
} else {
81+
result
82+
}
83+
} else {
84+
self.to_string()
85+
}
86+
}
87+
888
fn to_f64(&self, rounding_mode: astro_float::RoundingMode) -> Option<f64> {
989
let mut big_float = self.clone();
1090
big_float.set_precision(64, rounding_mode).ok()?;
1191

1292
let sign = big_float.sign()?;
93+
1394
let exponent = big_float.exponent()? as isize;
95+
1496
let mantissa_digits = big_float.mantissa_digits()?;
1597

1698
if mantissa_digits.is_empty() {
1799
return Some(0.0);
18100
}
19101

20102
let mantissa = mantissa_digits[0];
103+
21104
if mantissa == 0 {
22105
return Some(0.0);
23106
}
24107

25108
let mut exponent = exponent + 0b1111111111;
109+
26110
let mut ret = 0u64;
27111

28112
if exponent >= 0b11111111111 {
29-
return Some(match sign {
113+
Some(match sign {
30114
Sign::Pos => f64::INFINITY,
31115
Sign::Neg => f64::NEG_INFINITY,
32-
});
116+
})
33117
} else if exponent <= 0 {
34118
let shift = -exponent;
119+
35120
if shift < 52 {
36121
ret |= mantissa >> (shift + 12);
122+
37123
if sign == Sign::Neg {
38124
ret |= 0x8000000000000000u64;
39125
}
126+
40127
return Some(f64::from_bits(ret));
41128
} else {
42129
return Some(0.0);
43130
}
44131
} else {
45132
let mantissa = mantissa << 1;
133+
46134
exponent -= 1;
135+
47136
if sign == Sign::Neg {
48137
ret |= 1;
49138
}
139+
50140
ret <<= 11;
51141
ret |= exponent as u64;
52142
ret <<= 52;
53143
ret |= mantissa >> 12;
144+
54145
return Some(f64::from_bits(ret));
55146
}
56147
}

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
pub(crate) use {
22
ariadne::{Color, Label, Report, ReportKind, Source},
3-
astro_float::{BigFloat, Consts, Sign},
3+
astro_float::{BigFloat, Consts, Radix, Sign},
44
chumsky::prelude::*,
55
clap::Parser as Clap,
66
environment::Environment,

src/rounding_mode.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ impl std::str::FromStr for RoundingMode {
4848
}
4949
}
5050

51-
impl Into<astro_float::RoundingMode> for RoundingMode {
52-
fn into(self) -> astro_float::RoundingMode {
53-
match self {
51+
impl From<RoundingMode> for astro_float::RoundingMode {
52+
fn from(mode: RoundingMode) -> Self {
53+
match mode {
5454
RoundingMode::None => astro_float::RoundingMode::None,
5555
RoundingMode::Up => astro_float::RoundingMode::Up,
5656
RoundingMode::Down => astro_float::RoundingMode::Down,

src/value.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ impl Display for Value<'_> {
3333
.join(", ")
3434
),
3535
Value::Null => write!(f, "null"),
36-
Value::Number(number) => write!(f, "{number}",),
36+
Value::Number(number) => write!(f, "{}", number.display()),
3737
Value::String(string) => write!(f, "{string}"),
3838
}
3939
}

0 commit comments

Comments
 (0)