Merge pull request #2108 from rtfeldman/implement_num_to_str

Implement Num.toStr
This commit is contained in:
Richard Feldman 2021-11-30 15:34:39 -05:00 committed by GitHub
commit 68e206f42c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 123 additions and 180 deletions

View File

@ -61,6 +61,7 @@ interface Num
addChecked,
atan,
acos,
toStr,
Signed128,
Signed64,
Signed32,

View File

@ -10,8 +10,6 @@ interface Str
countGraphemes,
startsWith,
endsWith,
fromInt,
fromFloat,
fromUtf8,
Utf8Problem,
Utf8ByteProblem,

View File

@ -385,6 +385,13 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// maxI128 : I128
add_type!(Symbol::NUM_MAX_I128, i128_type());
// toStr : Num a -> Str
add_top_level_function_type!(
Symbol::NUM_TO_STR,
vec![num_type(flex(TVAR1))],
Box::new(str_type())
);
// Float module
// div : Float a, Float a -> Float a
@ -618,13 +625,6 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
Box::new(nat_type())
);
// fromInt : Int a -> Str
add_top_level_function_type!(
Symbol::STR_FROM_INT,
vec![int_type(flex(TVAR1))],
Box::new(str_type())
);
// repeat : Str, Nat -> Str
add_top_level_function_type!(
Symbol::STR_REPEAT,
@ -702,13 +702,6 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
Box::new(list_type(u8_type()))
);
// fromFloat : Float a -> Str
add_top_level_function_type!(
Symbol::STR_FROM_FLOAT,
vec![float_type(flex(TVAR1))],
Box::new(str_type())
);
// List module
// get : List elem, Nat -> Result elem [ OutOfBounds ]*

View File

