From 2e6ced7f45cc486df6309e85a6ed87056c1b2d8b Mon Sep 17 00:00:00 2001 From: Jengamon Date: Mon, 13 May 2024 19:00:46 -0700 Subject: [PATCH 01/23] add string.sub --- src/stdlib/string.rs | 43 ++++++++++++++++++++++++++++++++++++++++ tests/scripts/string.lua | 16 +++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/src/stdlib/string.rs b/src/stdlib/string.rs index 58b7e21e..cc4655e0 100644 --- a/src/stdlib/string.rs +++ b/src/stdlib/string.rs @@ -24,5 +24,48 @@ pub fn load_string<'gc>(ctx: Context<'gc>) { ) .unwrap(); + string + .set( + ctx, + "sub", + Callback::from_fn(&ctx, |ctx, _, mut stack| { + let (string, i, j) = stack.consume::<(Value, i64, Option)>(ctx)?; + let string = match string { + Value::Integer(i) => i.to_string().as_bytes().to_vec(), + Value::String(s) => s.as_bytes().to_vec(), + v => { + return Err(format!( + "Bad argument to sub: expected string, got {}", + v.type_name() + ) + .into_value(ctx) + .into()) + } + }; + + let i = if i >= 0 { + i.saturating_sub(1) as usize + } else { + (string.len() as i64 + i) as usize + } + .clamp(0, (string.len() as usize).saturating_sub(1)); + let j = if let Some(j) = j { + if j >= 0 { + j.saturating_sub(1) as usize + } else { + (string.len() as i64 + j) as usize + } + .clamp(0, (string.len() as usize).saturating_sub(1)) + } else { + string.len().saturating_sub(1) + }; + + let result = if i > j { &[] } else { &string[i..=j] }; + stack.replace(ctx, crate::String::from_slice(&ctx, result).into_value(ctx)); + Ok(CallbackReturn::Return) + }), + ) + .unwrap(); + ctx.set_global("string", string).unwrap(); } diff --git a/tests/scripts/string.lua b/tests/scripts/string.lua index 277b82b4..ec49b7db 100644 --- a/tests/scripts/string.lua +++ b/tests/scripts/string.lua @@ -35,6 +35,22 @@ function test_len() string.len(-2147483648) == 11 end +do + assert(is_err(function() return string.sub(nil) end) and + is_err(function() return string.sub(true, 1) end) and + is_err(function() return string.sub(false) end) and + is_err(function() return string.sub({}) end) and + is_err(function() return string.sub(is_err) end) and + is_err(function() return string.sub(coroutine.create(test_coroutine_len)) end) and + string.sub(48, 1) == "48" and + string.sub(48, 2) == "8" and + string.sub(48, -1) == "8" and + string.sub("hilo", -1, -4) == "" and + string.sub("hilo", -4, -1) == "hilo" and + string.sub("hilo", -4, -3) == "hi" + ) +end + assert( test_concat() and test_len() From 64a1d8b39d484dfe2b07010ee139d348169a3447 Mon Sep 17 00:00:00 2001 From: Jengamon Date: Mon, 13 May 2024 19:13:03 -0700 Subject: [PATCH 02/23] fix: handle empty strings gracefully --- src/stdlib/string.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/stdlib/string.rs b/src/stdlib/string.rs index cc4655e0..0d44c569 100644 --- a/src/stdlib/string.rs +++ b/src/stdlib/string.rs @@ -51,16 +51,16 @@ pub fn load_string<'gc>(ctx: Context<'gc>) { .clamp(0, (string.len() as usize).saturating_sub(1)); let j = if let Some(j) = j { if j >= 0 { - j.saturating_sub(1) as usize + j as usize } else { - (string.len() as i64 + j) as usize + (string.len() as i64 + j + 1) as usize } - .clamp(0, (string.len() as usize).saturating_sub(1)) } else { - string.len().saturating_sub(1) - }; + string.len() + } + .clamp(0, string.len()); - let result = if i > j { &[] } else { &string[i..=j] }; + let result = if i > j { &[] } else { &string[i..j] }; stack.replace(ctx, crate::String::from_slice(&ctx, result).into_value(ctx)); Ok(CallbackReturn::Return) }), From 8817317169cd1871e53a723c816c6e0e5a3d0206 Mon Sep 17 00:00:00 2001 From: Jengamon Date: Mon, 13 May 2024 19:17:26 -0700 Subject: [PATCH 03/23] fix: handle i correctly --- src/stdlib/string.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/stdlib/string.rs b/src/stdlib/string.rs index 0d44c569..b08202f1 100644 --- a/src/stdlib/string.rs +++ b/src/stdlib/string.rs @@ -47,8 +47,7 @@ pub fn load_string<'gc>(ctx: Context<'gc>) { i.saturating_sub(1) as usize } else { (string.len() as i64 + i) as usize - } - .clamp(0, (string.len() as usize).saturating_sub(1)); + }; let j = if let Some(j) = j { if j >= 0 { j as usize @@ -60,7 +59,11 @@ pub fn load_string<'gc>(ctx: Context<'gc>) { } .clamp(0, string.len()); - let result = if i > j { &[] } else { &string[i..j] }; + let result = if i > j || i >= string.len() { + &[] + } else { + &string[i..j] + }; stack.replace(ctx, crate::String::from_slice(&ctx, result).into_value(ctx)); Ok(CallbackReturn::Return) }), From 9666409c8c7da139d69afdacab4383e39a9d0c7e Mon Sep 17 00:00:00 2001 From: Jengamon Date: Mon, 13 May 2024 19:20:51 -0700 Subject: [PATCH 04/23] fix: update condition --- src/stdlib/string.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stdlib/string.rs b/src/stdlib/string.rs index b08202f1..129e7f7d 100644 --- a/src/stdlib/string.rs +++ b/src/stdlib/string.rs @@ -59,7 +59,7 @@ pub fn load_string<'gc>(ctx: Context<'gc>) { } .clamp(0, string.len()); - let result = if i > j || i >= string.len() { + let result = if i >= j || i >= string.len() { &[] } else { &string[i..j] From ae26c1cd1ef24640a3a78470f32bb56ede06ea63 Mon Sep 17 00:00:00 2001 From: Jengamon Date: Mon, 13 May 2024 19:24:41 -0700 Subject: [PATCH 05/23] fix: slightly more thorough test --- tests/scripts/string.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/scripts/string.lua b/tests/scripts/string.lua index ec49b7db..816a785c 100644 --- a/tests/scripts/string.lua +++ b/tests/scripts/string.lua @@ -46,7 +46,7 @@ do string.sub(48, 2) == "8" and string.sub(48, -1) == "8" and string.sub("hilo", -1, -4) == "" and - string.sub("hilo", -4, -1) == "hilo" and + string.sub("hilo", -4, 4) == "hilo" and string.sub("hilo", -4, -3) == "hi" ) end From f7dbafc75cdcbda018f8c5cd42bb2d98a9ca9052 Mon Sep 17 00:00:00 2001 From: Jengamon Date: Mon, 13 May 2024 19:30:17 -0700 Subject: [PATCH 06/23] fix: better errors --- src/stdlib/string.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/stdlib/string.rs b/src/stdlib/string.rs index 129e7f7d..470193d4 100644 --- a/src/stdlib/string.rs +++ b/src/stdlib/string.rs @@ -29,7 +29,7 @@ pub fn load_string<'gc>(ctx: Context<'gc>) { ctx, "sub", Callback::from_fn(&ctx, |ctx, _, mut stack| { - let (string, i, j) = stack.consume::<(Value, i64, Option)>(ctx)?; + let string = stack.pop_front(); let string = match string { Value::Integer(i) => i.to_string().as_bytes().to_vec(), Value::String(s) => s.as_bytes().to_vec(), @@ -43,6 +43,7 @@ pub fn load_string<'gc>(ctx: Context<'gc>) { } }; + let (i, j) = stack.consume::<(i64, Option)>(ctx)?; let i = if i >= 0 { i.saturating_sub(1) as usize } else { From d9d78a21a219d226ed68e2724a4b9a345a856cd2 Mon Sep 17 00:00:00 2001 From: Jengamon Date: Sat, 25 May 2024 21:47:36 -0700 Subject: [PATCH 07/23] Update string.rs Use saturating_add_signed to be safe --- src/stdlib/string.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stdlib/string.rs b/src/stdlib/string.rs index 470193d4..29a63bbf 100644 --- a/src/stdlib/string.rs +++ b/src/stdlib/string.rs @@ -47,13 +47,13 @@ pub fn load_string<'gc>(ctx: Context<'gc>) { let i = if i >= 0 { i.saturating_sub(1) as usize } else { - (string.len() as i64 + i) as usize + string.len().saturating_add_signed(i as isize) }; let j = if let Some(j) = j { if j >= 0 { j as usize } else { - (string.len() as i64 + j + 1) as usize + string.len().saturating_add_signed(j as isize) + 1 } } else { string.len() From 57ec6aea8524fc5d1c83954bf56aa2983920bdb9 Mon Sep 17 00:00:00 2001 From: Jengamon Date: Sat, 25 May 2024 21:48:35 -0700 Subject: [PATCH 08/23] Update string.lua add out-of-bounds test for `j` --- tests/scripts/string.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/scripts/string.lua b/tests/scripts/string.lua index 816a785c..be364cdd 100644 --- a/tests/scripts/string.lua +++ b/tests/scripts/string.lua @@ -47,7 +47,8 @@ do string.sub(48, -1) == "8" and string.sub("hilo", -1, -4) == "" and string.sub("hilo", -4, 4) == "hilo" and - string.sub("hilo", -4, -3) == "hi" + string.sub("hilo", -4, -3) == "hi" and + string.sub("hilo", -4, -6) == "" ) end From 36b28e6064fa4d611aa65a31e45923b8ae1c7362 Mon Sep 17 00:00:00 2001 From: Jengamon Date: Sat, 25 May 2024 21:57:26 -0700 Subject: [PATCH 09/23] Update string.rs Fix `j` indexing --- src/stdlib/string.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stdlib/string.rs b/src/stdlib/string.rs index 29a63bbf..18614f1f 100644 --- a/src/stdlib/string.rs +++ b/src/stdlib/string.rs @@ -53,7 +53,7 @@ pub fn load_string<'gc>(ctx: Context<'gc>) { if j >= 0 { j as usize } else { - string.len().saturating_add_signed(j as isize) + 1 + string.len().saturating_add_signed(j as isize + 1) } } else { string.len() From e5133e999770aa7fda68835b0465a6ba69e962b8 Mon Sep 17 00:00:00 2001 From: Jengamon Date: Sat, 25 May 2024 22:01:47 -0700 Subject: [PATCH 10/23] Update string.rs Fix `i == 0` case --- src/stdlib/string.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/stdlib/string.rs b/src/stdlib/string.rs index 18614f1f..0db9bcfc 100644 --- a/src/stdlib/string.rs +++ b/src/stdlib/string.rs @@ -44,8 +44,10 @@ pub fn load_string<'gc>(ctx: Context<'gc>) { }; let (i, j) = stack.consume::<(i64, Option)>(ctx)?; - let i = if i >= 0 { + let i = if i > 0 { i.saturating_sub(1) as usize + } else if i == 0 { + 0 } else { string.len().saturating_add_signed(i as isize) }; From 860de47a3342d20f95983cb74b631e74b3037b63 Mon Sep 17 00:00:00 2001 From: Jengamon Date: Sat, 25 May 2024 22:02:41 -0700 Subject: [PATCH 11/23] Update string.lua Test `i == 0` case --- tests/scripts/string.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/scripts/string.lua b/tests/scripts/string.lua index be364cdd..a31a839c 100644 --- a/tests/scripts/string.lua +++ b/tests/scripts/string.lua @@ -48,7 +48,8 @@ do string.sub("hilo", -1, -4) == "" and string.sub("hilo", -4, 4) == "hilo" and string.sub("hilo", -4, -3) == "hi" and - string.sub("hilo", -4, -6) == "" + string.sub("hilo", -4, -6) == "" and + string.sub("hilo", 0, -4) == "h" ) end From ec53e7132b939b6cce0015f86a94b1f70034fb3e Mon Sep 17 00:00:00 2001 From: Jengamon Date: Sun, 26 May 2024 07:39:02 -0700 Subject: [PATCH 12/23] Avoid `as` casting - it has weird behavior on 32-bit architectures --- src/stdlib/string.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/stdlib/string.rs b/src/stdlib/string.rs index 0db9bcfc..0405512b 100644 --- a/src/stdlib/string.rs +++ b/src/stdlib/string.rs @@ -45,17 +45,18 @@ pub fn load_string<'gc>(ctx: Context<'gc>) { let (i, j) = stack.consume::<(i64, Option)>(ctx)?; let i = if i > 0 { - i.saturating_sub(1) as usize + i.saturating_sub(1).try_into()? } else if i == 0 { 0 } else { - string.len().saturating_add_signed(i as isize) + string.len().saturating_add_signed(i.try_into()?) }; let j = if let Some(j) = j { if j >= 0 { - j as usize + j.try_into()? } else { - string.len().saturating_add_signed(j as isize + 1) + let j: isize = j.try_into()?; + string.len().saturating_add_signed(j + 1) } } else { string.len() From cb84ec3eb65c4124d6abaf80e703f460576446d0 Mon Sep 17 00:00:00 2001 From: Jengamon Date: Mon, 27 May 2024 07:43:54 -0700 Subject: [PATCH 13/23] Fix comments ... poking at stuff without a dev env is "*fun*" --- src/stdlib/string.rs | 60 +++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/src/stdlib/string.rs b/src/stdlib/string.rs index 0405512b..ede3cf8c 100644 --- a/src/stdlib/string.rs +++ b/src/stdlib/string.rs @@ -29,10 +29,39 @@ pub fn load_string<'gc>(ctx: Context<'gc>) { ctx, "sub", Callback::from_fn(&ctx, |ctx, _, mut stack| { + fn operate_sub<'a>(string: &'a [u8], i: i64, j: Option) -> Result<&'a [u8], std::num::TryFromIntError> { + let i = if i > 0 { + i.saturating_sub(1).try_into()? + } else if i == 0 { + 0 + } else { + string.len().saturating_add_signed(i.try_into()?) + }; + let j = if let Some(j) = j { + if j >= 0 { + j.try_into()? + } else { + let j: isize = j.try_into()?; + string.len().saturating_add_signed(j + 1) + } + } else { + string.len() + } + .clamp(0, string.len()); + + return Ok(if i >= j || i >= string.len() { + &[] + } else { + &string[i..j] + }) + } + let string = stack.pop_front(); + let (i, j) = stack.consume::<(i64, Option)>(ctx)?; let string = match string { - Value::Integer(i) => i.to_string().as_bytes().to_vec(), - Value::String(s) => s.as_bytes().to_vec(), + Value::Integer(i) => ctx.intern(operate_sub(i.to_string().as_bytes(), i, j)?), + Value::Number(n) => ctx.intern(operate_sub(n.to_string().as_bytes(), i, j)?), + Value::String(s) => ctx.intern(operate_sub(s.as_bytes(), i, j)?), v => { return Err(format!( "Bad argument to sub: expected string, got {}", @@ -43,32 +72,7 @@ pub fn load_string<'gc>(ctx: Context<'gc>) { } }; - let (i, j) = stack.consume::<(i64, Option)>(ctx)?; - let i = if i > 0 { - i.saturating_sub(1).try_into()? - } else if i == 0 { - 0 - } else { - string.len().saturating_add_signed(i.try_into()?) - }; - let j = if let Some(j) = j { - if j >= 0 { - j.try_into()? - } else { - let j: isize = j.try_into()?; - string.len().saturating_add_signed(j + 1) - } - } else { - string.len() - } - .clamp(0, string.len()); - - let result = if i >= j || i >= string.len() { - &[] - } else { - &string[i..j] - }; - stack.replace(ctx, crate::String::from_slice(&ctx, result).into_value(ctx)); + stack.replace(ctx, string); Ok(CallbackReturn::Return) }), ) From c699a98ebe86a0d5292e604737447da0cc095673 Mon Sep 17 00:00:00 2001 From: Jengamon Date: Mon, 27 May 2024 07:45:32 -0700 Subject: [PATCH 14/23] Update string.lua Add Number test --- tests/scripts/string.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/scripts/string.lua b/tests/scripts/string.lua index a31a839c..450c6850 100644 --- a/tests/scripts/string.lua +++ b/tests/scripts/string.lua @@ -49,7 +49,8 @@ do string.sub("hilo", -4, 4) == "hilo" and string.sub("hilo", -4, -3) == "hi" and string.sub("hilo", -4, -6) == "" and - string.sub("hilo", 0, -4) == "h" + string.sub("hilo", 0, -4) == "h" and + string.sub(3.4, 1, 2) == "3." ) end From 352bd10d0e5f48bc56e69cf07818742d289d1007 Mon Sep 17 00:00:00 2001 From: Jengamon Date: Mon, 27 May 2024 07:48:12 -0700 Subject: [PATCH 15/23] Format code --- src/stdlib/string.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/stdlib/string.rs b/src/stdlib/string.rs index ede3cf8c..3d650cbc 100644 --- a/src/stdlib/string.rs +++ b/src/stdlib/string.rs @@ -29,7 +29,11 @@ pub fn load_string<'gc>(ctx: Context<'gc>) { ctx, "sub", Callback::from_fn(&ctx, |ctx, _, mut stack| { - fn operate_sub<'a>(string: &'a [u8], i: i64, j: Option) -> Result<&'a [u8], std::num::TryFromIntError> { + fn operate_sub<'a>( + string: &'a [u8], + i: i64, + j: Option, + ) -> Result<&'a [u8], std::num::TryFromIntError> { let i = if i > 0 { i.saturating_sub(1).try_into()? } else if i == 0 { @@ -48,12 +52,12 @@ pub fn load_string<'gc>(ctx: Context<'gc>) { string.len() } .clamp(0, string.len()); - + return Ok(if i >= j || i >= string.len() { &[] } else { &string[i..j] - }) + }); } let string = stack.pop_front(); From 25e4198cf905fc47ac5c2d3912dafe7116f5a921 Mon Sep 17 00:00:00 2001 From: Jengamon Date: Mon, 27 May 2024 07:49:54 -0700 Subject: [PATCH 16/23] whitespace my frenemy --- src/stdlib/string.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stdlib/string.rs b/src/stdlib/string.rs index 3d650cbc..15e40d81 100644 --- a/src/stdlib/string.rs +++ b/src/stdlib/string.rs @@ -52,7 +52,7 @@ pub fn load_string<'gc>(ctx: Context<'gc>) { string.len() } .clamp(0, string.len()); - + return Ok(if i >= j || i >= string.len() { &[] } else { From 0d0e1969b392cb6545347d158862d9c4fafcbe8c Mon Sep 17 00:00:00 2001 From: Jengamon O Date: Mon, 27 May 2024 15:05:55 +0000 Subject: [PATCH 17/23] Names bit me --- src/stdlib/string.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/stdlib/string.rs b/src/stdlib/string.rs index 15e40d81..ac52f9b3 100644 --- a/src/stdlib/string.rs +++ b/src/stdlib/string.rs @@ -34,6 +34,7 @@ pub fn load_string<'gc>(ctx: Context<'gc>) { i: i64, j: Option, ) -> Result<&'a [u8], std::num::TryFromIntError> { + dbg!(i, j); let i = if i > 0 { i.saturating_sub(1).try_into()? } else if i == 0 { @@ -63,9 +64,9 @@ pub fn load_string<'gc>(ctx: Context<'gc>) { let string = stack.pop_front(); let (i, j) = stack.consume::<(i64, Option)>(ctx)?; let string = match string { - Value::Integer(i) => ctx.intern(operate_sub(i.to_string().as_bytes(), i, j)?), - Value::Number(n) => ctx.intern(operate_sub(n.to_string().as_bytes(), i, j)?), - Value::String(s) => ctx.intern(operate_sub(s.as_bytes(), i, j)?), + Value::Integer(int) => ctx.intern(operate_sub(int.to_string().as_bytes(), i, j)?), + Value::Number(num) => ctx.intern(operate_sub(num.to_string().as_bytes(), i, j)?), + Value::String(string) => ctx.intern(operate_sub(string.as_bytes(), i, j)?), v => { return Err(format!( "Bad argument to sub: expected string, got {}", From 118f726f8fe2147d1f06b8132e76a0ecb0b9f67a Mon Sep 17 00:00:00 2001 From: Jengamon Date: Mon, 27 May 2024 08:08:06 -0700 Subject: [PATCH 18/23] oops --- src/stdlib/string.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/stdlib/string.rs b/src/stdlib/string.rs index ac52f9b3..ce873bb7 100644 --- a/src/stdlib/string.rs +++ b/src/stdlib/string.rs @@ -34,7 +34,6 @@ pub fn load_string<'gc>(ctx: Context<'gc>) { i: i64, j: Option, ) -> Result<&'a [u8], std::num::TryFromIntError> { - dbg!(i, j); let i = if i > 0 { i.saturating_sub(1).try_into()? } else if i == 0 { From 3f4d20696898c4633fde30303516e8a69f469c1d Mon Sep 17 00:00:00 2001 From: Jengamon Date: Mon, 27 May 2024 08:09:08 -0700 Subject: [PATCH 19/23] More formatting --- src/stdlib/string.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/stdlib/string.rs b/src/stdlib/string.rs index ce873bb7..84f04f0b 100644 --- a/src/stdlib/string.rs +++ b/src/stdlib/string.rs @@ -63,8 +63,12 @@ pub fn load_string<'gc>(ctx: Context<'gc>) { let string = stack.pop_front(); let (i, j) = stack.consume::<(i64, Option)>(ctx)?; let string = match string { - Value::Integer(int) => ctx.intern(operate_sub(int.to_string().as_bytes(), i, j)?), - Value::Number(num) => ctx.intern(operate_sub(num.to_string().as_bytes(), i, j)?), + Value::Integer(int) => { + ctx.intern(operate_sub(int.to_string().as_bytes(), i, j)?) + }, + Value::Number(num) => { + ctx.intern(operate_sub(num.to_string().as_bytes(), i, j)?) + }, Value::String(string) => ctx.intern(operate_sub(string.as_bytes(), i, j)?), v => { return Err(format!( From 3d1c42c2d1daf4c0645bf1b3a39d459d7eccc220 Mon Sep 17 00:00:00 2001 From: Jengamon Date: Mon, 27 May 2024 08:11:37 -0700 Subject: [PATCH 20/23] format and simplify --- src/stdlib/string.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/stdlib/string.rs b/src/stdlib/string.rs index 84f04f0b..9c58d4c3 100644 --- a/src/stdlib/string.rs +++ b/src/stdlib/string.rs @@ -60,15 +60,14 @@ pub fn load_string<'gc>(ctx: Context<'gc>) { }); } - let string = stack.pop_front(); - let (i, j) = stack.consume::<(i64, Option)>(ctx)?; + let (string, i, j) = stack.consume::<(Value, i64, Option)>(ctx)?; let string = match string { Value::Integer(int) => { ctx.intern(operate_sub(int.to_string().as_bytes(), i, j)?) - }, + } Value::Number(num) => { ctx.intern(operate_sub(num.to_string().as_bytes(), i, j)?) - }, + } Value::String(string) => ctx.intern(operate_sub(string.as_bytes(), i, j)?), v => { return Err(format!( From 9754b5f8abb69e00e4cc65ff7f349f11b66210b2 Mon Sep 17 00:00:00 2001 From: Jengamon Date: Mon, 27 May 2024 08:28:49 -0700 Subject: [PATCH 21/23] Work for a larger negative range - by casting from u64 (i64 and i64::MIN negated) -> usize, rather than i64 -> isize --- src/stdlib/string.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/stdlib/string.rs b/src/stdlib/string.rs index 9c58d4c3..e8f3a756 100644 --- a/src/stdlib/string.rs +++ b/src/stdlib/string.rs @@ -39,14 +39,16 @@ pub fn load_string<'gc>(ctx: Context<'gc>) { } else if i == 0 { 0 } else { - string.len().saturating_add_signed(i.try_into()?) + // we abs_diff rather than abs so that all possible numbers *including* + // i64::MIN are accounted for (as abs_diff returns a u64) + string.len().saturating_sub(i.abs_diff(0).try_into()?) }; let j = if let Some(j) = j { if j >= 0 { j.try_into()? } else { - let j: isize = j.try_into()?; - string.len().saturating_add_signed(j + 1) + let j: usize = j.abs_diff(0).try_into()?; + string.len().saturating_sub(j.saturating_sub(1)) } } else { string.len() From e0d2159c70f6ff2e76e27acb1adab796513cc3d4 Mon Sep 17 00:00:00 2001 From: Jengamon Date: Mon, 27 May 2024 12:13:57 -0700 Subject: [PATCH 22/23] Use i64::unsigned_abs forgot i used it for `select` impl... --- src/stdlib/string.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/stdlib/string.rs b/src/stdlib/string.rs index e8f3a756..0c2b8d53 100644 --- a/src/stdlib/string.rs +++ b/src/stdlib/string.rs @@ -39,15 +39,13 @@ pub fn load_string<'gc>(ctx: Context<'gc>) { } else if i == 0 { 0 } else { - // we abs_diff rather than abs so that all possible numbers *including* - // i64::MIN are accounted for (as abs_diff returns a u64) - string.len().saturating_sub(i.abs_diff(0).try_into()?) + string.len().saturating_sub(i.unsigned_abs().try_into()?) }; let j = if let Some(j) = j { if j >= 0 { j.try_into()? } else { - let j: usize = j.abs_diff(0).try_into()?; + let j: usize = j.unsigned_abs().try_into()?; string.len().saturating_sub(j.saturating_sub(1)) } } else { From db93189b6a1b2a0f9997b77165bff776d44147a4 Mon Sep 17 00:00:00 2001 From: Jengamon Date: Thu, 30 May 2024 06:54:11 -0700 Subject: [PATCH 23/23] Update COMPATIBILITY.md --- COMPATIBILITY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/COMPATIBILITY.md b/COMPATIBILITY.md index ec684538..7bc7d3aa 100644 --- a/COMPATIBILITY.md +++ b/COMPATIBILITY.md @@ -115,7 +115,7 @@ likely not be implemented due to differences between piccolo and PUC-Lua. | ⚫️️ | `packsize(fmt)` | | | | ⚫️️ | `rep(s, n[, sep])` | | | | ⚫️️ | `reverse(s)` | | | -| ⚫️️ | `sub(s, i[, j])` | | | +| 🔵 | `sub(s, i[, j])` | | | | ⚫️️ | `unpack(fmt, s[, pos])` | | | | ⚫️️ | `upper(s)` | | |