1 use std
::panic
::{catch_unwind, AssertUnwindSafe}
;
2 use std
::path
::{Path, PathBuf}
;
5 use rustc_ast
::token
::{DelimToken, TokenKind}
;
6 use rustc_errors
::Diagnostic
;
9 parser
::{ForceCollect, Parser as RawParser}
,
11 use rustc_span
::{sym, symbol::kw, Span}
;
13 use crate::attr
::first_attr_value_str_by_name
;
14 use crate::syntux
::session
::ParseSess
;
15 use crate::{Config, Input}
;
17 pub(crate) type DirectoryOwnership
= rustc_expand
::module
::DirectoryOwnership
;
18 pub(crate) type ModulePathSuccess
= rustc_expand
::module
::ModulePathSuccess
;
21 pub(crate) struct Directory
{
22 pub(crate) path
: PathBuf
,
23 pub(crate) ownership
: DirectoryOwnership
,
26 /// A parser for Rust source code.
27 pub(crate) struct Parser
<'a
> {
28 parser
: RawParser
<'a
>,
31 /// A builder for the `Parser`.
33 pub(crate) struct ParserBuilder
<'a
> {
34 config
: Option
<&'a Config
>,
35 sess
: Option
<&'a ParseSess
>,
37 directory_ownership
: Option
<DirectoryOwnership
>,
40 impl<'a
> ParserBuilder
<'a
> {
41 pub(crate) fn input(mut self, input
: Input
) -> ParserBuilder
<'a
> {
42 self.input
= Some(input
);
46 pub(crate) fn sess(mut self, sess
: &'a ParseSess
) -> ParserBuilder
<'a
> {
47 self.sess
= Some(sess
);
51 pub(crate) fn config(mut self, config
: &'a Config
) -> ParserBuilder
<'a
> {
52 self.config
= Some(config
);
56 pub(crate) fn directory_ownership(
58 directory_ownership
: Option
<DirectoryOwnership
>,
59 ) -> ParserBuilder
<'a
> {
60 self.directory_ownership
= directory_ownership
;
64 pub(crate) fn build(self) -> Result
<Parser
<'a
>, ParserError
> {
65 let sess
= self.sess
.ok_or(ParserError
::NoParseSess
)?
;
66 let input
= self.input
.ok_or(ParserError
::NoInput
)?
;
68 let parser
= match Self::parser(sess
.inner(), input
) {
71 if let Some(diagnostics
) = db
{
72 sess
.emit_diagnostics(diagnostics
);
73 return Err(ParserError
::ParserCreationError
);
75 return Err(ParserError
::ParsePanicError
);
83 sess
: &'a rustc_session
::parse
::ParseSess
,
85 ) -> Result
<rustc_parse
::parser
::Parser
<'a
>, Option
<Vec
<Diagnostic
>>> {
87 Input
::File(ref file
) => catch_unwind(AssertUnwindSafe(move || {
88 new_parser_from_file(sess
, file
, None
)
91 Input
::Text(text
) => rustc_parse
::maybe_new_parser_from_source_str(
93 rustc_span
::FileName
::Custom("stdin".to_owned()),
96 .map_err(|db
| Some(db
)),
101 #[derive(Debug, PartialEq)]
102 pub(crate) enum ParserError
{
110 impl<'a
> Parser
<'a
> {
111 pub(crate) fn submod_path_from_attr(attrs
: &[ast
::Attribute
], path
: &Path
) -> Option
<PathBuf
> {
112 let path_string
= first_attr_value_str_by_name(attrs
, sym
::path
)?
.as_str();
113 // On windows, the base path might have the form
114 // `\\?\foo\bar` in which case it does not tolerate
115 // mixed `/` and `\` separators, so canonicalize
118 let path_string
= path_string
.replace("/", "\\");
120 Some(path
.join(&*path_string
))
123 pub(crate) fn parse_file_as_module(
127 ) -> Result
<(ast
::Mod
, Vec
<ast
::Attribute
>), ParserError
> {
128 let result
= catch_unwind(AssertUnwindSafe(|| {
129 let mut parser
= new_parser_from_file(sess
.inner(), &path
, Some(span
));
130 match parser
.parse_mod(&TokenKind
::Eof
, ast
::Unsafe
::No
) {
131 Ok(result
) => Some(result
),
133 sess
.emit_or_cancel_diagnostic(&mut e
);
134 if sess
.can_reset_errors() {
143 if !sess
.has_errors() {
147 if sess
.can_reset_errors() {
151 Err(ParserError
::ParseError
)
153 Ok(None
) => Err(ParserError
::ParseError
),
154 Err(..) if path
.exists() => Err(ParserError
::ParseError
),
155 Err(_
) => Err(ParserError
::ParsePanicError
),
159 pub(crate) fn parse_crate(
162 directory_ownership
: Option
<DirectoryOwnership
>,
164 ) -> Result
<ast
::Crate
, ParserError
> {
165 let krate
= Parser
::parse_crate_inner(config
, input
, directory_ownership
, sess
)?
;
166 if !sess
.has_errors() {
170 if sess
.can_reset_errors() {
175 Err(ParserError
::ParseError
)
178 fn parse_crate_inner(
181 directory_ownership
: Option
<DirectoryOwnership
>,
183 ) -> Result
<ast
::Crate
, ParserError
> {
184 let mut parser
= ParserBuilder
::default()
187 .directory_ownership(directory_ownership
)
190 parser
.parse_crate_mod()
193 fn parse_crate_mod(&mut self) -> Result
<ast
::Crate
, ParserError
> {
194 let mut parser
= AssertUnwindSafe(&mut self.parser
);
196 match catch_unwind(move || parser
.parse_crate_mod()) {
200 Err(ParserError
::ParseError
)
202 Err(_
) => Err(ParserError
::ParsePanicError
),
206 pub(crate) fn parse_cfg_if(
208 mac
: &'a ast
::MacCall
,
209 ) -> Result
<Vec
<ast
::Item
>, &'
static str> {
210 match catch_unwind(AssertUnwindSafe(|| Parser
::parse_cfg_if_inner(sess
, mac
))) {
211 Ok(Ok(items
)) => Ok(items
),
212 Ok(err @
Err(_
)) => err
,
213 Err(..) => Err("failed to parse cfg_if!"),
217 fn parse_cfg_if_inner(
219 mac
: &'a ast
::MacCall
,
220 ) -> Result
<Vec
<ast
::Item
>, &'
static str> {
221 let token_stream
= mac
.args
.inner_tokens();
223 rustc_parse
::stream_to_parser(sess
.inner(), token_stream
.clone(), Some(""));
225 let mut items
= vec
![];
226 let mut process_if_cfg
= true;
228 while parser
.token
.kind
!= TokenKind
::Eof
{
230 if !parser
.eat_keyword(kw
::If
) {
231 return Err("Expected `if`");
233 // Inner attributes are not actually syntactically permitted here, but we don't
234 // care about inner vs outer attributes in this position. Our purpose with this
235 // special case parsing of cfg_if macros is to ensure we can correctly resolve
236 // imported modules that may have a custom `path` defined.
238 // As such, we just need to advance the parser past the attribute and up to
239 // to the opening brace.
240 // See also https://github.com/rust-lang/rust/pull/79433
242 .parse_attribute(rustc_parse
::parser
::attr
::InnerAttrPolicy
::Permitted
)
243 .map_err(|_
| "Failed to parse attributes")?
;
246 if !parser
.eat(&TokenKind
::OpenDelim(DelimToken
::Brace
)) {
247 return Err("Expected an opening brace");
250 while parser
.token
!= TokenKind
::CloseDelim(DelimToken
::Brace
)
251 && parser
.token
.kind
!= TokenKind
::Eof
253 let item
= match parser
.parse_item(ForceCollect
::No
) {
254 Ok(Some(item_ptr
)) => item_ptr
.into_inner(),
255 Ok(None
) => continue,
258 parser
.sess
.span_diagnostic
.reset_err_count();
260 "Expected item inside cfg_if block, but failed to parse it as an item",
264 if let ast
::ItemKind
::Mod(..) = item
.kind
{
269 if !parser
.eat(&TokenKind
::CloseDelim(DelimToken
::Brace
)) {
270 return Err("Expected a closing brace");
273 if parser
.eat(&TokenKind
::Eof
) {
277 if !parser
.eat_keyword(kw
::Else
) {
278 return Err("Expected `else`");
281 process_if_cfg
= parser
.token
.is_keyword(kw
::If
);