Skip to main content

nova_parser/
lib.rs

1//! Parser for the Nova programming language.
2//!
3//! Converts a `Vec<Spanned<Token>>` (from `nova-lexer`) into an `ast::File`.
4//! A hand-written recursive-descent parser: after an error it skips to the next
5//! item or statement boundary and keeps going.
6//!
7//! # Usage
8//!
9//! ```
10//! use nova_diagnostics::FileDb;
11//! use nova_lexer::lex;
12//! use nova_parser::parse;
13//!
14//! let mut db = FileDb::new();
15//! let file_id = db.add("main.nova", "fn main() {}");
16//! let source = db.get_source(file_id).unwrap();
17//! let (tokens, _lex_errs) = lex(source, file_id);
18//! let (ast, _parse_errs) = parse(&tokens, file_id);
19//! ```
20
21mod error;
22mod grammar;
23
24pub use error::ParseError;
25
26use nova_ast::File;
27use nova_diagnostics::{FileId, Spanned};
28use nova_lexer::Token;
29
30/// Parse a token stream into a `File` AST.
31///
32/// Returns `Some(File)` even when errors are present: the parser skips to the
33/// next item or statement boundary after an error and keeps going. It
34/// currently never returns `None`.
35pub fn parse(tokens: &[Spanned<Token>], file: FileId) -> (Option<File>, Vec<ParseError>) {
36    grammar::parse_file(tokens, file)
37}
38
39/// What [`parse_recovering`] returns.
40#[derive(Debug)]
41pub struct Parsed {
42    /// The file, with every item that parsed.
43    pub file: File,
44    pub errors: Vec<ParseError>,
45    /// The names of the top-level items dropped after their names were
46    /// read: `fn f(x: Int {` drops `f`.
47    pub dropped: Vec<Spanned<String>>,
48}
49
50/// [`parse`], also naming the items it dropped (spec
51/// `docs/superpowers/specs/2026-10-08-phase-3-2-lsp-core-design.md` ยง3.2).
52/// The language server's analysis calls this; every other caller uses
53/// [`parse`], whose result is the same file and errors.
54pub fn parse_recovering(tokens: &[Spanned<Token>], file: FileId) -> Parsed {
55    grammar::parse_recovering(tokens, file)
56}