trident/syntax/parser/
mod.rs1mod expr;
2mod items;
3mod stmts;
4mod types;
5
6#[cfg(test)]
7mod tests;
8
9use crate::ast::*;
10use crate::diagnostic::Diagnostic;
11use crate::lexeme::Lexeme;
12use crate::span::{Span, Spanned};
13
14const MAX_NESTING_DEPTH: u32 = 256;
15
16pub(crate) struct Parser {
17 tokens: Vec<Spanned<Lexeme>>,
18 pos: usize,
19 diagnostics: Vec<Diagnostic>,
20 depth: u32,
21 source: Vec<u8>,
23}
24
25impl Parser {
26 pub(crate) fn new(tokens: Vec<Spanned<Lexeme>>) -> Self {
27 Self {
28 tokens,
29 pos: 0,
30 diagnostics: Vec::new(),
31 depth: 0,
32 source: Vec::new(),
33 }
34 }
35
36 pub(crate) fn new_with_source(tokens: Vec<Spanned<Lexeme>>, source: &str) -> Self {
37 Self {
38 tokens,
39 pos: 0,
40 diagnostics: Vec::new(),
41 depth: 0,
42 source: source.as_bytes().to_vec(),
43 }
44 }
45
46 fn same_line(&self, a: Span, b: Span) -> bool {
49 if self.source.is_empty() {
50 return true;
51 }
52 let start = a.end as usize;
53 let end = (b.start as usize).min(self.source.len());
54 if start >= end {
55 return true;
56 }
57 !self.source[start..end].contains(&b'\n')
58 }
59
60 pub(crate) fn parse_file(mut self) -> Result<File, Vec<Diagnostic>> {
61 let file = if self.at(&Lexeme::Program) {
62 self.parse_program()
63 } else if self.at(&Lexeme::Module) {
64 self.parse_module()
65 } else {
66 self.error_with_help(
67 "expected 'program' or 'module' declaration at the start of file",
68 "every .tri file must begin with `program <name>` or `module <name>`",
69 );
70 return Err(self.diagnostics);
71 };
72
73 if !self.diagnostics.is_empty() {
74 return Err(self.diagnostics);
75 }
76 Ok(file)
77 }
78
79 fn enter_nesting(&mut self) -> bool {
80 self.depth += 1;
81 if self.depth > MAX_NESTING_DEPTH {
82 self.error_with_help(
83 "nesting depth exceeded (maximum 256 levels)",
84 "simplify your program by extracting deeply nested code into functions",
85 );
86 return false;
87 }
88 true
89 }
90
91 fn exit_nesting(&mut self) {
92 self.depth -= 1;
93 }
94
95 fn peek(&self) -> &Lexeme {
98 &self.tokens[self.pos].node
99 }
100
101 fn current_span(&self) -> Span {
102 self.tokens[self.pos].span
103 }
104
105 fn prev_span(&self) -> Span {
106 if self.pos > 0 {
107 self.tokens[self.pos - 1].span
108 } else {
109 self.current_span()
110 }
111 }
112
113 fn advance(&mut self) -> &Spanned<Lexeme> {
114 let tok = &self.tokens[self.pos];
115 if self.pos < self.tokens.len() - 1 {
116 self.pos += 1;
117 }
118 tok
119 }
120
121 fn at(&self, token: &Lexeme) -> bool {
122 std::mem::discriminant(self.peek()) == std::mem::discriminant(token)
123 }
124
125 fn eat(&mut self, token: &Lexeme) -> bool {
126 if self.at(token) {
127 self.advance();
128 true
129 } else {
130 false
131 }
132 }
133
134 fn expect(&mut self, token: &Lexeme) -> Span {
135 if self.at(token) {
136 let span = self.current_span();
137 self.advance();
138 span
139 } else {
140 self.error_at_current(&format!(
141 "expected {}, found {}",
142 token.description(),
143 self.peek().description()
144 ));
145 self.current_span()
146 }
147 }
148
149 fn expect_ident(&mut self) -> Spanned<String> {
150 if let Lexeme::Ident(name) = self.peek().clone() {
151 let span = self.current_span();
152 self.advance();
153 Spanned::new(name, span)
154 } else {
155 self.error_at_current(&format!(
156 "expected identifier, found {}",
157 self.peek().description()
158 ));
159 Spanned::new("_error_".to_string(), self.current_span())
160 }
161 }
162
163 fn try_ident(&mut self) -> Option<Spanned<String>> {
164 if let Lexeme::Ident(name) = self.peek().clone() {
165 let span = self.current_span();
166 self.advance();
167 Some(Spanned::new(name, span))
168 } else {
169 None
170 }
171 }
172
173 fn expect_integer(&mut self) -> u64 {
174 if let Lexeme::Integer(n) = self.peek() {
175 let n = *n;
176 self.advance();
177 n
178 } else {
179 self.error_at_current(&format!(
180 "expected integer literal, found {}",
181 self.peek().description()
182 ));
183 0
184 }
185 }
186
187 fn error_at_current(&mut self, msg: &str) {
188 self.diagnostics
189 .push(Diagnostic::error(msg.to_string(), self.current_span()));
190 }
191
192 fn error_with_help(&mut self, msg: &str, help: &str) {
193 self.diagnostics.push(
194 Diagnostic::error(msg.to_string(), self.current_span()).with_help(help.to_string()),
195 );
196 }
197
198 fn parse_module_path(&mut self) -> ModulePath {
199 let first = self.expect_ident();
200 let mut parts = vec![first.node];
201 while self.eat(&Lexeme::Dot) {
202 if let Some(ident) = self.try_ident() {
203 parts.push(ident.node);
204 } else {
205 break;
206 }
207 }
208 ModulePath(parts)
209 }
210}