1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
//! Recursive descent with a Pratt expression parser, declarators, and error recovery.
//!
//! Design: `spec/06-lexer-and-parser.md`. Layer rank 7, see `spec/18-package-layout.md`.
//!
//! # Status
//!
//! The grammar is here: expressions, declaration specifiers, declarators, initializers,
//! statements and declarations, in every dialect from C89 to C23 and with the GNU extensions
//! that real code cannot be read without. [`parse`] takes the tokens phase 7 produced and gives
//! back a tree and the diagnostics it collected on the way. What is not here is the printer, so
//! there is no way to turn the tree back into source yet, and there is nothing that checks the
//! tree means anything.
//!
//! ```
//! use rucc_base::Interner;
//! use rucc_lex::{Convert, Keywords, Options, convert, tokenize};
//! use rucc_parse::{Context, parse};
//! use rucc_session::Std;
//! use rucc_target::{TargetInfo, Triple};
//!
//! let std = Std::C23;
//! // The keyword table is interned first, before any source is read.
//! let mut interner = Interner::new();
//! let keywords = Keywords::new(&mut interner, std, true);
//! let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse::<Triple>().unwrap());
//!
//! let source = b"int main(void) { return 0; }";
//! let (pp, _) = tokenize(source, 0, Options::new(), &mut interner);
//! let cx = Convert { keywords: &keywords, interner: &interner, target: &target,
//! std, pedantic: false };
//! let (tokens, _) = convert(&pp, &cx);
//!
//! let parsed = parse(&tokens, Context::new(&interner, std));
//! assert!(!parsed.failed());
//! assert_eq!(parsed.ast.top_level().len(), 1);
//! ```
//!
//! # What the parser reads
//!
//! A slice of [`rucc_lex::Token`], which is what phase 7 produces from the preprocessor's
//! output. Directives are gone by then, adjacent string literals have been joined, constants
//! have been converted, and a spelling no longer means anything. The parser never looks at
//! source text and never asks the lexer a question, which is what makes the typedef decision in
//! [`scope`] the only place the ambiguity in C's grammar is resolved.
//!
//! # What it builds
//!
//! A [`rucc_ast::Ast`], which records what was written rather than what it means. Nothing here
//! resolves a name to a declaration, works out a type, folds a constant or desugars anything.
//! A file that parses is not a file that compiles, and keeping the two apart is what lets the
//! printer put back what it was given.
//!
//! # Where the productions are
//!
//! [`Parser`] holds the state and the helpers, and the productions are inherent methods on it
//! written across six private modules: expressions, specifiers, declarators, initializers,
//! statements and declarations. They are one recursive descent parser split up for reading
//! rather than six things that call each other, so nothing is exported from them.
//!
//! Every crate in the workspace is published, and publishing implies a promise. This one is
//! tier 3: its Rust API is explicitly unstable and will change without a major version bump.
//! Depend on the `rucc` binary's behaviour, not on this.
pub use crate;
pub use crate;
pub use crate;
pub use crate;
/// Parses a translation unit.
///
/// Always gives back a tree. A file that does not parse produces poisoned nodes where the
/// productions gave up, so that everything after a mistake is still parsed and reported on, and
/// [`Parsed::failed`] is what says whether to carry on with it.
/// The milestone in `spec/17-milestones.md` that fills this crate in.
pub const MILESTONE: &str = "M2";