1 //! The main parser interface.
3 #![feature(array_windows)]
4 #![feature(box_patterns)]
5 #![feature(if_let_guard)]
6 #![feature(iter_intersperse)]
7 #![feature(let_chains)]
8 #![feature(never_type)]
9 #![feature(rustc_attrs)]
10 #![recursion_limit = "256"]
17 use rustc_ast
::tokenstream
::TokenStream
;
18 use rustc_ast
::{AttrItem, Attribute, MetaItem}
;
19 use rustc_ast_pretty
::pprust
;
20 use rustc_data_structures
::sync
::Lrc
;
21 use rustc_errors
::{Applicability, Diagnostic, FatalError, Level, PResult}
;
22 use rustc_errors
::{DiagnosticMessage, SubdiagnosticMessage}
;
23 use rustc_macros
::fluent_messages
;
24 use rustc_session
::parse
::ParseSess
;
25 use rustc_span
::{FileName, SourceFile, Span}
;
29 pub const MACRO_ARGUMENTS
: Option
<&str> = Some("macro arguments");
33 use parser
::{make_unclosed_delims_error, Parser}
;
35 pub mod validate_attr
;
39 fluent_messages
! { "../locales/en-US.ftl" }
41 // A bunch of utility functions of the form `parse_<thing>_from_<source>`
42 // where <thing> includes crate, expr, item, stmt, tts, and one that
43 // uses a HOF to parse anything, and <source> includes file and
46 /// A variant of 'panictry!' that works on a `Vec<Diagnostic>` instead of a single
47 /// `DiagnosticBuilder`.
48 macro_rules
! panictry_buffer
{
49 ($handler
:expr
, $e
:expr
) => {{
50 use rustc_errors
::FatalError
;
51 use std
::result
::Result
::{Err, Ok}
;
56 $handler
.emit_diagnostic(&mut e
);
64 pub fn parse_crate_from_file
<'a
>(input
: &Path
, sess
: &'a ParseSess
) -> PResult
<'a
, ast
::Crate
> {
65 let mut parser
= new_parser_from_file(sess
, input
, None
);
66 parser
.parse_crate_mod()
69 pub fn parse_crate_attrs_from_file
<'a
>(
72 ) -> PResult
<'a
, ast
::AttrVec
> {
73 let mut parser
= new_parser_from_file(sess
, input
, None
);
74 parser
.parse_inner_attributes()
77 pub fn parse_crate_from_source_str(
81 ) -> PResult
<'_
, ast
::Crate
> {
82 new_parser_from_source_str(sess
, name
, source
).parse_crate_mod()
85 pub fn parse_crate_attrs_from_source_str(
89 ) -> PResult
<'_
, ast
::AttrVec
> {
90 new_parser_from_source_str(sess
, name
, source
).parse_inner_attributes()
93 pub fn parse_stream_from_source_str(
97 override_span
: Option
<Span
>,
99 source_file_to_stream(sess
, sess
.source_map().new_source_file(name
, source
), override_span
)
102 /// Creates a new parser from a source string.
103 pub fn new_parser_from_source_str(sess
: &ParseSess
, name
: FileName
, source
: String
) -> Parser
<'_
> {
104 panictry_buffer
!(&sess
.span_diagnostic
, maybe_new_parser_from_source_str(sess
, name
, source
))
107 /// Creates a new parser from a source string. Returns any buffered errors from lexing the initial
109 pub fn maybe_new_parser_from_source_str(
113 ) -> Result
<Parser
<'_
>, Vec
<Diagnostic
>> {
114 maybe_source_file_to_parser(sess
, sess
.source_map().new_source_file(name
, source
))
117 /// Creates a new parser, handling errors as appropriate if the file doesn't exist.
118 /// If a span is given, that is used on an error as the source of the problem.
119 pub fn new_parser_from_file
<'a
>(sess
: &'a ParseSess
, path
: &Path
, sp
: Option
<Span
>) -> Parser
<'a
> {
120 source_file_to_parser(sess
, file_to_source_file(sess
, path
, sp
))
123 /// Given a session and a `source_file`, returns a parser.
124 fn source_file_to_parser(sess
: &ParseSess
, source_file
: Lrc
<SourceFile
>) -> Parser
<'_
> {
125 panictry_buffer
!(&sess
.span_diagnostic
, maybe_source_file_to_parser(sess
, source_file
))
128 /// Given a session and a `source_file`, return a parser. Returns any buffered errors from lexing the
129 /// initial token stream.
130 fn maybe_source_file_to_parser(
132 source_file
: Lrc
<SourceFile
>,
133 ) -> Result
<Parser
<'_
>, Vec
<Diagnostic
>> {
134 let end_pos
= source_file
.end_pos
;
135 let stream
= maybe_file_to_stream(sess
, source_file
, None
)?
;
136 let mut parser
= stream_to_parser(sess
, stream
, None
);
137 if parser
.token
== token
::Eof
{
138 parser
.token
.span
= Span
::new(end_pos
, end_pos
, parser
.token
.span
.ctxt(), None
);
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.
149 fn try_file_to_source_file(
152 spanopt
: Option
<Span
>,
153 ) -> Result
<Lrc
<SourceFile
>, Diagnostic
> {
154 sess
.source_map().load_file(path
).map_err(|e
| {
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
{
164 /// Given a session and a path and an optional span (for error reporting),
165 /// adds the path to the session's `source_map` and returns the new `source_file`.
166 fn file_to_source_file(sess
: &ParseSess
, path
: &Path
, spanopt
: Option
<Span
>) -> Lrc
<SourceFile
> {
167 match try_file_to_source_file(sess
, path
, spanopt
) {
168 Ok(source_file
) => source_file
,
170 sess
.span_diagnostic
.emit_diagnostic(&mut d
);
176 /// Given a `source_file`, produces a sequence of token trees.
177 pub fn source_file_to_stream(
179 source_file
: Lrc
<SourceFile
>,
180 override_span
: Option
<Span
>,
182 panictry_buffer
!(&sess
.span_diagnostic
, maybe_file_to_stream(sess
, source_file
, override_span
))
185 /// Given a source file, produces a sequence of token trees. Returns any buffered errors from
186 /// parsing the token stream.
187 pub fn maybe_file_to_stream(
189 source_file
: Lrc
<SourceFile
>,
190 override_span
: Option
<Span
>,
191 ) -> Result
<TokenStream
, Vec
<Diagnostic
>> {
192 let src
= source_file
.src
.as_ref().unwrap_or_else(|| {
193 sess
.span_diagnostic
.bug(&format
!(
194 "cannot lex `source_file` without source: {}",
195 sess
.source_map().filename_for_diagnostics(&source_file
.name
)
199 lexer
::parse_token_trees(sess
, src
.as_str(), source_file
.start_pos
, override_span
)
202 /// Given a stream and the `ParseSess`, produces a parser.
203 pub fn stream_to_parser
<'a
>(
206 subparser_name
: Option
<&'
static str>,
208 Parser
::new(sess
, stream
, false, subparser_name
)
211 /// Runs the given subparser `f` on the tokens of the given `attr`'s item.
212 pub fn parse_in
<'a
, T
>(
216 mut f
: impl FnMut(&mut Parser
<'a
>) -> PResult
<'a
, T
>,
217 ) -> PResult
<'a
, T
> {
218 let mut parser
= Parser
::new(sess
, tts
, false, Some(name
));
219 let result
= f(&mut parser
)?
;
220 if parser
.token
!= token
::Eof
{
221 parser
.unexpected()?
;
226 pub fn fake_token_stream_for_item(sess
: &ParseSess
, item
: &ast
::Item
) -> TokenStream
{
227 let source
= pprust
::item_to_string(item
);
228 let filename
= FileName
::macro_expansion_source_code(&source
);
229 parse_stream_from_source_str(filename
, source
, sess
, Some(item
.span
))
232 pub fn fake_token_stream_for_crate(sess
: &ParseSess
, krate
: &ast
::Crate
) -> TokenStream
{
233 let source
= pprust
::crate_to_string_for_macros(krate
);
234 let filename
= FileName
::macro_expansion_source_code(&source
);
235 parse_stream_from_source_str(filename
, source
, sess
, Some(krate
.spans
.inner_span
))
238 pub fn parse_cfg_attr(
240 parse_sess
: &ParseSess
,
241 ) -> Option
<(MetaItem
, Vec
<(AttrItem
, Span
)>)> {
242 match attr
.get_normal_item().args
{
243 ast
::AttrArgs
::Delimited(ast
::DelimArgs { dspan, delim, ref tokens }
)
244 if !tokens
.is_empty() =>
246 let msg
= "wrong `cfg_attr` delimiters";
247 crate::validate_attr
::check_meta_bad_delim(parse_sess
, dspan
, delim
, msg
);
248 match parse_in(parse_sess
, tokens
.clone(), "`cfg_attr` input", |p
| p
.parse_cfg_attr()) {
249 Ok(r
) => return Some(r
),
251 e
.help(&format
!("the valid syntax is `{}`", CFG_ATTR_GRAMMAR_HELP
))
252 .note(CFG_ATTR_NOTE_REF
)
257 _
=> error_malformed_cfg_attr_missing(attr
.span
, parse_sess
),
262 const CFG_ATTR_GRAMMAR_HELP
: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]";
263 const CFG_ATTR_NOTE_REF
: &str = "for more information, visit \
264 <https://doc.rust-lang.org/reference/conditional-compilation.html\
265 #the-cfg_attr-attribute>";
267 fn error_malformed_cfg_attr_missing(span
: Span
, parse_sess
: &ParseSess
) {
270 .struct_span_err(span
, "malformed `cfg_attr` attribute input")
273 "missing condition and attribute",
274 CFG_ATTR_GRAMMAR_HELP
,
275 Applicability
::HasPlaceholders
,
277 .note(CFG_ATTR_NOTE_REF
)