1use crate::ast::*;
2use harn_lexer::{Span, Token, TokenKind};
3
4use super::error::ParserError;
5
6pub const MAX_NESTING_DEPTH: usize = 64;
9
10pub struct Parser {
12 pub(super) tokens: Vec<Token>,
13 pub(super) pos: usize,
14 pub(super) errors: Vec<ParserError>,
15 nesting_depth: usize,
16 #[cfg(test)]
17 pub(super) stack_extent: (usize, usize),
18 #[cfg(test)]
19 pub(super) deepest_nesting: usize,
20}
21
22impl Parser {
23 pub(super) fn at_module_scope(&self) -> bool {
24 self.nesting_depth == 0
25 }
26
27 pub fn new(tokens: Vec<Token>) -> Self {
28 Self {
29 tokens,
30 pos: 0,
31 errors: Vec::new(),
32 nesting_depth: 0,
33 #[cfg(test)]
34 stack_extent: (usize::MAX, 0),
35 #[cfg(test)]
36 deepest_nesting: 0,
37 }
38 }
39
40 pub(super) fn check_token_nesting_limit(&self) -> Result<(), ParserError> {
41 let mut depth = 0usize;
42 for token in &self.tokens {
43 match token.kind {
44 TokenKind::LBrace | TokenKind::LBracket | TokenKind::LParen => {
45 depth += 1;
46 if depth > MAX_NESTING_DEPTH {
47 return Err(ParserError::Unexpected {
48 got: "source nesting depth exceeded".to_string(),
49 expected: format!(
50 "parser nesting depth within {MAX_NESTING_DEPTH} levels"
51 ),
52 span: token.span,
53 });
54 }
55 }
56 TokenKind::RBrace | TokenKind::RBracket | TokenKind::RParen => {
57 depth = depth.saturating_sub(1);
58 }
59 _ => {}
60 }
61 }
62 Ok(())
63 }
64
65 pub(super) fn current_span(&self) -> Span {
66 self.tokens
67 .get(self.pos)
68 .map(|t| t.span)
69 .unwrap_or(Span::dummy())
70 }
71
72 pub(super) fn current_kind(&self) -> Option<&TokenKind> {
73 self.tokens.get(self.pos).map(|t| &t.kind)
74 }
75
76 pub(super) fn prev_span(&self) -> Span {
77 if self.pos > 0 {
78 self.tokens[self.pos - 1].span
79 } else {
80 Span::dummy()
81 }
82 }
83
84 pub(super) fn last_non_newline_span(&self) -> Span {
92 let mut i = self.pos;
93 while i > 0 {
94 i -= 1;
95 if self.tokens[i].kind != TokenKind::Newline {
96 return self.tokens[i].span;
97 }
98 }
99 Span::dummy()
100 }
101
102 pub fn parse(&mut self) -> Result<Vec<SNode>, ParserError> {
104 self.check_token_nesting_limit()?;
105
106 let mut nodes = Vec::new();
107 self.skip_newlines();
108
109 while !self.is_at_end() {
110 if self.check(&TokenKind::RBrace) {
112 self.advance();
113 self.skip_newlines();
114 continue;
115 }
116
117 let result = if self.check(&TokenKind::Import) {
118 self.parse_import()
119 } else if self.check(&TokenKind::At) {
120 self.parse_attributed_decl()
121 } else if self.check(&TokenKind::Pipeline) {
122 self.parse_pipeline()
123 } else if self.check(&TokenKind::EvalPack) {
124 self.parse_eval_pack_decl(false)
125 } else {
126 self.parse_statement()
127 };
128
129 match result {
130 Ok(node) => {
131 let end_line = node.span.end_line;
132 nodes.push(node);
133 let consumed_sep = self.consume_statement_separator();
134 if !consumed_sep && !self.is_at_end() {
135 self.require_statement_separator(end_line, "top-level item")?;
136 }
137 }
138 Err(err) => {
139 self.errors.push(err);
140 self.synchronize();
141 }
142 }
143 }
144
145 if let Some(first) = self.errors.first() {
146 return Err(first.clone());
147 }
148 Ok(nodes)
149 }
150
151 pub fn all_errors(&self) -> &[ParserError] {
153 &self.errors
154 }
155
156 pub(super) fn is_statement_start(&self) -> bool {
158 matches!(
159 self.current_kind(),
160 Some(
161 TokenKind::Let
162 | TokenKind::Const
163 | TokenKind::Var
164 | TokenKind::If
165 | TokenKind::For
166 | TokenKind::While
167 | TokenKind::Match
168 | TokenKind::Retry
169 | TokenKind::Return
170 | TokenKind::Throw
171 | TokenKind::Fn
172 | TokenKind::Pub
173 | TokenKind::Try
174 | TokenKind::Select
175 | TokenKind::Pipeline
176 | TokenKind::Import
177 | TokenKind::Parallel
178 | TokenKind::Enum
179 | TokenKind::EvalPack
180 | TokenKind::Struct
181 | TokenKind::Interface
182 | TokenKind::Emit
183 | TokenKind::Guard
184 | TokenKind::Require
185 | TokenKind::Deadline
186 | TokenKind::Yield
187 | TokenKind::Mutex
188 | TokenKind::Defer
189 | TokenKind::Break
190 | TokenKind::Continue
191 | TokenKind::Tool
192 | TokenKind::Skill
193 | TokenKind::Impl
194 )
195 )
196 }
197
198 pub(super) fn synchronize(&mut self) {
200 while !self.is_at_end() {
201 if self.check(&TokenKind::Semicolon) {
202 self.advance();
203 self.skip_newlines();
204 return;
205 }
206 if self.check(&TokenKind::Newline) {
207 self.advance();
208 if self.is_at_end() || self.is_statement_start() {
209 return;
210 }
211 continue;
212 }
213 if self.check(&TokenKind::RBrace) {
214 return;
215 }
216 self.advance();
217 }
218 }
219
220 pub(super) fn is_at_end(&self) -> bool {
221 self.pos >= self.tokens.len()
222 || matches!(self.tokens.get(self.pos), Some(t) if t.kind == TokenKind::Eof)
223 }
224
225 pub(super) fn current(&self) -> Option<&Token> {
226 self.tokens.get(self.pos)
227 }
228
229 pub(super) fn peek_kind(&self) -> Option<&TokenKind> {
230 self.tokens.get(self.pos + 1).map(|t| &t.kind)
231 }
232
233 pub(super) fn peek_kind_at(&self, offset: usize) -> Option<&TokenKind> {
234 self.tokens.get(self.pos + offset).map(|t| &t.kind)
235 }
236
237 pub(super) fn check(&self, kind: &TokenKind) -> bool {
238 self.current()
239 .map(|t| std::mem::discriminant(&t.kind) == std::mem::discriminant(kind))
240 .unwrap_or(false)
241 }
242
243 pub(super) fn check_skip_newlines(&mut self, kind: &TokenKind) -> bool {
246 let saved = self.pos;
247 self.skip_newlines();
248 if self.check(kind) {
249 true
250 } else {
251 self.pos = saved;
252 false
253 }
254 }
255
256 pub(super) fn check_identifier(&self, name: &str) -> bool {
258 matches!(self.current().map(|t| &t.kind), Some(TokenKind::Identifier(s)) if s == name)
259 }
260
261 pub(super) fn check_contextual_gen_fn(&self) -> bool {
264 if !self.check_identifier("gen") {
265 return false;
266 }
267 matches!(
268 self.tokens.get(self.pos + 1).map(|t| &t.kind),
269 Some(TokenKind::Fn)
270 )
271 }
272
273 pub(super) fn check_contextual_brace_block(&self, name: &str) -> bool {
277 if !self.check_identifier(name) {
278 return false;
279 }
280 matches!(
281 self.tokens.get(self.pos + 1).map(|t| &t.kind),
282 Some(TokenKind::LBrace)
283 )
284 }
285
286 pub(super) fn advance(&mut self) {
287 if self.pos < self.tokens.len() {
288 self.pos += 1;
289 }
290 }
291
292 pub(super) fn consume(
293 &mut self,
294 kind: &TokenKind,
295 expected: &str,
296 ) -> Result<Token, ParserError> {
297 self.skip_newlines();
298 let tok = self.current().ok_or_else(|| self.make_error(expected))?;
299 if std::mem::discriminant(&tok.kind) != std::mem::discriminant(kind) {
300 return Err(self.make_error(expected));
301 }
302 let tok = tok.clone();
303 self.advance();
304 Ok(tok)
305 }
306
307 pub(super) fn consume_identifier(&mut self, expected: &str) -> Result<String, ParserError> {
308 self.skip_newlines();
309 let tok = self.current().ok_or_else(|| self.make_error(expected))?;
310 if let TokenKind::Identifier(name) = &tok.kind {
311 let name = name.clone();
312 self.advance();
313 Ok(name)
314 } else {
315 let kw_name = harn_lexer::KEYWORDS
318 .iter()
319 .find(|&&kw| kw == tok.kind.to_string());
320 if let Some(kw) = kw_name {
321 Err(ParserError::Unexpected {
322 got: format!("'{kw}' (reserved keyword)"),
323 expected: expected.into(),
324 span: tok.span,
325 })
326 } else {
327 Err(self.make_error(expected))
328 }
329 }
330 }
331
332 pub(super) fn consume_contextual_keyword(
333 &mut self,
334 name: &str,
335 expected: &str,
336 ) -> Result<Token, ParserError> {
337 self.skip_newlines();
338 let tok = self.current().ok_or_else(|| self.make_error(expected))?;
339 if matches!(&tok.kind, TokenKind::Identifier(id) if id == name) {
340 let tok = tok.clone();
341 self.advance();
342 Ok(tok)
343 } else {
344 Err(self.make_error(expected))
345 }
346 }
347
348 pub(super) fn consume_identifier_or_keyword(
352 &mut self,
353 expected: &str,
354 ) -> Result<String, ParserError> {
355 self.skip_newlines();
356 let tok = self.current().ok_or_else(|| self.make_error(expected))?;
357 if let TokenKind::Identifier(name) = &tok.kind {
358 let name = name.clone();
359 self.advance();
360 return Ok(name);
361 }
362 let name = match &tok.kind {
363 TokenKind::Pipeline => "pipeline",
364 TokenKind::Extends => "extends",
365 TokenKind::Override => "override",
366 TokenKind::Let => "let",
367 TokenKind::Const => "const",
368 TokenKind::Var => "var",
369 TokenKind::If => "if",
370 TokenKind::Else => "else",
371 TokenKind::For => "for",
372 TokenKind::In => "in",
373 TokenKind::Match => "match",
374 TokenKind::Retry => "retry",
375 TokenKind::Parallel => "parallel",
376 TokenKind::Return => "return",
377 TokenKind::Import => "import",
378 TokenKind::True => "true",
379 TokenKind::False => "false",
380 TokenKind::Nil => "nil",
381 TokenKind::Try => "try",
382 TokenKind::Catch => "catch",
383 TokenKind::Throw => "throw",
384 TokenKind::Finally => "finally",
385 TokenKind::Fn => "fn",
386 TokenKind::Spawn => "spawn",
387 TokenKind::While => "while",
388 TokenKind::TypeKw => "type",
389 TokenKind::Enum => "enum",
390 TokenKind::EvalPack => "eval_pack",
391 TokenKind::Struct => "struct",
392 TokenKind::Interface => "interface",
393 TokenKind::Emit => "emit",
394 TokenKind::Pub => "pub",
395 TokenKind::From => "from",
396 TokenKind::To => "to",
397 TokenKind::Tool => "tool",
398 TokenKind::Exclusive => "exclusive",
399 TokenKind::Guard => "guard",
400 TokenKind::Require => "require",
401 TokenKind::Deadline => "deadline",
402 TokenKind::Defer => "defer",
403 TokenKind::Yield => "yield",
404 TokenKind::Mutex => "mutex",
405 TokenKind::Break => "break",
406 TokenKind::Continue => "continue",
407 TokenKind::Select => "select",
408 TokenKind::Impl => "impl",
409 TokenKind::Skill => "skill",
410 _ => return Err(self.make_error(expected)),
411 };
412 let name = name.to_string();
413 self.advance();
414 Ok(name)
415 }
416
417 pub(super) fn skip_newlines(&mut self) {
418 while self.pos < self.tokens.len() && self.tokens[self.pos].kind == TokenKind::Newline {
419 self.pos += 1;
420 }
421 }
422
423 pub(super) fn consume_statement_separator(&mut self) -> bool {
430 let mut consumed = false;
431 if self.check(&TokenKind::Semicolon) {
432 self.advance();
433 consumed = true;
434 }
435 let start = self.pos;
436 self.skip_newlines();
437 consumed || self.pos != start
438 }
439
440 pub(super) fn require_statement_separator(
441 &self,
442 prev_end_line: usize,
443 expected_item: &str,
444 ) -> Result<(), ParserError> {
445 let Some(tok) = self.current() else {
446 return Ok(());
447 };
448 if tok.kind == TokenKind::Eof || tok.span.line != prev_end_line {
449 return Ok(());
450 }
451 Err(ParserError::Unexpected {
452 got: tok.kind.to_string(),
453 expected: format!("{expected_item} separator (`;` or newline)"),
454 span: tok.span,
455 })
456 }
457
458 pub(super) fn make_error(&self, expected: &str) -> ParserError {
459 if let Some(tok) = self.tokens.get(self.pos) {
460 if tok.kind == TokenKind::Eof {
461 return ParserError::UnexpectedEof {
462 expected: expected.into(),
463 span: tok.span,
464 };
465 }
466 ParserError::Unexpected {
467 got: tok.kind.to_string(),
468 expected: expected.into(),
469 span: tok.span,
470 }
471 } else {
472 ParserError::UnexpectedEof {
473 expected: expected.into(),
474 span: self.prev_span(),
475 }
476 }
477 }
478
479 pub(super) fn error(&self, expected: &str) -> ParserError {
480 self.make_error(expected)
481 }
482
483 pub(super) fn with_nesting<T>(
484 &mut self,
485 context: &'static str,
486 f: impl FnOnce(&mut Self) -> Result<T, ParserError>,
487 ) -> Result<T, ParserError> {
488 #[cfg(test)]
489 self.record_stack_position();
490 if self.nesting_depth >= MAX_NESTING_DEPTH {
491 return Err(self.nesting_limit_error(context));
492 }
493 self.nesting_depth += 1;
494 let result = f(self);
495 self.nesting_depth = self.nesting_depth.saturating_sub(1);
496 result
497 }
498
499 #[cold]
500 #[inline(never)]
501 fn nesting_limit_error(&self, context: &'static str) -> ParserError {
502 ParserError::Unexpected {
503 got: format!("{context} nesting depth exceeded"),
504 expected: format!("parser nesting depth within {MAX_NESTING_DEPTH} levels"),
505 span: self.current_span(),
506 }
507 }
508
509 #[cfg(test)]
510 #[inline(never)]
511 pub(super) fn record_stack_position(&mut self) {
512 let marker = 0u8;
513 let address = std::ptr::from_ref(std::hint::black_box(&marker)) as usize;
514 self.stack_extent.0 = self.stack_extent.0.min(address);
515 self.stack_extent.1 = self.stack_extent.1.max(address);
516 self.deepest_nesting = self.deepest_nesting.max(self.nesting_depth);
517 }
518}