]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_parse/src/lib.rs
New upstream version 1.67.1+dfsg1
[rustc.git] / compiler / rustc_parse / src / lib.rs
CommitLineData
9fa01778
XL
1//! The main parser interface.
2
cdc7bbd5 3#![feature(array_windows)]
5e7ed085 4#![feature(box_patterns)]
94222f64 5#![feature(if_let_guard)]
487cf647 6#![feature(iter_intersperse)]
5e7ed085 7#![feature(let_chains)]
5e7ed085 8#![feature(never_type)]
064997fb 9#![feature(rustc_attrs)]
6a06907d 10#![recursion_limit = "256"]
60c5eb7d 11
c295e0f8
XL
12#[macro_use]
13extern crate tracing;
14
3dfed10e 15use rustc_ast as ast;
923072b8
FG
16use rustc_ast::token;
17use rustc_ast::tokenstream::TokenStream;
487cf647 18use rustc_ast::{AttrItem, Attribute, MetaItem};
923072b8 19use rustc_ast_pretty::pprust;
e74abb32 20use rustc_data_structures::sync::Lrc;
94222f64 21use rustc_errors::{Applicability, Diagnostic, FatalError, Level, PResult};
74b04a01 22use rustc_session::parse::ParseSess;
5869c6ff 23use rustc_span::{FileName, SourceFile, Span};
9346a6ac 24
ba9703b0 25use std::path::Path;
223e47cc 26
29967ef6 27pub const MACRO_ARGUMENTS: Option<&str> = Some("macro arguments");
9346a6ac 28
1a4d82fc 29#[macro_use]
223e47cc 30pub mod parser;
dfeec247 31use parser::{emit_unclosed_delims, make_unclosed_delims_error, Parser};
1a4d82fc 32pub mod lexer;
60c5eb7d 33pub mod validate_attr;
476ff2be 34
2b03887a
FG
35mod errors;
36
e1599b0c 37// A bunch of utility functions of the form `parse_<thing>_from_<source>`
223e47cc
LB
38// where <thing> includes crate, expr, item, stmt, tts, and one that
39// uses a HOF to parse anything, and <source> includes file and
e1599b0c 40// `source_str`.
223e47cc 41
2b03887a
FG
42/// A variant of 'panictry!' that works on a `Vec<Diagnostic>` instead of a single
43/// `DiagnosticBuilder`.
e74abb32 44macro_rules! panictry_buffer {
dfeec247 45 ($handler:expr, $e:expr) => {{
60c5eb7d 46 use rustc_errors::FatalError;
dfeec247 47 use std::result::Result::{Err, Ok};
e74abb32
XL
48 match $e {
49 Ok(e) => e,
50 Err(errs) => {
5e7ed085
FG
51 for mut e in errs {
52 $handler.emit_diagnostic(&mut e);
e74abb32
XL
53 }
54 FatalError.raise()
55 }
56 }
dfeec247 57 }};
e74abb32
XL
58}
59
c30ab7b3 60pub fn parse_crate_from_file<'a>(input: &Path, sess: &'a ParseSess) -> PResult<'a, ast::Crate> {
ba9703b0 61 let mut parser = new_parser_from_file(sess, input, None);
54a0048b 62 parser.parse_crate_mod()
223e47cc
LB
63}
64
dfeec247
XL
65pub fn parse_crate_attrs_from_file<'a>(
66 input: &Path,
67 sess: &'a ParseSess,
f2b60f7d 68) -> PResult<'a, ast::AttrVec> {
ba9703b0 69 let mut parser = new_parser_from_file(sess, input, None);
54a0048b 70 parser.parse_inner_attributes()
1a4d82fc
JJ
71}
72
dfeec247
XL
73pub fn parse_crate_from_source_str(
74 name: FileName,
75 source: String,
76 sess: &ParseSess,
77) -> PResult<'_, ast::Crate> {
c30ab7b3 78 new_parser_from_source_str(sess, name, source).parse_crate_mod()
223e47cc
LB
79}
80
dfeec247
XL
81pub fn parse_crate_attrs_from_source_str(
82 name: FileName,
83 source: String,
84 sess: &ParseSess,
f2b60f7d 85) -> PResult<'_, ast::AttrVec> {
c30ab7b3 86 new_parser_from_source_str(sess, name, source).parse_inner_attributes()
1a4d82fc
JJ
87}
88
9fa01778
XL
89pub fn parse_stream_from_source_str(
90 name: FileName,
91 source: String,
92 sess: &ParseSess,
93 override_span: Option<Span>,
94) -> TokenStream {
dfeec247
XL
95 let (stream, mut errors) =
96 source_file_to_stream(sess, sess.source_map().new_source_file(name, source), override_span);
e74abb32 97 emit_unclosed_delims(&mut errors, &sess);
9fa01778 98 stream
223e47cc
LB
99}
100
9fa01778
XL
101/// Creates a new parser from a source string.
102pub fn new_parser_from_source_str(sess: &ParseSess, name: FileName, source: String) -> Parser<'_> {
a1dfa0c6
XL
103 panictry_buffer!(&sess.span_diagnostic, maybe_new_parser_from_source_str(sess, name, source))
104}
105
9fa01778 106/// Creates a new parser from a source string. Returns any buffered errors from lexing the initial
a1dfa0c6 107/// token stream.
dfeec247
XL
108pub fn maybe_new_parser_from_source_str(
109 sess: &ParseSess,
110 name: FileName,
111 source: String,
112) -> Result<Parser<'_>, Vec<Diagnostic>> {
ba9703b0 113 maybe_source_file_to_parser(sess, sess.source_map().new_source_file(name, source))
223e47cc
LB
114}
115
e1599b0c 116/// Creates a new parser, handling errors as appropriate if the file doesn't exist.
1b1a35ee 117/// If a span is given, that is used on an error as the source of the problem.
ba9703b0
XL
118pub fn new_parser_from_file<'a>(sess: &'a ParseSess, path: &Path, sp: Option<Span>) -> Parser<'a> {
119 source_file_to_parser(sess, file_to_source_file(sess, path, sp))
223e47cc
LB
120}
121
064997fb 122/// Given a session and a `source_file`, returns a parser.
9fa01778 123fn source_file_to_parser(sess: &ParseSess, source_file: Lrc<SourceFile>) -> Parser<'_> {
dfeec247 124 panictry_buffer!(&sess.span_diagnostic, maybe_source_file_to_parser(sess, source_file))
a1dfa0c6
XL
125}
126
064997fb 127/// Given a session and a `source_file`, return a parser. Returns any buffered errors from lexing the
a1dfa0c6 128/// initial token stream.
9fa01778
XL
129fn maybe_source_file_to_parser(
130 sess: &ParseSess,
131 source_file: Lrc<SourceFile>,
132) -> Result<Parser<'_>, Vec<Diagnostic>> {
b7449926 133 let end_pos = source_file.end_pos;
9fa01778 134 let (stream, unclosed_delims) = maybe_file_to_stream(sess, source_file, None)?;
dc9dc135 135 let mut parser = stream_to_parser(sess, stream, None);
9fa01778 136 parser.unclosed_delims = unclosed_delims;
74b04a01 137 if parser.token == token::Eof {
c295e0f8 138 parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt(), None);
c1a9b12d
SL
139 }
140
a1dfa0c6 141 Ok(parser)
970d7e83
LB
142}
143
e1599b0c 144// Base abstractions
970d7e83 145
0731742a
XL
146/// Given a session and a path and an optional span (for error reporting),
147/// add the path to the session's source_map and return the new source_file or
148/// error when a file can't be read.
dfeec247
XL
149fn try_file_to_source_file(
150 sess: &ParseSess,
151 path: &Path,
152 spanopt: Option<Span>,
153) -> Result<Lrc<SourceFile>, Diagnostic> {
154 sess.source_map().load_file(path).map_err(|e| {
0731742a
XL
155 let msg = format!("couldn't read {}: {}", path.display(), e);
156 let mut diag = Diagnostic::new(Level::Fatal, &msg);
157 if let Some(sp) = spanopt {
158 diag.set_span(sp);
159 }
160 diag
161 })
162}
163
970d7e83 164/// Given a session and a path and an optional span (for error reporting),
e1599b0c 165/// adds the path to the session's `source_map` and returns the new `source_file`.
dfeec247 166fn file_to_source_file(sess: &ParseSess, path: &Path, spanopt: Option<Span>) -> Lrc<SourceFile> {
0731742a 167 match try_file_to_source_file(sess, path, spanopt) {
b7449926 168 Ok(source_file) => source_file,
5e7ed085
FG
169 Err(mut d) => {
170 sess.span_diagnostic.emit_diagnostic(&mut d);
0731742a 171 FatalError.raise();
223e47cc
LB
172 }
173 }
174}
175
e1599b0c 176/// Given a `source_file`, produces a sequence of token trees.
9fa01778
XL
177pub fn source_file_to_stream(
178 sess: &ParseSess,
179 source_file: Lrc<SourceFile>,
180 override_span: Option<Span>,
181) -> (TokenStream, Vec<lexer::UnmatchedBrace>) {
a1dfa0c6
XL
182 panictry_buffer!(&sess.span_diagnostic, maybe_file_to_stream(sess, source_file, override_span))
183}
184
9fa01778 185/// Given a source file, produces a sequence of token trees. Returns any buffered errors from
48663c56 186/// parsing the token stream.
9fa01778
XL
187pub fn maybe_file_to_stream(
188 sess: &ParseSess,
189 source_file: Lrc<SourceFile>,
190 override_span: Option<Span>,
191) -> Result<(TokenStream, Vec<lexer::UnmatchedBrace>), Vec<Diagnostic>> {
1b1a35ee 192 let src = source_file.src.as_ref().unwrap_or_else(|| {
17df50a5
XL
193 sess.span_diagnostic.bug(&format!(
194 "cannot lex `source_file` without source: {}",
94222f64 195 sess.source_map().filename_for_diagnostics(&source_file.name)
17df50a5 196 ));
1b1a35ee
XL
197 });
198
199 let (token_trees, unmatched_braces) =
200 lexer::parse_token_trees(sess, src.as_str(), source_file.start_pos, override_span);
a1dfa0c6 201
48663c56
XL
202 match token_trees {
203 Ok(stream) => Ok((stream, unmatched_braces)),
a1dfa0c6
XL
204 Err(err) => {
205 let mut buffer = Vec::with_capacity(1);
206 err.buffer(&mut buffer);
9fa01778 207 // Not using `emit_unclosed_delims` to use `db.buffer`
48663c56 208 for unmatched in unmatched_braces {
e74abb32
XL
209 if let Some(err) = make_unclosed_delims_error(unmatched, &sess) {
210 err.buffer(&mut buffer);
9fa01778 211 }
9fa01778 212 }
a1dfa0c6
XL
213 Err(buffer)
214 }
215 }
970d7e83
LB
216}
217
e1599b0c 218/// Given a stream and the `ParseSess`, produces a parser.
dc9dc135
XL
219pub fn stream_to_parser<'a>(
220 sess: &'a ParseSess,
221 stream: TokenStream,
222 subparser_name: Option<&'static str>,
223) -> Parser<'a> {
ba9703b0 224 Parser::new(sess, stream, false, subparser_name)
1a4d82fc
JJ
225}
226
e74abb32 227/// Runs the given subparser `f` on the tokens of the given `attr`'s item.
60c5eb7d 228pub fn parse_in<'a, T>(
e74abb32 229 sess: &'a ParseSess,
60c5eb7d
XL
230 tts: TokenStream,
231 name: &'static str,
e74abb32
XL
232 mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
233) -> PResult<'a, T> {
ba9703b0 234 let mut parser = Parser::new(sess, tts, false, Some(name));
e74abb32
XL
235 let result = f(&mut parser)?;
236 if parser.token != token::Eof {
237 parser.unexpected()?;
238 }
239 Ok(result)
8faf50e0
XL
240}
241
923072b8
FG
242pub fn fake_token_stream_for_item(sess: &ParseSess, item: &ast::Item) -> TokenStream {
243 let source = pprust::item_to_string(item);
5869c6ff 244 let filename = FileName::macro_expansion_source_code(&source);
923072b8 245 parse_stream_from_source_str(filename, source, sess, Some(item.span))
3dfed10e 246}
94222f64 247
a2a8927a
XL
248pub fn fake_token_stream_for_crate(sess: &ParseSess, krate: &ast::Crate) -> TokenStream {
249 let source = pprust::crate_to_string_for_macros(krate);
250 let filename = FileName::macro_expansion_source_code(&source);
5e7ed085 251 parse_stream_from_source_str(filename, source, sess, Some(krate.spans.inner_span))
a2a8927a
XL
252}
253
94222f64
XL
254pub fn parse_cfg_attr(
255 attr: &Attribute,
256 parse_sess: &ParseSess,
257) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> {
258 match attr.get_normal_item().args {
487cf647
FG
259 ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens })
260 if !tokens.is_empty() =>
261 {
94222f64
XL
262 let msg = "wrong `cfg_attr` delimiters";
263 crate::validate_attr::check_meta_bad_delim(parse_sess, dspan, delim, msg);
487cf647 264 match parse_in(parse_sess, tokens.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) {
94222f64
XL
265 Ok(r) => return Some(r),
266 Err(mut e) => {
267 e.help(&format!("the valid syntax is `{}`", CFG_ATTR_GRAMMAR_HELP))
268 .note(CFG_ATTR_NOTE_REF)
269 .emit();
270 }
271 }
272 }
273 _ => error_malformed_cfg_attr_missing(attr.span, parse_sess),
274 }
275 None
276}
277
278const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]";
279const CFG_ATTR_NOTE_REF: &str = "for more information, visit \
280 <https://doc.rust-lang.org/reference/conditional-compilation.html\
281 #the-cfg_attr-attribute>";
282
283fn error_malformed_cfg_attr_missing(span: Span, parse_sess: &ParseSess) {
284 parse_sess
285 .span_diagnostic
286 .struct_span_err(span, "malformed `cfg_attr` attribute input")
287 .span_suggestion(
288 span,
289 "missing condition and attribute",
923072b8 290 CFG_ATTR_GRAMMAR_HELP,
94222f64
XL
291 Applicability::HasPlaceholders,
292 )
293 .note(CFG_ATTR_NOTE_REF)
294 .emit();
295}