Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 49 additions & 1 deletion src/compiler/string_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,56 @@ pub fn read_hex_float(s: &[u8]) -> Option<f64> {
if is_neg {
base = -base;
}
Some(ldexp(base, exp))
}

fn ldexp(mut val: f64, exp: i32) -> f64 {
fn iexp2(exp: i32) -> f64 {
assert!(exp >= -1022 && exp <= 1023);
f64::from_bits(((exp + 1023 as i32) as u64) << 52)
}
fn extract_exp(val: f64) -> u64 {
(val.to_bits() >> 52) & 0x7ff
}
fn extract_mantissa(val: f64) -> u64 {
val.to_bits() & ((1 << 52) - 1)
}

let mut orig_exp = extract_exp(val) as i32;
let mantissa = extract_mantissa(val);
if orig_exp == 0 {
if mantissa == 0 {
return val;
}
// input is subnormal
val *= iexp2(54);
orig_exp = extract_exp(val) as i32 - 54;
} else if orig_exp == 2047 {
// input is NaN of Inf
return val;
}

Some(base * (exp as f64).exp2())
let new_exp = orig_exp.saturating_add(exp);
if new_exp >= 2047 {
f64::copysign(f64::INFINITY, val) // overflow
} else if new_exp <= -54 {
f64::copysign(0.0, val) // underflow
} else {
if new_exp > 0 {
f64::from_bits(
((val.is_sign_negative() as u64) << 63)
| ((new_exp as u64) << 52)
| (mantissa as u64),
)
} else {
// Output is subnormal
f64::from_bits(
((val.is_sign_negative() as u64) << 63)
| (((new_exp + 54) as u64) << 52)
| (mantissa as u64),
) * iexp2(-54)
}
}
}

/// Read an optional '-' or '+' prefix and return whether the value is negated (starts with a '-'
Expand Down
13 changes: 13 additions & 0 deletions src/stdlib/string.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::{Callback, CallbackReturn, Context, String, Table};

mod format;

pub fn load_string<'gc>(ctx: Context<'gc>) {
let string = Table::new(&ctx);

Expand Down Expand Up @@ -99,5 +101,16 @@ pub fn load_string<'gc>(ctx: Context<'gc>) {
}),
);

string
.set(
ctx,
"format",
Callback::from_fn(&ctx, |ctx, _, stack| {
let seq = format::string_format(ctx, stack)?;
Ok(CallbackReturn::Sequence(crate::BoxSequence::new(&ctx, seq)))
}),
)
.unwrap();

ctx.set_global("string", string);
}
Loading