diff --git a/crates/haku-wasm/src/lib.rs b/crates/haku-wasm/src/lib.rs index 78c13ac..3a4cb6f 100644 --- a/crates/haku-wasm/src/lib.rs +++ b/crates/haku-wasm/src/lib.rs @@ -220,6 +220,7 @@ enum StatusCode { SourceCodeTooLong, TooManyTokens, TooManyAstNodes, + TooManyParserEvents, ParserUnbalancedEvents, ChunkTooBig, DiagnosticsEmitted, @@ -254,6 +255,7 @@ extern "C" fn haku_status_string(code: StatusCode) -> *const i8 { StatusCode::SourceCodeTooLong => c"source code is too long", StatusCode::TooManyTokens => c"source code has too many tokens", StatusCode::TooManyAstNodes => c"source code has too many AST nodes", + StatusCode::TooManyParserEvents => c"source code has too many parser events", StatusCode::ParserUnbalancedEvents => c"parser produced unbalanced events", StatusCode::ChunkTooBig => c"compiled bytecode is too large", StatusCode::DiagnosticsEmitted => c"diagnostics were emitted", @@ -365,6 +367,10 @@ unsafe extern "C" fn haku_compile_brush( info!("compiling failed: too many AST nodes"); return StatusCode::TooManyAstNodes; } + Err(IntoAstError::TooManyEvents) => { + info!("compiling failed: too many parser events"); + return StatusCode::TooManyParserEvents; + } Err(IntoAstError::UnbalancedEvents) => { info!("compiling failed: parser produced unbalanced events"); return StatusCode::ParserUnbalancedEvents; diff --git a/crates/haku/src/parser.rs b/crates/haku/src/parser.rs index 3d9ea09..3dce27a 100644 --- a/crates/haku/src/parser.rs +++ b/crates/haku/src/parser.rs @@ -52,7 +52,9 @@ impl<'a> Parser<'a> { Self { tokens: input, - events: Vec::with_capacity(limits.max_events), + // Add one event to the capacity, because that makes it easier to detect when we ran out + // of space. (No need to store flags or anything, just check if events are at capacity.) + events: Vec::with_capacity(limits.max_events + 1), position: 0, diagnostics: Vec::with_capacity(16), fuel: Cell::new(Self::FUEL), @@ -153,6 +155,11 @@ impl<'a> Parser<'a> { } pub fn into_ast(self, ast: &mut Ast) -> Result<(NodeId, Vec), IntoAstError> { + // If events are at capacity, that means the pool was exhausted and we return an error. + if self.events.len() == self.events.capacity() { + return Err(IntoAstError::TooManyEvents); + } + let mut token = 0; let mut events = self.events; let mut stack = Vec::new(); @@ -260,6 +267,7 @@ impl fmt::Debug for Event { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum IntoAstError { NodeAlloc(NodeAllocError), + TooManyEvents, UnbalancedEvents, } @@ -273,6 +281,7 @@ impl fmt::Display for IntoAstError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { IntoAstError::NodeAlloc(e) => fmt::Display::fmt(e, f), + IntoAstError::TooManyEvents => f.write_str("too many parser events"), IntoAstError::UnbalancedEvents => f.write_str("parser produced unbalanced events"), } }