diff --git a/book/src/list-functions.md b/book/src/list-functions.md index 023abe1c..e75ebe90 100644 --- a/book/src/list-functions.md +++ b/book/src/list-functions.md @@ -119,4 +119,6 @@ fn str_append(a: String, b: String) -> String fn str_contains(haystack: String, needle: String) -> Bool fn str_replace(s: String, pattern: String, replacement: String) -> String fn str_repeat(a: String, n: Scalar) -> String +fn chr(n: Scalar) -> String +fn hex(n: Scalar) -> String ``` diff --git a/examples/prelude_tests.nbt b/examples/prelude_tests.nbt index ee942cb7..0b3036ca 100644 --- a/examples/prelude_tests.nbt +++ b/examples/prelude_tests.nbt @@ -72,3 +72,11 @@ assert(str_replace("hello world", "hello", "HEY") == "HEY world") assert(str_replace("xxx", "x", "yY") == "yYyYyY") assert(str_repeat("xy", 3) == "xyxyxy") + +assert(hex(0x0) == "0x0") +assert(hex(0x1) == "0x1") +assert(hex(0x9) == "0x9") +assert(hex(0xa) == "0xa") +assert(hex(0xf) == "0xf") +assert(hex(0xabc1234567890) == "0xabc1234567890") +assert(hex(-0xc0ffee) == "-0xc0ffee") diff --git a/numbat/modules/core/functions.nbt b/numbat/modules/core/functions.nbt new file mode 100644 index 00000000..3ab05367 --- /dev/null +++ b/numbat/modules/core/functions.nbt @@ -0,0 +1,5 @@ +fn abs(x: T) -> T +fn round(x: T) -> T +fn floor(x: T) -> T +fn ceil(x: T) -> T +fn mod(a: T, b: T) -> T diff --git a/numbat/modules/core/strings.nbt b/numbat/modules/core/strings.nbt index 75d9634b..c8aec88b 100644 --- a/numbat/modules/core/strings.nbt +++ b/numbat/modules/core/strings.nbt @@ -1,9 +1,12 @@ use core::scalar +use core::functions fn str_length(s: String) -> Scalar fn str_slice(s: String, start: Scalar, end: Scalar) -> String +fn chr(n: Scalar) -> String + fn str_append(a: String, b: String) -> String = "{a}{b}" fn str_contains(haystack: String, needle: String) -> Bool = @@ -26,3 +29,13 @@ fn str_repeat(a: String, n: Scalar) -> String = if n > 0 then str_append(a, str_repeat(a, n - 1)) else "" + +fn hex_digit(x: Scalar) -> String = + if mod(x, 16) < 10 then chr(48 + mod(x, 16)) else chr(97 + mod(x, 16) - 10) + +fn hex(x: Scalar) -> String = + if x < 0 + then "-{hex(-x)}" + else if floor(x / 16) == 0 + then str_append("0x", hex_digit(x)) + else str_append(hex(floor(x / 16)), hex_digit(x)) diff --git a/numbat/modules/math/functions.nbt b/numbat/modules/math/functions.nbt index 26f1a406..2e29c91f 100644 --- a/numbat/modules/math/functions.nbt +++ b/numbat/modules/math/functions.nbt @@ -3,11 +3,6 @@ use math::constants ## Basics -fn abs(x: T) -> T -fn round(x: T) -> T -fn floor(x: T) -> T -fn ceil(x: T) -> T -fn mod(a: T, b: T) -> T fn sqrt(x: D^2) -> D = x^(1/2) fn sqr(x: D) -> D^2 = x^2 diff --git a/numbat/modules/prelude.nbt b/numbat/modules/prelude.nbt index 4ad93cb6..a6e83951 100644 --- a/numbat/modules/prelude.nbt +++ b/numbat/modules/prelude.nbt @@ -1,6 +1,7 @@ use core::scalar use core::quantities use core::dimensions +use core::functions use core::strings use core::error diff --git a/numbat/src/ffi.rs b/numbat/src/ffi.rs index 1cb70f6e..fe685ab0 100644 --- a/numbat/src/ffi.rs +++ b/numbat/src/ffi.rs @@ -323,6 +323,14 @@ pub(crate) fn functions() -> &'static HashMap { callable: Callable::Function(Box::new(str_slice)), }, ); + m.insert( + "chr".to_string(), + ForeignFunction { + name: "chr".into(), + arity: 1..=1, + callable: Callable::Function(Box::new(chr)), + }, + ); m }) @@ -722,3 +730,13 @@ fn str_slice(args: &[Value]) -> Result { Ok(Value::String(output.into())) } + +fn chr(args: &[Value]) -> Result { + assert!(args.len() == 1); + + let idx = args[0].unsafe_as_quantity().unsafe_value().to_f64() as u32; + + let output = char::from_u32(idx).unwrap_or('�'); + + Ok(Value::String(output.to_string())) +}