@ -61,11 +61,9 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
STR_STARTS_WITH_CODE_PT => str_starts_with_code_point,
STR_ENDS_WITH => str_ends_with,
STR_COUNT_GRAPHEMES => str_count_graphemes,
STR_FROM_INT => str_from_int,
STR_FROM_UTF8 => str_from_utf8,
STR_FROM_UTF8_RANGE => str_from_utf8_range,
STR_TO_UTF8 => str_to_utf8,
STR_FROM_FLOAT=> str_from_float,
STR_REPEAT => str_repeat,
STR_TRIM => str_trim,
STR_TRIM_LEFT => str_trim_left,
@ -192,6 +190,7 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
NUM_SHIFT_RIGHT_ZERO_FILL => num_shift_right_zf_by,
NUM_INT_CAST=> num_int_cast,
NUM_MAX_I128=> num_max_i128,
NUM_TO_STR => num_to_str,
RESULT_MAP => result_map,
RESULT_MAP_ERR => result_map_err,
RESULT_AFTER => result_after,
@ -369,6 +368,26 @@ fn num_min_int(symbol: Symbol, var_store: &mut VarStore) -> Def {
}
}
// Num.toStr : Num a -> Str
fn num_to_str(symbol: Symbol, var_store: &mut VarStore) -> Def {
let num_var = var_store.fresh();
let str_var = var_store.fresh();
let body = RunLowLevel {
op: LowLevel::NumToStr,
args: vec![(num_var, Var(Symbol::ARG_1))],
ret_var: str_var,
};
defn(
symbol,
vec![(num_var, Symbol::ARG_1)],
var_store,
body,
str_var,
)
}
/// Bool.isEq : val, val -> Bool
fn bool_eq(symbol: Symbol, var_store: &mut VarStore) -> Def {
let arg_var = var_store.fresh();
@ -1436,26 +1455,6 @@ fn str_count_graphemes(symbol: Symbol, var_store: &mut VarStore) -> Def {
)
}
/// Str.fromInt : Int * -> Str
fn str_from_int(symbol: Symbol, var_store: &mut VarStore) -> Def {
let int_var = var_store.fresh();
let str_var = var_store.fresh();
let body = RunLowLevel {
op: LowLevel::StrFromInt,
args: vec![(int_var, Var(Symbol::ARG_1))],
ret_var: str_var,
};
defn(
symbol,
vec![(int_var, Symbol::ARG_1)],
var_store,
body,
str_var,
)
}
/// Str.fromUtf8 : List U8 -> Result Str [ BadUtf8 { byteIndex : Nat, problem : Utf8Problem } } ]*
fn str_from_utf8(symbol: Symbol, var_store: &mut VarStore) -> Def {
let bytes_var = var_store.fresh();
@ -1738,26 +1737,6 @@ fn str_to_utf8(symbol: Symbol, var_store: &mut VarStore) -> Def {
lowlevel_1(symbol, LowLevel::StrToUtf8, var_store)
}
/// Str.fromFloat : Float * -> Str
fn str_from_float(symbol: Symbol, var_store: &mut VarStore) -> Def {
let float_var = var_store.fresh();
let str_var = var_store.fresh();
let body = RunLowLevel {
op: LowLevel::StrFromFloat,
args: vec![(float_var, Var(Symbol::ARG_1))],
ret_var: str_var,
};
defn(
symbol,
vec![(float_var, Symbol::ARG_1)],
var_store,
body,
str_var,
)
}
/// List.concat : List elem, List elem -> List elem
fn list_concat(symbol: Symbol, var_store: &mut VarStore) -> Def {
let list_var = var_store.fresh();

View File

@ -5522,6 +5522,24 @@ fn run_low_level<'a, 'ctx, 'env>(
list_join(env, parent, list, outer_list_layout)
}
NumToStr => {
// Num.toStr : Num a -> Str
debug_assert_eq!(args.len(), 1);
let (num, num_layout) = load_symbol_and_layout(scope, &args[0]);
match num_layout {
Layout::Builtin(Builtin::Int(int_width)) => {
let int = num.into_int_value();
str_from_int(env, int, *int_width)
}
Layout::Builtin(Builtin::Float(_float_width)) => {
str_from_float(env, scope, args[0])
}
_ => unreachable!(),
}
}
NumAbs | NumNeg | NumRound | NumSqrtUnchecked | NumLogUnchecked | NumSin | NumCos
| NumCeiling | NumFloor | NumToFloat | NumIsFinite | NumAtan | NumAcos | NumAsin => {
debug_assert_eq!(args.len(), 1);

View File

@ -406,7 +406,7 @@ pub fn str_from_utf8<'a, 'ctx, 'env>(
decode_from_utf8_result(env, result_ptr).into()
}
/// Str.fromInt : Int -> Str
/// Str.fromFloat : Int -> Str
pub fn str_from_float<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
scope: &Scope<'a, 'ctx>,

View File

@ -87,6 +87,7 @@ pub fn decode_low_level<'a>(
F32 => code_builder.f32_add(),
F64 => code_builder.f64_add(),
},
NumToStr => return NotImplemented,
NumAddChecked => return NotImplemented,
NumSub => match ret_layout.arg_types(CallConv::Zig)[0] {
I32 => code_builder.i32_sub(),

View File

@ -108,6 +108,7 @@ pub enum LowLevel {
NumShiftRightBy,
NumShiftRightZfBy,
NumIntCast,
NumToStr,
Eq,
NotEq,
And,
@ -186,12 +187,10 @@ impl LowLevel {
Symbol::STR_ENDS_WITH => Some(StrEndsWith),
Symbol::STR_SPLIT => Some(StrSplit),
Symbol::STR_COUNT_GRAPHEMES => Some(StrCountGraphemes),
Symbol::STR_FROM_INT => Some(StrFromInt),
Symbol::STR_FROM_UTF8 => None,
Symbol::STR_FROM_UTF8_RANGE => None,
Symbol::STR_TO_UTF8 => Some(StrToUtf8),
Symbol::STR_REPEAT => Some(StrRepeat),
Symbol::STR_FROM_FLOAT => Some(StrFromFloat),
Symbol::STR_TRIM => Some(StrTrim),
Symbol::STR_TRIM_LEFT => Some(StrTrimLeft),
Symbol::STR_TRIM_RIGHT => Some(StrTrimRight),
@ -268,6 +267,7 @@ impl LowLevel {
Symbol::NUM_CEILING => Some(NumCeiling),
Symbol::NUM_POW_INT => Some(NumPowInt),
Symbol::NUM_FLOOR => Some(NumFloor),
Symbol::NUM_TO_STR => Some(NumToStr),
// => Some(NumIsFinite),
Symbol::NUM_ATAN => Some(NumAtan),
Symbol::NUM_ACOS => Some(NumAcos),

View File

@ -992,6 +992,7 @@ define_builtins! {
104 NUM_BYTES_TO_U32: "bytesToU32"
105 NUM_CAST_TO_NAT: "#castToNat"
106 NUM_DIV_CEIL: "divCeil"
107 NUM_TO_STR: "toStr"
}
2 BOOL: "Bool" => {
0 BOOL_BOOL: "Bool" imported // the Bool.Bool type alias
@ -1017,19 +1018,17 @@ define_builtins! {
7 STR_COUNT_GRAPHEMES: "countGraphemes"
8 STR_STARTS_WITH: "startsWith"
9 STR_ENDS_WITH: "endsWith"
10 STR_FROM_INT: "fromInt"
11 STR_FROM_FLOAT: "fromFloat"
12 STR_FROM_UTF8: "fromUtf8"
13 STR_UT8_PROBLEM: "Utf8Problem" // the Utf8Problem type alias
14 STR_UT8_BYTE_PROBLEM: "Utf8ByteProblem" // the Utf8ByteProblem type alias
15 STR_TO_UTF8: "toUtf8"
16 STR_STARTS_WITH_CODE_PT: "startsWithCodePt"
17 STR_ALIAS_ANALYSIS_STATIC: "#aliasAnalysisStatic" // string with the static lifetime
18 STR_FROM_UTF8_RANGE: "fromUtf8Range"
19 STR_REPEAT: "repeat"
20 STR_TRIM: "trim"
21 STR_TRIM_LEFT: "trimLeft"
22 STR_TRIM_RIGHT: "trimRight"
10 STR_FROM_UTF8: "fromUtf8"
11 STR_UT8_PROBLEM: "Utf8Problem" // the Utf8Problem type alias
12 STR_UT8_BYTE_PROBLEM: "Utf8ByteProblem" // the Utf8ByteProblem type alias
13 STR_TO_UTF8: "toUtf8"
14 STR_STARTS_WITH_CODE_PT: "startsWithCodePt"
15 STR_ALIAS_ANALYSIS_STATIC: "#aliasAnalysisStatic" // string with the static lifetime
16 STR_FROM_UTF8_RANGE: "fromUtf8Range"
17 STR_REPEAT: "repeat"
18 STR_TRIM: "trim"
19 STR_TRIM_LEFT: "trimLeft"
20 STR_TRIM_RIGHT: "trimRight"
}
4 LIST: "List" => {
0 LIST_LIST: "List" imported // the List.List type alias

View File

@ -980,9 +980,9 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
| NumPowInt | NumBitwiseAnd | NumBitwiseXor | NumBitwiseOr | NumShiftLeftBy
| NumShiftRightBy | NumShiftRightZfBy => arena.alloc_slice_copy(&[irrelevant, irrelevant]),
NumAbs | NumNeg | NumSin | NumCos | NumSqrtUnchecked | NumLogUnchecked | NumRound
| NumCeiling | NumFloor | NumToFloat | Not | NumIsFinite | NumAtan | NumAcos | NumAsin
| NumIntCast => arena.alloc_slice_copy(&[irrelevant]),
NumToStr | NumAbs | NumNeg | NumSin | NumCos | NumSqrtUnchecked | NumLogUnchecked
| NumRound | NumCeiling | NumFloor | NumToFloat | Not | NumIsFinite | NumAtan | NumAcos
| NumAsin | NumIntCast => arena.alloc_slice_copy(&[irrelevant]),
NumBytesToU16 => arena.alloc_slice_copy(&[borrowed, irrelevant]),
NumBytesToU32 => arena.alloc_slice_copy(&[borrowed, irrelevant]),
StrStartsWith | StrEndsWith => arena.alloc_slice_copy(&[owned, borrowed]),

View File

@ -228,10 +228,10 @@ mod solve_expr {
infer_eq_without_problem(
indoc!(
r#"
Str.fromInt
Num.toStr
"#
),
"Int * -> Str",
"Num * -> Str",
);
}
@ -4543,8 +4543,8 @@ mod solve_expr {
|> Str.concat ") ("
|> Str.concat (printExpr b)
|> Str.concat ")"
Val v -> Str.fromInt v
Var v -> "Var " |> Str.concat (Str.fromInt v)
Val v -> Num.toStr v
Var v -> "Var " |> Str.concat (Num.toStr v)
main : Str
main = printExpr (Var 3)

View File

@ -1990,3 +1990,35 @@ fn when_on_i16() {
i16
);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn num_to_str() {
use roc_std::RocStr;
assert_evals_to!(
r#"Num.toStr 1234"#,
RocStr::from_slice("1234".as_bytes()),
RocStr
);
assert_evals_to!(r#"Num.toStr 0"#, RocStr::from_slice("0".as_bytes()), RocStr);
assert_evals_to!(
r#"Num.toStr -1"#,
RocStr::from_slice("-1".as_bytes()),
RocStr
);
let max = format!("{}", i64::MAX);
assert_evals_to!(
r#"Num.toStr Num.maxInt"#,
RocStr::from_slice(max.as_bytes()),
RocStr
);
let min = format!("{}", i64::MIN);
assert_evals_to!(
r#"Num.toStr Num.minInt"#,
RocStr::from_slice(min.as_bytes()),
RocStr
);
}

View File

@ -527,40 +527,6 @@ fn str_starts_with_false_small_str() {
assert_evals_to!(r#"Str.startsWith "1234" "23""#, false, bool);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_from_int() {
assert_evals_to!(
r#"Str.fromInt 1234"#,
roc_std::RocStr::from_slice("1234".as_bytes()),
roc_std::RocStr
);
assert_evals_to!(
r#"Str.fromInt 0"#,
roc_std::RocStr::from_slice("0".as_bytes()),
roc_std::RocStr
);
assert_evals_to!(
r#"Str.fromInt -1"#,
roc_std::RocStr::from_slice("-1".as_bytes()),
roc_std::RocStr
);
let max = format!("{}", i64::MAX);
assert_evals_to!(
r#"Str.fromInt Num.maxInt"#,
RocStr::from_slice(max.as_bytes()),
RocStr
);
let min = format!("{}", i64::MIN);
assert_evals_to!(
r#"Str.fromInt Num.minInt"#,
RocStr::from_slice(min.as_bytes()),
RocStr
);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_from_utf8_pass_single_ascii() {
@ -838,8 +804,8 @@ fn nested_recursive_literal() {
|> Str.concat ") ("
|> Str.concat (printExpr b)
|> Str.concat ")"
Val v -> "Val " |> Str.concat (Str.fromInt v)
Var v -> "Var " |> Str.concat (Str.fromInt v)
Val v -> "Val " |> Str.concat (Num.toStr v)
Var v -> "Var " |> Str.concat (Num.toStr v)
printExpr expr
"#
@ -875,12 +841,6 @@ fn str_join_comma_single() {
assert_evals_to!(r#"Str.joinWith ["1"] ", " "#, RocStr::from("1"), RocStr);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_from_float() {
assert_evals_to!(r#"Str.fromFloat 3.14"#, RocStr::from("3.14"), RocStr);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_to_utf8() {

View File

@ -446,39 +446,6 @@ fn str_starts_with_false_small_str() {
assert_evals_to!(r#"Str.startsWith "1234" "23""#, false, bool);
}
// #[test]
// fn str_from_int() {
// assert_evals_to!(
// r#"Str.fromInt 1234"#,
// roc_std::RocStr::from_slice("1234".as_bytes()),
// roc_std::RocStr
// );
// assert_evals_to!(
// r#"Str.fromInt 0"#,
// roc_std::RocStr::from_slice("0".as_bytes()),
// roc_std::RocStr
// );
// assert_evals_to!(
// r#"Str.fromInt -1"#,
// roc_std::RocStr::from_slice("-1".as_bytes()),
// roc_std::RocStr
// );
// let max = format!("{}", i64::MAX);
// assert_evals_to!(
// r#"Str.fromInt Num.maxInt"#,
// RocStr::from_slice(max.as_bytes()),
// RocStr
// );
// let min = format!("{}", i64::MIN);
// assert_evals_to!(
// r#"Str.fromInt Num.minInt"#,
// RocStr::from_slice(min.as_bytes()),
// RocStr
// );
// }
// #[test]
// fn str_from_utf8_pass_single_ascii() {
// assert_evals_to!(
@ -729,8 +696,8 @@ fn str_starts_with_false_small_str() {
// |> Str.concat ") ("
// |> Str.concat (printExpr b)
// |> Str.concat ")"
// Val v -> "Val " |> Str.concat (Str.fromInt v)
// Var v -> "Var " |> Str.concat (Str.fromInt v)
// Val v -> "Val " |> Str.concat (Num.toStr v)
// Var v -> "Var " |> Str.concat (Num.toStr v)
// printExpr expr
// "#
@ -763,11 +730,6 @@ fn str_starts_with_false_small_str() {
// assert_evals_to!(r#"Str.joinWith ["1"] ", " "#, RocStr::from("1"), RocStr);
// }
// #[test]
// fn str_from_float() {
// assert_evals_to!(r#"Str.fromFloat 3.14"#, RocStr::from("3.14"), RocStr);
// }
// #[test]
// fn str_to_utf8() {
// assert_evals_to!(

View File

@ -175,8 +175,8 @@ main = "Hello, world!"
#[test]
fn call_builtin() {
expect_html_def(
r#"myVal = Str.fromInt 1234"#,
"<span class=\"syntax-value\">myVal</span><span class=\"syntax-operator\"> = </span><span class=\"syntax-value\">Str.fromInt</span><span class=\"syntax-blank\"> </span><span class=\"syntax-number\">1234</span>\n\n",
r#"myVal = Num.toStr 1234"#,
"<span class=\"syntax-value\">myVal</span><span class=\"syntax-operator\"> = </span><span class=\"syntax-value\">Num.toStr</span><span class=\"syntax-blank\"> </span><span class=\"syntax-number\">1234</span>\n\n",
);
}

View File

@ -13,9 +13,9 @@ main =
optimized = eval (constFolding (reassoc e))
unoptimized
|> Str.fromInt
|> Num.toStr
|> Str.concat " & "
|> Str.concat (Str.fromInt optimized)
|> Str.concat (Num.toStr optimized)
|> Task.putLine
Expr : [

View File

@ -115,9 +115,9 @@ deriv : I64, Expr -> IO Expr
deriv = \i, f ->
fprime = d "x" f
line =
Str.fromInt (i + 1)
Num.toStr (i + 1)
|> Str.concat " count: "
|> Str.concat (Str.fromInt (count fprime))
|> Str.concat (Num.toStr (count fprime))
Task.putLine line
|> Task.after \_ -> Task.succeed fprime

View File

@ -7,7 +7,7 @@ main : Task.Task {} []
main =
Task.after Task.getInt \n ->
queens n # original koka 13
|> Str.fromInt
|> Num.toStr
|> Task.putLine
ConsList a : [ Nil, Cons a (ConsList a) ]

View File

@ -7,7 +7,7 @@ show = \list ->
else
content =
list
|> List.map Str.fromInt
|> List.map Num.toStr
|> Str.joinWith ", "
"[ \(content) ]"

View File

@ -55,7 +55,7 @@ main =
Cons head _ ->
val = fold (\_, v, r -> if v then r + 1 else r) head 0
val
|> Str.fromInt
|> Num.toStr
|> Task.putLine
Nil ->

View File

@ -20,7 +20,7 @@ main =
val = fold (\_, v, r -> if v then r + 1 else r) m 0
val
|> Str.fromInt
|> Num.toStr
|> Task.putLine
boom : Str -> a

View File

@ -13,7 +13,7 @@ main =
|> Task.putLine
show : RedBlackTree I64 {} -> Str
show = \tree -> showRBTree tree Str.fromInt (\{} -> "{}")
show = \tree -> showRBTree tree Num.toStr (\{} -> "{}")
showRBTree : RedBlackTree k v, (k -> Str), (v -> Str) -> Str
showRBTree = \tree, showKey, showValue ->

View File

@ -13,7 +13,7 @@ main =
# Task.putLine (showBool test1)
#
# _ ->
# ns = Str.fromInt n
# ns = Num.toStr n
# Task.putLine "No test \(ns)"
showBool : Bool -> Str

View File

@ -33,7 +33,7 @@ toStrData: Data -> Str
toStrData = \data ->
when data is
Lambda _ -> "[]"
Number n -> Str.fromInt (Num.intCast n)
Number n -> Num.toStr (Num.intCast n)
Var v -> Variable.toStr v
toStrState: State -> Str
@ -49,7 +49,7 @@ toStrState = \state ->
toStr: Context -> Str
toStr = \{scopes, stack, state, vars} ->
depth = Str.fromInt (List.len scopes)
depth = Num.toStr (List.len scopes)
stateStr = toStrState state
stackStr = Str.joinWith (List.map stack toStrData) " "
varsStr = Str.joinWith (List.map vars toStrData) " "

View File

@ -203,7 +203,7 @@ interpretCtx = \ctx ->
# This is supposed to flush io buffers. We don't buffer, so it does nothing
interpretCtx newCtx
Ok (T x _) ->
data = Str.fromInt (Num.intCast x)
data = Num.toStr (Num.intCast x)
Task.fail (InvalidChar data)
Err NoScope ->
Task.fail NoScope
@ -358,7 +358,7 @@ stepExecCtx = \ctx, char ->
0x2E -> # `.` write int
when popNumber ctx is
Ok (T popCtx num) ->
{} <- Task.await (Stdout.raw (Str.fromInt (Num.intCast num)))
{} <- Task.await (Stdout.raw (Num.toStr (Num.intCast num)))
Task.succeed popCtx
Err e ->
Task.fail e
@ -395,7 +395,7 @@ stepExecCtx = \ctx, char ->
Ok var ->
Task.succeed (Context.pushStack ctx (Var var))
Err _ ->
data = Str.fromInt (Num.intCast x)
data = Num.toStr (Num.intCast x)
Task.fail (InvalidChar data)
unaryOp: Context, (I32 -> I32) -> Result Context InterpreterErrors