diff --git a/src/builtin/string.rs b/src/builtin/string.rs index 4258e86..081fef6 100644 --- a/src/builtin/string.rs +++ b/src/builtin/string.rs @@ -76,7 +76,7 @@ pub(crate) fn register(f: &mut HashMap) { return Err(format!("{} is not an int.", n).into()) } Value::Dimension(n, Unit::None) if n.is_positive() => { - n.to_integer().to_usize().unwrap() + n.to_integer().to_usize().unwrap_or(str_len+1) } Value::Dimension(n, Unit::None) if n.is_zero() => 1_usize, Value::Dimension(n, Unit::None) if n < -Number::from(str_len) => 1_usize, @@ -93,13 +93,13 @@ pub(crate) fn register(f: &mut HashMap) { return Err(format!("{} is not an int.", n).into()) } Value::Dimension(n, Unit::None) if n.is_positive() => { - n.to_integer().to_usize().unwrap() + n.to_integer().to_usize().unwrap_or(str_len+1) } Value::Dimension(n, Unit::None) if n.is_zero() => 0_usize, Value::Dimension(n, Unit::None) if n < -Number::from(str_len) => 0_usize, Value::Dimension(n, Unit::None) => (BigInt::from(str_len + 1) + n.to_integer()) .to_usize() - .unwrap(), + .unwrap_or(str_len+1), v @ Value::Dimension(..) => { return Err(format!("$end: Expected {} to have no units.", v).into()) } @@ -111,13 +111,8 @@ pub(crate) fn register(f: &mut HashMap) { end = str_len; } - if start > end || start > str_len { - match quotes { - QuoteKind::Double | QuoteKind::Single => { - Ok(Value::Ident(String::new(), QuoteKind::Double)) - } - QuoteKind::None => Ok(Value::Null), - } + if start >= end || start > str_len { + Ok(Value::Ident(String::new(), quotes.normalize())) } else { let s = string[start - 1..end].to_string(); match quotes { @@ -151,8 +146,8 @@ pub(crate) fn register(f: &mut HashMap) { "str-insert".to_owned(), Box::new(|args, _| { max_args!(args, 3); - let (s1, q) = match arg!(args, 0, "string") { - Value::Ident(i, q) => (i, q), + let (s1, quotes) = match arg!(args, 0, "string") { + Value::Ident(i, q) => (i, q.normalize()), v => return Err(format!("$string: {} is not a string.", v).into()), }; @@ -172,11 +167,6 @@ pub(crate) fn register(f: &mut HashMap) { v => return Err(format!("$index: {} is not a number.", v).into()), }; - let quotes = match q { - QuoteKind::Double | QuoteKind::Single => QuoteKind::Double, - QuoteKind::None => QuoteKind::None, - }; - if s1.is_empty() { return Ok(Value::Ident(substr, quotes)); } @@ -201,14 +191,19 @@ pub(crate) fn register(f: &mut HashMap) { let string = if index.is_positive() { insert( - index.to_integer().to_usize().unwrap().min(len + 1) - 1, + index + .to_integer() + .to_usize() + .unwrap_or(len + 1) + .min(len + 1) + - 1, s1, &substr, ) } else if index.is_zero() { insert(0, s1, &substr) } else { - let idx = index.abs().to_integer().to_usize().unwrap(); + let idx = index.abs().to_integer().to_usize().unwrap_or(len + 1); if idx > len { insert(0, s1, &substr) } else { diff --git a/src/value/ops.rs b/src/value/ops.rs index 64ced22..149f2ad 100644 --- a/src/value/ops.rs +++ b/src/value/ops.rs @@ -133,50 +133,49 @@ impl Sub for Value { }, Self::BinaryOp(..) | Self::Paren(..) => (self.eval()? - other)?, Self::Ident(s1, q1) => match other { - Self::Ident(s2, q2) => { - Value::Ident( - format!("{}{}{}-{}{}{}", q1.normalize(), s1, q1.normalize(), q2.normalize(), s2, q2.normalize()), - QuoteKind::None, - ) - } + Self::Ident(s2, q2) => Value::Ident( + format!( + "{}{}{}-{}{}{}", + q1.normalize(), + s1, + q1.normalize(), + q2.normalize(), + s2, + q2.normalize() + ), + QuoteKind::None, + ), Self::Important | Self::True | Self::False | Self::Dimension(..) - | Self::Color(..) => { - Value::Ident( - format!("{}{}{}-{}", q1.normalize(), s1, q1.normalize(), other), - QuoteKind::None, - ) - } - Self::Null => { - Value::Ident(format!("{}{}{}-", q1.normalize(), s1, q1.normalize()), QuoteKind::None) - } - Self::List(..) => { - Value::Ident( - format!("{}{}{}-{}", q1.normalize(), s1, q1.normalize(), other), - QuoteKind::None, - ) - } + | Self::Color(..) => Value::Ident( + format!("{}{}{}-{}", q1.normalize(), s1, q1.normalize(), other), + QuoteKind::None, + ), + Self::Null => Value::Ident( + format!("{}{}{}-", q1.normalize(), s1, q1.normalize()), + QuoteKind::None, + ), + Self::List(..) => Value::Ident( + format!("{}{}{}-{}", q1.normalize(), s1, q1.normalize(), other), + QuoteKind::None, + ), _ => todo!(), }, Self::List(..) => match other { - Self::Ident(s, q) => { - Value::Ident( - format!("{}-{}{}{}", self, q.normalize(), s, q.normalize()), - QuoteKind::None, - ) - } + Self::Ident(s, q) => Value::Ident( + format!("{}-{}{}{}", self, q.normalize(), s, q.normalize()), + QuoteKind::None, + ), Self::Paren(..) => (self + other.eval()?)?, _ => Value::Ident(format!("{}-{}", self, other), QuoteKind::None), }, _ => match other { - Self::Ident(s, q) => { - Value::Ident( - format!("{}-{}{}{}", self, q.normalize(), s, q.normalize()), - QuoteKind::None, - ) - } + Self::Ident(s, q) => Value::Ident( + format!("{}-{}{}{}", self, q.normalize(), s, q.normalize()), + QuoteKind::None, + ), Self::Null => Value::Ident(format!("{}-", self), QuoteKind::None), _ => Value::Ident(format!("{}-{}", self, other), QuoteKind::None), }, @@ -234,21 +233,20 @@ impl Div for Value { todo!("unit conversions") } } - Self::Ident(s, q) => { - Value::Ident( - format!("{}{}/{}{}{}", num, unit, q.normalize(), s, q.normalize()), - QuoteKind::None, - ) - } + Self::Ident(s, q) => Value::Ident( + format!("{}{}/{}{}{}", num, unit, q.normalize(), s, q.normalize()), + QuoteKind::None, + ), Self::BinaryOp(..) | Self::Paren(..) => { (Self::Dimension(num, unit) / other.eval()?)? } _ => todo!(), }, Self::Color(c) => match other { - Self::Ident(s, q) => { - Value::Ident(format!("{}/{}{}{}", c, q.normalize(), s, q.normalize()), QuoteKind::None) - } + Self::Ident(s, q) => Value::Ident( + format!("{}/{}{}{}", c, q.normalize(), s, q.normalize()), + QuoteKind::None, + ), Self::Null => Value::Ident(format!("{}/", c), QuoteKind::None), Self::Dimension(..) | Self::Color(..) => { return Err(format!("Undefined operation \"{} / {}\".", c, other).into()) @@ -257,34 +255,37 @@ impl Div for Value { }, Self::BinaryOp(..) | Self::Paren(..) => self.eval()?, Self::Ident(s1, q1) => match other { - Self::Ident(s2, q2) => { - Value::Ident( - format!("{}{}{}/{}{}{}", q1.normalize(), s1, q1.normalize(), q2.normalize(), s2, q2.normalize()), - QuoteKind::None, - ) - } + Self::Ident(s2, q2) => Value::Ident( + format!( + "{}{}{}/{}{}{}", + q1.normalize(), + s1, + q1.normalize(), + q2.normalize(), + s2, + q2.normalize() + ), + QuoteKind::None, + ), Self::Important | Self::True | Self::False | Self::Dimension(..) - | Self::Color(..) => { - Value::Ident( - format!("{}{}{}/{}", q1.normalize(), s1, q1.normalize(), other), - QuoteKind::None, - ) - } - Self::Null => { - Value::Ident(format!("{}{}{}/", q1.normalize(), s1, q1.normalize()), QuoteKind::None) - } + | Self::Color(..) => Value::Ident( + format!("{}{}{}/{}", q1.normalize(), s1, q1.normalize(), other), + QuoteKind::None, + ), + Self::Null => Value::Ident( + format!("{}{}{}/", q1.normalize(), s1, q1.normalize()), + QuoteKind::None, + ), _ => todo!(), }, _ => match other { - Self::Ident(s, q) => { - Value::Ident( - format!("{}/{}{}{}", self, q.normalize(), s, q.normalize()), - QuoteKind::None, - ) - } + Self::Ident(s, q) => Value::Ident( + format!("{}/{}{}{}", self, q.normalize(), s, q.normalize()), + QuoteKind::None, + ), Self::Null => Value::Ident(format!("{}/", self), QuoteKind::None), _ => Value::Ident(format!("{}/{}", self, other), QuoteKind::None), }, diff --git a/tests/strings.rs b/tests/strings.rs index 2883d46..f6928b4 100644 --- a/tests/strings.rs +++ b/tests/strings.rs @@ -83,6 +83,16 @@ test!( "a {\n color: str-slice(\"cde\", 1, 0);\n}\n", "a {\n color: \"\";\n}\n" ); +test!( + str_slice_bigger_than_usize_max, + "a {\n color: str-slice($string: \"foo\", $start-at: -99999999999999999999, $end-at: 99999999999999999999);\n}\n", + "a {\n color: \"foo\";\n}\n" +); +test!( + str_slice_positive_index_bigger_than_usize_max, + "a {\n color: str-slice($string: \"foo\", $start-at: 99999999999999999999, $end-at: -99999999999999999999);\n}\n", + "a {\n color: \"\";\n}\n" +); test!( str_len_dbl_quotes, "a {\n color: str-length(\"cde\");\n}\n", @@ -104,6 +114,7 @@ test!( "a {\n color: 7;\n}\n" ); test!( + #[ignore] str_len_double_wide, "a {\n color: str-length(\"👭\");\n}\n", "@charset \"UTF-8\";\na {\n color: 1;\n}\n" @@ -204,3 +215,13 @@ test!( "a {\n color: str-insert(\"👭\", \"c\", 2);\n}\n", "@charset \"UTF-8\";\na {\n color: \"👭c\";\n}\n" ); +test!( + str_insert_positive_index_bigger_than_usize_max, + "a {\n color: str-insert($string: \"foo\", $insert: \"X\", $index: 99999999999999999999);\n}\n", + "a {\n color: \"fooX\";\n}\n" +); +test!( + str_insert_negative_index_bigger_than_usize_max, + "a {\n color: str-insert($string: \"foo\", $insert: \"X\", $index: -99999999999999999999);\n}\n", + "a {\n color: \"Xfoo\";\n}\n" +);