Skip to main content

rucc_parse/
parser.rs

1//! The parser itself: the state every production shares, and the helpers they all use.
2//!
3//! Design: `spec/06-lexer-and-parser.md` section 6.3.
4//!
5//! The productions live in the modules beside this one and are written as inherent methods on
6//! [`Parser`], so they read as one recursive descent parser split across files rather than as a
7//! set of functions passing state to each other. What is here is the state, the diagnostics, and
8//! the small number of decisions that more than one production needs.
9
10use rucc_ast::{Ast, Decl, DeclId, Expr, ExprId, Stmt, StmtId, StrId};
11use rucc_base::{Interner, Symbol};
12use rucc_diag::{DEFAULT_ERROR_LIMIT, Diagnostic, Errors, Span};
13use rucc_lex::{Keyword, Punct, Token, TokenKind, Tokens};
14use rucc_session::Std;
15
16use crate::cursor::Cursor;
17use crate::scope::Scopes;
18
19/// How deeply brackets may nest before the parser gives up.
20///
21/// Recursive descent uses the machine stack for the grammar's nesting, so a file with a
22/// thousand open parentheses is a stack overflow rather than a diagnostic unless something
23/// stops it. The number is clang's `-fbracket-depth` default, which is the one real code has
24/// been measured against, and it is far above anything a human writes and far below anything
25/// that costs the stack more than a fraction of a megabyte.
26pub const MAX_NESTING: usize = 256;
27
28/// Everything the parser needs that is not the tokens.
29#[derive(Debug, Clone, Copy)]
30pub struct Context<'a> {
31    /// The spellings, for the diagnostics that name an identifier.
32    pub interner: &'a Interner,
33    /// The dialect, which decides whether an old-style definition is an error and whether a
34    /// C23 construct is one.
35    pub std: Std,
36    /// Whether the GNU extensions are on, which is `-std=gnu17` rather than `-std=c17`.
37    pub gnu: bool,
38    /// Whether `-pedantic` was given.
39    pub pedantic: bool,
40    /// How many errors to report before stopping, with zero meaning no limit.
41    pub error_limit: usize,
42}
43
44impl<'a> Context<'a> {
45    /// A context with the defaults, for a caller that only has an interner to hand.
46    #[must_use]
47    pub fn new(interner: &'a Interner, std: Std) -> Context<'a> {
48        Context { interner, std, gnu: true, pedantic: false, error_limit: DEFAULT_ERROR_LIMIT }
49    }
50}
51
52/// What one parse produced.
53#[derive(Debug)]
54pub struct Parsed {
55    /// The tree, which holds poisoned nodes where the source did not parse.
56    pub ast: Ast,
57    /// What went wrong, in the order it was found.
58    pub diagnostics: Vec<Diagnostic>,
59}
60
61impl Parsed {
62    /// Whether anything was reported at an error severity.
63    #[must_use]
64    pub fn failed(&self) -> bool {
65        self.diagnostics.iter().any(|d| d.severity.is_fatal())
66    }
67}
68
69/// The parser.
70#[derive(Debug)]
71pub struct Parser<'a> {
72    pub(crate) cursor: Cursor<'a>,
73    pub(crate) tokens: &'a Tokens,
74    pub(crate) scopes: Scopes,
75    pub(crate) errors: Errors,
76    pub(crate) ast: Ast,
77    pub(crate) cx: Context<'a>,
78    /// How many brackets are open, for [`MAX_NESTING`].
79    depth: usize,
80    /// Whether the nesting cap has already been reported, since reporting it at every level of
81    /// a thousand deep nesting is a thousand copies of the same message.
82    too_deep: bool,
83}
84
85impl<'a> Parser<'a> {
86    /// A parser over `tokens`.
87    #[must_use]
88    pub fn new(tokens: &'a Tokens, cx: Context<'a>) -> Parser<'a> {
89        Parser {
90            cursor: Cursor::new(&tokens.tokens),
91            tokens,
92            scopes: Scopes::new(),
93            errors: Errors::new(cx.error_limit),
94            ast: Ast::new(),
95            cx,
96            depth: 0,
97            too_deep: false,
98        }
99    }
100
101    /// The tree and the diagnostics, once the parse is over.
102    #[must_use]
103    pub fn finish(self) -> Parsed {
104        Parsed { ast: self.ast, diagnostics: self.errors.finish() }
105    }
106
107    /// Reports an error at `span`.
108    pub(crate) fn error(&mut self, code: &'static str, message: impl Into<String>, span: Span) {
109        self.errors.push(Diagnostic::error(message, span).with_code(code));
110    }
111
112    /// Reports a warning at `span`.
113    pub(crate) fn warn(&mut self, code: &'static str, message: impl Into<String>, span: Span) {
114        self.errors.push(Diagnostic::warning(message, span).with_code(code));
115    }
116
117    /// Reports a warning that only `-pedantic` asks for.
118    pub(crate) fn pedantic(&mut self, code: &'static str, message: impl Into<String>, span: Span) {
119        if self.cx.pedantic {
120            self.warn(code, message, span);
121        }
122    }
123
124    /// Whether the parse should stop, because the error limit was reached.
125    pub(crate) fn stopped(&self) -> bool {
126        self.errors.stopped()
127    }
128
129    /// How a token is named in a diagnostic.
130    pub(crate) fn describe(&self, token: Token) -> String {
131        match token.kind {
132            TokenKind::Eof => "end of file".to_string(),
133            TokenKind::Punct(punct) => format!("`{}`", punct.as_str()),
134            TokenKind::Keyword(word) => format!("`{}`", word.as_str()),
135            TokenKind::Ident => {
136                format!("`{}`", self.cx.interner.resolve(Symbol::from_raw(token.value)))
137            }
138            TokenKind::Int => "an integer constant".to_string(),
139            TokenKind::Float => "a floating constant".to_string(),
140            TokenKind::Char => "a character constant".to_string(),
141            TokenKind::Str => "a string literal".to_string(),
142        }
143    }
144
145    /// The spelling of an identifier, for a diagnostic that quotes it.
146    pub(crate) fn spelling(&self, name: Symbol) -> &str {
147        self.cx.interner.resolve(name)
148    }
149
150    /// Consumes `punct`, or reports that it is missing without consuming anything.
151    ///
152    /// The message points at the end of the previous token rather than at the token that turned
153    /// up, because a missing semicolon belongs at the end of the line it is missing from and not
154    /// at the start of the next one.
155    pub(crate) fn expect_punct(&mut self, punct: Punct) -> bool {
156        if self.cursor.eat_punct(punct) {
157            return true;
158        }
159        let found = self.describe(self.cursor.current());
160        let message = format!("expected `{}`, found {found}", punct.as_str());
161        let at = if punct == Punct::Semi { self.cursor.prev_end() } else { self.cursor.span() };
162        self.error("E0400", message, at);
163        false
164    }
165
166    /// Consumes `keyword`, or reports that it is missing.
167    pub(crate) fn expect_keyword(&mut self, keyword: Keyword) -> bool {
168        if self.cursor.eat_keyword(keyword) {
169            return true;
170        }
171        let found = self.describe(self.cursor.current());
172        let message = format!("expected `{}`, found {found}", keyword.as_str());
173        self.error("E0400", message, self.cursor.span());
174        false
175    }
176
177    /// Consumes an identifier and gives back its symbol and span.
178    pub(crate) fn expect_ident(&mut self) -> Option<(Symbol, Span)> {
179        if let Some(name) = self.cursor.current().ident() {
180            let span = self.cursor.span();
181            self.cursor.bump();
182            return Some((name, span));
183        }
184        let found = self.describe(self.cursor.current());
185        self.error("E0401", format!("expected an identifier, found {found}"), self.cursor.span());
186        None
187    }
188
189    /// A string literal, copied out of the token stream and into the tree.
190    ///
191    /// The literal rather than the expression: an `asm` template and a `static_assert` message
192    /// are strings in the grammar and not operands, so nothing is allowed to concatenate an
193    /// identifier onto one or take its address.
194    pub(crate) fn string_literal(&mut self) -> Option<StrId> {
195        let token = self.cursor.current();
196        if token.kind == TokenKind::Str {
197            self.cursor.bump();
198            let literal = self.tokens.strings[token.value as usize].clone();
199            return Some(self.ast.add_string(literal));
200        }
201        let found = self.describe(token);
202        self.error("E0409", format!("expected a string literal, found {found}"), token.span);
203        None
204    }
205
206    /// Opens a bracket, and reports the one time the nesting is too deep to continue.
207    ///
208    /// A caller that is refused must not recurse. It steps over the token that would have
209    /// opened the bracket and produces a poisoned node, which is what keeps the outer loops
210    /// making progress rather than meeting the same token again.
211    #[must_use]
212    pub(crate) fn enter(&mut self) -> bool {
213        if self.depth >= MAX_NESTING {
214            if !self.too_deep {
215                self.too_deep = true;
216                self.error(
217                    "E0402",
218                    format!("brackets nested more deeply than {MAX_NESTING} levels"),
219                    self.cursor.span(),
220                );
221            }
222            return false;
223        }
224        self.depth += 1;
225        true
226    }
227
228    /// Closes a bracket opened by [`Parser::enter`].
229    pub(crate) fn leave(&mut self) {
230        self.depth -= 1;
231    }
232
233    /// Adds an expression to the tree.
234    pub(crate) fn add_expr(&mut self, expr: Expr, span: Span) -> ExprId {
235        self.ast.expr(expr, span)
236    }
237
238    /// Adds a statement to the tree.
239    pub(crate) fn add_stmt(&mut self, stmt: Stmt, span: Span) -> StmtId {
240        self.ast.stmt(stmt, span)
241    }
242
243    /// Adds a declaration to the tree.
244    pub(crate) fn add_decl(&mut self, decl: Decl, span: Span) -> DeclId {
245        self.ast.decl(decl, span)
246    }
247
248    /// An expression node standing in for one that did not parse.
249    pub(crate) fn poison_expr(&mut self, span: Span) -> ExprId {
250        self.ast.expr(Expr::Error, span)
251    }
252
253    /// A statement node standing in for one that did not parse.
254    pub(crate) fn poison_stmt(&mut self, span: Span) -> StmtId {
255        self.ast.stmt(Stmt::Error, span)
256    }
257
258    /// A declaration node standing in for one that did not parse.
259    pub(crate) fn poison_decl(&mut self, span: Span) -> DeclId {
260        self.ast.decl(Decl::Error, span)
261    }
262
263    /// The span from `start` to the end of the token before the current one.
264    pub(crate) fn span_from(&self, start: Span) -> Span {
265        start.to(self.cursor.prev_end())
266    }
267}