From d058919ed2e194ce94e27cae5404df871ecc6f12 Mon Sep 17 00:00:00 2001 From: Kai Schmidt Date: Sat, 15 Jun 2024 12:51:54 -0700 Subject: [PATCH] add a recursion limit to parser --- src/parse.rs | 21 ++++++++++++++++++++- todo.md | 1 + 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/parse.rs b/src/parse.rs index a3b4e96b..79cc7691 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -26,6 +26,7 @@ pub enum ParseError { SplitInModifier, UnsplitInModifier, LineTooLong(usize), + RecursionLimit, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -100,6 +101,7 @@ impl fmt::Display for ParseError { "Split line into multiple lines (heuristic: {}/{}) 😏", width, ERROR_MAX_WIDTH ), + ParseError::RecursionLimit => write!(f, "Parsing recursion limit reached"), } } } @@ -197,6 +199,7 @@ pub fn parse( errors, diagnostics, next_output_comment: 0, + depth: 0, }; let items = parser.items(true); if parser.errors.is_empty() && parser.index < parser.tokens.len() { @@ -207,7 +210,15 @@ pub fn parse( .map(ParseError::Unexpected), ); } - (items, parser.errors, parser.diagnostics) + let mut errors = parser.errors; + if let Some(error) = errors + .iter() + .find(|e| matches!(e.value, ParseError::RecursionLimit)) + { + let error = error.clone(); + errors = vec![error]; + } + (items, errors, parser.diagnostics) } parse(input, inputs, tokens, lex_errors, src) } @@ -220,6 +231,7 @@ struct Parser<'i> { next_output_comment: usize, errors: Vec>, diagnostics: Vec, + depth: usize, } type FunctionContents = (Option>, Vec>>, Option); @@ -732,6 +744,11 @@ impl<'i> Parser<'i> { Some(span.sp(make(items))) } fn try_modified(&mut self) -> Option> { + if self.depth > 50 { + self.errors + .push(self.prev_span().sp(ParseError::RecursionLimit)); + return None; + } let (modifier, mod_span) = if let Some(prim) = Primitive::all() .filter(|prim| prim.is_modifier()) .find_map(|prim| { @@ -756,6 +773,7 @@ impl<'i> Parser<'i> { }; let mut args = Vec::new(); self.try_spaces(); + self.depth += 1; for i in 0..modifier.args() { loop { args.extend(self.try_spaces()); @@ -782,6 +800,7 @@ impl<'i> Parser<'i> { break; } } + self.depth -= 1; let span = if let Some(last) = args.last() { mod_span.clone().merge(last.span.clone()) diff --git a/todo.md b/todo.md index 68a56138..44f15b4e 100644 --- a/todo.md +++ b/todo.md @@ -1,6 +1,7 @@ # Uiua Todo - 0.12 + - Don't generate inlay hints if not necessary - `setinv` on and by inverses - Document on and by inverses - Pervasive switch functions and `repeat`