Skip to main content

lemma/parsing/
ast.rs

1//! AST infrastructure types
2//!
3//! This module contains metadata types used throughout the parser:
4//! - `Span` for tracking source code locations
5//! - `DepthTracker` for tracking expression nesting depth during parsing
6
7/// Span representing a location in source code
8#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
9pub struct Span {
10    pub start: usize,
11    pub end: usize,
12    pub line: usize,
13    pub col: usize,
14}
15
16impl Span {
17    pub fn from_pest_span(span: pest::Span) -> Self {
18        let (line, col) = span.start_pos().line_col();
19        Self {
20            start: span.start(),
21            end: span.end(),
22            line,
23            col,
24        }
25    }
26}
27
28/// Tracks expression nesting depth during parsing to prevent stack overflow
29pub struct DepthTracker {
30    depth: usize,
31    max_depth: usize,
32}
33
34impl DepthTracker {
35    pub fn new() -> Self {
36        Self::default()
37    }
38
39    pub fn with_max_depth(max_depth: usize) -> Self {
40        Self {
41            depth: 0,
42            max_depth,
43        }
44    }
45
46    pub fn push_depth(&mut self) -> Result<(), String> {
47        self.depth += 1;
48        if self.depth > self.max_depth {
49            return Err(format!(
50                "Expression depth {} exceeds maximum of {}",
51                self.depth, self.max_depth
52            ));
53        }
54        Ok(())
55    }
56
57    pub fn pop_depth(&mut self) {
58        if self.depth > 0 {
59            self.depth -= 1;
60        }
61    }
62
63    pub fn max_depth(&self) -> usize {
64        self.max_depth
65    }
66}
67
68impl Default for DepthTracker {
69    fn default() -> Self {
70        Self {
71            depth: 0,
72            max_depth: 100,
73        }
74    }
75}