handle large integers in builtin string functions

This commit is contained in:
ConnorSkees 2020-03-23 13:57:00 -04:00
parent 795c8bdb05
commit f4f9a79b2b
3 changed files with 99 additions and 82 deletions

View File

@ -76,7 +76,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
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<String, Builtin>) {
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<String, Builtin>) {
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<String, Builtin>) {
"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<String, Builtin>) {
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<String, Builtin>) {
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 {

View File

@ -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),
},

View File

@ -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"
);