Support Num.toStr for f32, f64

This commit is contained in:
Ayaz Hafiz 2022-07-13 12:13:01 -04:00
parent 6ac9c37e06
commit b7c312d449
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
7 changed files with 79 additions and 14 deletions

View file

@ -152,7 +152,6 @@ comptime {
exportStrFn(str.strConcatC, "concat");
exportStrFn(str.strJoinWithC, "joinWith");
exportStrFn(str.strNumberOfBytes, "number_of_bytes");
exportStrFn(str.strFromFloatC, "from_float");
exportStrFn(str.strEqual, "equal");
exportStrFn(str.substringUnsafe, "substring_unsafe");
exportStrFn(str.getUnsafe, "get_unsafe");
@ -173,6 +172,7 @@ comptime {
}
inline for (FLOATS) |T| {
str.exportFromFloat(T, ROC_BUILTINS ++ "." ++ STR ++ ".from_float.");
num.exportParseFloat(T, ROC_BUILTINS ++ "." ++ STR ++ ".to_float.");
}
}

View file

@ -749,13 +749,19 @@ fn strFromIntHelp(comptime T: type, int: T) RocStr {
}
// Str.fromFloat
pub fn strFromFloatC(float: f64) callconv(.C) RocStr {
return @call(.{ .modifier = always_inline }, strFromFloatHelp, .{ f64, float });
pub fn exportFromFloat(comptime T: type, comptime name: []const u8) void {
comptime var f = struct {
fn func(float: T) callconv(.C) RocStr {
return @call(.{ .modifier = always_inline }, strFromFloatHelp, .{ T, float });
}
}.func;
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
}
fn strFromFloatHelp(comptime T: type, float: T) RocStr {
var buf: [100]u8 = undefined;
const result = std.fmt.bufPrint(&buf, "{d}", .{float}) catch unreachable;
const result = std.fmt.bufPrint(&buf, "{}", .{float}) catch unreachable;
return RocStr.init(&buf, result.len);
}

View file

@ -319,7 +319,7 @@ pub const STR_STARTS_WITH_SCALAR: &str = "roc_builtins.str.starts_with_scalar";
pub const STR_ENDS_WITH: &str = "roc_builtins.str.ends_with";
pub const STR_NUMBER_OF_BYTES: &str = "roc_builtins.str.number_of_bytes";
pub const STR_FROM_INT: IntrinsicName = int_intrinsic!("roc_builtins.str.from_int");
pub const STR_FROM_FLOAT: &str = "roc_builtins.str.from_float";
pub const STR_FROM_FLOAT: IntrinsicName = float_intrinsic!("roc_builtins.str.from_float");
pub const STR_TO_INT: IntrinsicName = int_intrinsic!("roc_builtins.str.to_int");
pub const STR_TO_FLOAT: IntrinsicName = float_intrinsic!("roc_builtins.str.to_float");
pub const STR_TO_DECIMAL: &str = "roc_builtins.str.to_decimal";

View file

@ -5496,7 +5496,14 @@ fn run_low_level<'a, 'ctx, 'env>(
// Str.fromFloat : Float * -> Str
debug_assert_eq!(args.len(), 1);
str_from_float(env, scope, args[0])
let (float, float_layout) = load_symbol_and_layout(scope, &args[0]);
let float_width = match float_layout {
Layout::Builtin(Builtin::Float(float_width)) => *float_width,
_ => unreachable!(),
};
str_from_float(env, float, float_width)
}
StrFromUtf8Range => {
debug_assert_eq!(args.len(), 3);
@ -5815,8 +5822,8 @@ fn run_low_level<'a, 'ctx, 'env>(
str_from_int(env, int, *int_width)
}
Layout::Builtin(Builtin::Float(_float_width)) => {
str_from_float(env, scope, args[0])
Layout::Builtin(Builtin::Float(float_width)) => {
str_from_float(env, num, *float_width)
}
_ => unreachable!(),
}

