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    /// The `#pragma pack` lines read so far, which is in `pack.rs` with the code that reads them.
84    pub(crate) packs: crate::pack::Packs,
85}
86
87impl<'a> Parser<'a> {
88    /// A parser over `tokens`.
89    #[must_use]
90    pub fn new(tokens: &'a Tokens, cx: Context<'a>) -> Parser<'a> {
91        Parser {
92            cursor: Cursor::new(&tokens.tokens),
93            tokens,
94            scopes: Scopes::new(),
95            errors: Errors::new(cx.error_limit),
96            ast: Ast::new(),
97            cx,
98            depth: 0,
99            too_deep: false,
100            packs: crate::pack::Packs::default(),
101        }
102    }
103
104    /// The tree and the diagnostics, once the parse is over.
105    #[must_use]
106    pub fn finish(self) -> Parsed {
107        Parsed { ast: self.ast, diagnostics: self.errors.finish() }
108    }
109
110    /// Reports an error at `span`.
111    pub(crate) fn error(&mut self, code: &'static str, message: impl Into<String>, span: Span) {
112        self.errors.push(Diagnostic::error(message, span).with_code(code));
113    }
114
115    /// Reports a warning at `span`.
116    pub(crate) fn warn(&mut self, code: &'static str, message: impl Into<String>, span: Span) {
117        self.errors.push(Diagnostic::warning(message, span).with_code(code));
118    }
119
120    /// Reports a warning that only `-pedantic` asks for.
121    pub(crate) fn pedantic(&mut self, code: &'static str, message: impl Into<String>, span: Span) {
122        if self.cx.pedantic {
123            self.warn(code, message, span);
124        }
125    }
126
127    /// Whether the parse should stop, because the error limit was reached.
128    pub(crate) fn stopped(&self) -> bool {
129        self.errors.stopped()
130    }
131
132    /// How a token is named in a diagnostic.
133    pub(crate) fn describe(&self, token: Token) -> String {
134        match token.kind {
135            TokenKind::Eof => "end of file".to_string(),
136            TokenKind::Punct(punct) => format!("`{}`", punct.as_str()),
137            TokenKind::Keyword(word) => format!("`{}`", word.as_str()),
138            TokenKind::Ident => {
139                format!("`{}`", self.cx.interner.resolve(Symbol::from_raw(token.value)))
140            }
141            TokenKind::Int => "an integer constant".to_string(),
142            TokenKind::Float => "a floating constant".to_string(),
143            TokenKind::Char => "a character constant".to_string(),
144            TokenKind::Str => "a string literal".to_string(),
145        }
146    }
147
148    /// Consumes `punct`, or reports that it is missing without consuming anything.
149    ///
150    /// The message points at the end of the previous token rather than at the token that turned
151    /// up, because a missing semicolon belongs at the end of the line it is missing from and not
152    /// at the start of the next one.
153    pub(crate) fn expect_punct(&mut self, punct: Punct) -> bool {
154        if self.cursor.eat_punct(punct) {
155            return true;
156        }
157        let found = self.describe(self.cursor.current());
158        let message = format!("expected `{}`, found {found}", punct.as_str());
159        let at = if punct == Punct::Semi { self.cursor.prev_end() } else { self.cursor.span() };
160        self.error("E0400", message, at);
161        false
162    }
163
164    /// Consumes `keyword`, or reports that it is missing.
165    pub(crate) fn expect_keyword(&mut self, keyword: Keyword) -> bool {
166        if self.cursor.eat_keyword(keyword) {
167            return true;
168        }
169        let found = self.describe(self.cursor.current());
170        let message = format!("expected `{}`, found {found}", keyword.as_str());
171        self.error("E0400", message, self.cursor.span());
172        false
173    }
174
175    /// Consumes an identifier and gives back its symbol and span.
176    pub(crate) fn expect_ident(&mut self) -> Option<(Symbol, Span)> {
177        if let Some(name) = self.cursor.current().ident() {
178            let span = self.cursor.span();
179            self.cursor.bump();
180            return Some((name, span));
181        }
182        let found = self.describe(self.cursor.current());
183        self.error("E0401", format!("expected an identifier, found {found}"), self.cursor.span());
184        None
185    }
186
187    /// A string literal, copied out of the token stream and into the tree.
188    ///
189    /// The literal rather than the expression: an `asm` template and a `static_assert` message
190    /// are strings in the grammar and not operands, so nothing is allowed to concatenate an
191    /// identifier onto one or take its address.
192    pub(crate) fn string_literal(&mut self) -> Option<StrId> {
193        let token = self.cursor.current();
194        if token.kind == TokenKind::Str {
195            self.cursor.bump();
196            let literal = self.tokens.strings[token.value as usize].clone();
197            return Some(self.ast.add_string(literal));
198        }
199        let found = self.describe(token);
200        self.error("E0409", format!("expected a string literal, found {found}"), token.span);
201        None
202    }
203
204    /// Opens a bracket, and reports the one time the nesting is too deep to continue.
205    ///
206    /// A caller that is refused must not recurse. It steps over the token that would have
207    /// opened the bracket and produces a poisoned node, which is what keeps the outer loops
208    /// making progress rather than meeting the same token again.
209    #[must_use]
210    pub(crate) fn enter(&mut self) -> bool {
211        if self.depth >= MAX_NESTING {
212            if !self.too_deep {
213                self.too_deep = true;
214                self.error(
215                    "E0402",
216                    format!("brackets nested more deeply than {MAX_NESTING} levels"),
217                    self.cursor.span(),
218                );
219            }
220            return false;
221        }
222        self.depth += 1;
223        true
224    }
225
226    /// Closes a bracket opened by [`Parser::enter`].
227    pub(crate) fn leave(&mut self) {
228        self.depth -= 1;
229    }
230
231    /// Adds an expression to the tree.
232    pub(crate) fn add_expr(&mut self, expr: Expr, span: Span) -> ExprId {
233        self.ast.expr(expr, span)
234    }
235
236    /// Adds a statement to the tree.
237    pub(crate) fn add_stmt(&mut self, stmt: Stmt, span: Span) -> StmtId {
238        self.ast.stmt(stmt, span)
239    }
240
241    /// Adds a declaration to the tree.
242    pub(crate) fn add_decl(&mut self, decl: Decl, span: Span) -> DeclId {
243        self.ast.decl(decl, span)
244    }
245
246    /// An expression node standing in for one that did not parse.
247    pub(crate) fn poison_expr(&mut self, span: Span) -> ExprId {
248        self.ast.expr(Expr::Error, span)
249    }
250
251    /// A statement node standing in for one that did not parse.
252    pub(crate) fn poison_stmt(&mut self, span: Span) -> StmtId {
253        self.ast.stmt(Stmt::Error, span)
254    }
255
256    /// A declaration node standing in for one that did not parse.
257    pub(crate) fn poison_decl(&mut self, span: Span) -> DeclId {
258        self.ast.decl(Decl::Error, span)
259    }
260
261    /// The span from `start` to the end of the token before the current one.
262    pub(crate) fn span_from(&self, start: Span) -> Span {
263        start.to(self.cursor.prev_end())
264    }
265}