Skip to content

Commit

Permalink
catch subscripts being too large
Browse files Browse the repository at this point in the history
  • Loading branch information
kaikalii committed Nov 24, 2024
1 parent e00d6be commit 63e3d8f
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 34 deletions.
12 changes: 4 additions & 8 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,8 @@ pub enum Subscript {
NegOnly,
/// A number
N(i32),
/// The subscript is too large
TooLarge,
}

impl Subscript {
Expand All @@ -667,20 +669,14 @@ impl fmt::Display for Subscript {
}
Ok(())
}
Subscript::TooLarge => write!(f, "…"),
}
}
}

impl Subscripted {
/// Get the subscript as a string
pub fn n_string(&self) -> String {
self.n.value.to_string()
}
}

impl fmt::Debug for Subscripted {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.word.value.fmt(f)?;
write!(f, "{}", self.n_string())
write!(f, "{}", self.n.value)
}
}
4 changes: 4 additions & 0 deletions src/compile/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1821,6 +1821,10 @@ code:
self.add_error(span.clone(), "Subscript is incomplete");
None
}
Subscript::TooLarge => {
self.add_error(span.clone(), "Subscript is too large");
None
}
}
}
fn positive_subscript(&mut self, n: i32, prim: Primitive, span: CodeSpan) -> UiuaResult<usize> {
Expand Down
12 changes: 9 additions & 3 deletions src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1131,19 +1131,19 @@ impl<'a> Formatter<'a> {
Word::Subscripted(sub) => match &sub.word.value {
Word::Modified(m) => {
self.format_modifier(&m.modifier, depth);
self.push(&sub.n.span, &sub.n_string());
self.subscript(&sub.n);
self.format_words(&m.operands, true, depth);
}
Word::Primitive(Primitive::Utf8) => {
self.push(&sub.word.span, "utf");
self.push(&sub.n.span, &sub.n_string());
self.subscript(&sub.n);
}
_ => {
self.format_word(&sub.word, depth);
if self.output.ends_with(SUBSCRIPT_DIGITS) {
self.output.push(' ');
}
self.push(&sub.n.span, &sub.n_string());
self.subscript(&sub.n);
}
},
Word::Spaces => self.push(&word.span, " "),
Expand Down Expand Up @@ -1437,6 +1437,12 @@ impl<'a> Formatter<'a> {
self.format_multiline_words(&func.lines, allow_compact, true, true, true, depth + 1);
self.output.push(')');
}
fn subscript(&mut self, sub: &Sp<Subscript>) {
match &sub.value {
Subscript::TooLarge => sub.span.as_str(self.inputs, |s| self.push(&sub.span, s)),
_ => self.push(&sub.span, &sub.value.to_string()),
}
}
}

fn words_are_multiline(words: &[Sp<Word>]) -> bool {
Expand Down
55 changes: 32 additions & 23 deletions src/lex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -929,6 +929,7 @@ impl<'a> Lexer<'a> {
let neg = self.next_char_exact("₋")
|| self.next_char_exact("`")
|| self.next_char_exact("¯");
let mut overflow = false;
loop {
if let Some(c) = self.next_char_if_all(|c| c.is_ascii_digit()) {
let n = n.get_or_insert(0);
Expand All @@ -938,18 +939,17 @@ impl<'a> Lexer<'a> {
{
let c = c.chars().next().unwrap();
let n = n.get_or_insert(0);
*n = *n * 10
+ SUBSCRIPT_DIGITS.iter().position(|&d| d == c).unwrap() as i32;
let (m, over_m) = n.overflowing_mul(10);
let (a, over_a) = m.overflowing_add(
SUBSCRIPT_DIGITS.iter().position(|&d| d == c).unwrap() as i32,
);
overflow |= over_m | over_a;
*n = a;
} else {
break;
}
}
let sub = match (neg, n) {
(false, None) => Subscript::Empty,
(true, None) => Subscript::NegOnly,
(false, Some(n)) => Subscript::N(n),
(true, Some(n)) => Subscript::N(-n),
};
let sub = pick_subscript(neg, n, overflow);
self.end(Subscr(sub), start)
} else {
self.end(Underscore, start)
Expand Down Expand Up @@ -1162,17 +1162,16 @@ impl<'a> Lexer<'a> {
}
}
let mut n: Option<i32> = None;
let mut overflow = false;
for c in s.chars() {
let i = SUBSCRIPT_DIGITS.iter().position(|&d| d == c).unwrap() as i32;
let n = n.get_or_insert(0);
*n = *n * 10 + i;
let (m, over_m) = n.overflowing_mul(10);
let (a, over_a) = m.overflowing_add(i);
overflow |= over_m | over_a;
*n = a;
}
let sub = match (neg, n) {
(false, None) => Subscript::Empty,
(true, None) => Subscript::NegOnly,
(false, Some(n)) => Subscript::N(n),
(true, Some(n)) => Subscript::N(-n),
};
let sub = pick_subscript(neg, n, overflow);
self.end(Subscr(sub), start)
}
// Identifiers and unformatted glyphs
Expand Down Expand Up @@ -1590,18 +1589,16 @@ fn subscript(s: &str) -> Option<Subscript> {
chars.next();
}
let mut n: Option<i32> = None;
let mut overflow = false;
for c in chars {
let i = SUBSCRIPT_DIGITS.iter().position(|&d| c == d)? as i32;
let n = n.get_or_insert(0);
*n *= 10;
*n += i;
let (m, over_m) = n.overflowing_mul(10);
let (a, over_a) = m.overflowing_add(i);
overflow |= over_m | over_a;
*n = a;
}
Some(match (neg, n) {
(false, None) => Subscript::Empty,
(true, None) => Subscript::NegOnly,
(false, Some(n)) => Subscript::N(n),
(true, Some(n)) => Subscript::N(-n),
})
Some(pick_subscript(neg, n, overflow))
}

/// Whether a string is a custom glyph
Expand Down Expand Up @@ -1660,3 +1657,15 @@ fn canonicalize_subscripts(ident: &str) -> Ident {
})
.collect()
}

fn pick_subscript(neg: bool, n: Option<i32>, overflow: bool) -> Subscript {
if overflow {
return Subscript::TooLarge;
}
match (neg, n) {
(false, None) => Subscript::Empty,
(true, None) => Subscript::NegOnly,
(false, Some(n)) => Subscript::N(n),
(true, Some(n)) => Subscript::N(-n),
}
}

0 comments on commit 63e3d8f

Please sign in to comment.