View file

@ -3,7 +3,7 @@ use crate::llvm::build::{Env, Scope};
use inkwell::builder::Builder;
use inkwell::values::{BasicValueEnum, IntValue, PointerValue, StructValue};
use inkwell::AddressSpace;
use roc_builtins::bitcode::{self, IntWidth};
use roc_builtins::bitcode::{self, FloatWidth, IntWidth};
use roc_module::symbol::Symbol;
use roc_mono::layout::{Builtin, Layout};
use roc_target::PtrWidth;
@ -103,11 +103,15 @@ pub fn decode_from_utf8_result<'a, 'ctx, 'env>(
}
}
/// Str.fromFloat : Int -> Str
/// Str.fromFloat : Float * -> Str
pub fn str_from_float<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
scope: &Scope<'a, 'ctx>,
int_symbol: Symbol,
float: BasicValueEnum<'ctx>,
float_width: FloatWidth,
) -> BasicValueEnum<'ctx> {
call_str_bitcode_fn(env, &[float], &bitcode::STR_FROM_FLOAT[float_width])
}
) -> BasicValueEnum<'ctx> {
let float = load_symbol(scope, &int_symbol);

View file

@ -1958,10 +1958,10 @@ impl<'a> LowLevelCall<'a> {
FloatWidth::F32 => {
self.load_args(backend);
backend.code_builder.f64_promote_f32();
self.load_args_and_call_zig(backend, bitcode::STR_FROM_FLOAT);
self.load_args_and_call_zig(backend, &bitcode::STR_FROM_FLOAT[width]);
}
FloatWidth::F64 => {
self.load_args_and_call_zig(backend, bitcode::STR_FROM_FLOAT);
self.load_args_and_call_zig(backend, &bitcode::STR_FROM_FLOAT[width]);
}
FloatWidth::F128 => todo!("F128 to Str"),
},

View file

@ -3054,6 +3054,54 @@ fn num_to_str_i64() {
);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn num_to_str_f32() {
use roc_std::RocStr;
assert_evals_to!(r#"Num.toStr -10.75f32"#, RocStr::from("-1.075e+01"), RocStr);
assert_evals_to!(r#"Num.toStr -1.75f32"#, RocStr::from("-1.75e+00"), RocStr);
assert_evals_to!(r#"Num.toStr 0f32"#, RocStr::from("0.0e+00"), RocStr);
assert_evals_to!(r#"Num.toStr 1.75f32"#, RocStr::from("1.75e+00"), RocStr);
assert_evals_to!(r#"Num.toStr 10.75f32"#, RocStr::from("1.075e+01"), RocStr);
assert_evals_to!(
r#"Num.toStr Num.maxF32"#,
RocStr::from("3.40282346e+38"),
RocStr
);
assert_evals_to!(
r#"Num.toStr Num.minF32"#,
RocStr::from("-3.40282346e+38"),
RocStr
);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn num_to_str_f64() {
use roc_std::RocStr;
assert_evals_to!(r#"Num.toStr -10.75f64"#, RocStr::from("-1.075e+01"), RocStr);
assert_evals_to!(r#"Num.toStr -1.75f64"#, RocStr::from("-1.75e+00"), RocStr);
assert_evals_to!(r#"Num.toStr 0f64"#, RocStr::from("0.0e+00"), RocStr);
assert_evals_to!(r#"Num.toStr 1.75f64"#, RocStr::from("1.75e+00"), RocStr);
assert_evals_to!(r#"Num.toStr 10.75f64"#, RocStr::from("1.075e+01"), RocStr);
assert_evals_to!(
r#"Num.toStr Num.maxF64"#,
RocStr::from("1.7976931348623157e+308"),
RocStr
);
assert_evals_to!(
r#"Num.toStr Num.minF64"#,
RocStr::from("-1.7976931348623157e+308"),
RocStr
);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn u8_addition_greater_than_i8() {