1 use std::panic::{catch_unwind, AssertUnwindSafe};
2 use std::path::{Path, PathBuf};
4 use rustc_ast::token::{DelimToken, TokenKind};
5 use rustc_ast::{ast, ptr};
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;
17 pub(crate) type DirectoryOwnership = rustc_expand::module::DirOwnership;
18 pub(crate) type ModulePathSuccess = rustc_expand::module::ModulePathSuccess;
19 pub(crate) type ModError<'a> = rustc_expand::module::ModError<'a>;
22 pub(crate) struct Directory {
23 pub(crate) path: PathBuf,
24 pub(crate) ownership: DirectoryOwnership,
27 /// A parser for Rust source code.
28 pub(crate) struct Parser<'a> {
29 parser: RawParser<'a>,
32 /// A builder for the `Parser`.
34 pub(crate) struct ParserBuilder<'a> {
35 sess: Option<&'a ParseSess>,
39 impl<'a> ParserBuilder<'a> {
40 pub(crate) fn input(mut self, input: Input) -> ParserBuilder<'a> {
41 self.input = Some(input);
45 pub(crate) fn sess(mut self, sess: &'a ParseSess) -> ParserBuilder<'a> {
46 self.sess = Some(sess);
50 pub(crate) fn build(self) -> Result<Parser<'a>, ParserError> {
51 let sess = self.sess.ok_or(ParserError::NoParseSess)?;
52 let input = self.input.ok_or(ParserError::NoInput)?;
54 let parser = match Self::parser(sess.inner(), input) {
57 if let Some(diagnostics) = db {
58 sess.emit_diagnostics(diagnostics);
59 return Err(ParserError::ParserCreationError);
61 return Err(ParserError::ParsePanicError);
69 sess: &'a rustc_session::parse::ParseSess,
71 ) -> Result<rustc_parse::parser::Parser<'a>, Option<Vec<Diagnostic>>> {
73 Input::File(ref file) => catch_unwind(AssertUnwindSafe(move || {
74 new_parser_from_file(sess, file, None)
77 Input::Text(text) => rustc_parse::maybe_new_parser_from_source_str(
79 rustc_span::FileName::Custom("stdin".to_owned()),
87 #[derive(Debug, PartialEq)]
88 pub(crate) enum ParserError {
97 pub(crate) fn submod_path_from_attr(attrs: &[ast::Attribute], path: &Path) -> Option<PathBuf> {
98 let path_string = first_attr_value_str_by_name(attrs, sym::path)?.as_str();
99 // On windows, the base path might have the form
100 // `\\?\foo\bar` in which case it does not tolerate
101 // mixed `/` and `\` separators, so canonicalize
104 let path_string = path_string.replace("/", "\\");
106 Some(path.join(&*path_string))
109 pub(crate) fn parse_file_as_module(
113 ) -> Result<(Vec<ast::Attribute>, Vec<ptr::P<ast::Item>>, Span), ParserError> {
114 let result = catch_unwind(AssertUnwindSafe(|| {
115 let mut parser = new_parser_from_file(sess.inner(), path, Some(span));
116 match parser.parse_mod(&TokenKind::Eof) {
117 Ok(result) => Some(result),
119 sess.emit_or_cancel_diagnostic(&mut e);
120 if sess.can_reset_errors() {
128 Ok(Some(m)) if !sess.has_errors() => Ok(m),
129 Ok(Some(m)) if sess.can_reset_errors() => {
133 Ok(_) => Err(ParserError::ParseError),
134 Err(..) if path.exists() => Err(ParserError::ParseError),
135 Err(_) => Err(ParserError::ParsePanicError),
139 pub(crate) fn parse_crate(
142 ) -> Result<ast::Crate, ParserError> {
143 let krate = Parser::parse_crate_inner(input, sess)?;
144 if !sess.has_errors() {
148 if sess.can_reset_errors() {
153 Err(ParserError::ParseError)
156 fn parse_crate_inner(input: Input, sess: &'a ParseSess) -> Result<ast::Crate, ParserError> {
157 ParserBuilder::default()
164 fn parse_crate_mod(&mut self) -> Result<ast::Crate, ParserError> {
165 let mut parser = AssertUnwindSafe(&mut self.parser);
167 match catch_unwind(move || parser.parse_crate_mod()) {
171 Err(ParserError::ParseError)
173 Err(_) => Err(ParserError::ParsePanicError),
177 pub(crate) fn parse_cfg_if(
179 mac: &'a ast::MacCall,
180 ) -> Result<Vec<ast::Item>, &'static str> {
181 match catch_unwind(AssertUnwindSafe(|| Parser::parse_cfg_if_inner(sess, mac))) {
182 Ok(Ok(items)) => Ok(items),
183 Ok(err @ Err(_)) => err,
184 Err(..) => Err("failed to parse cfg_if!"),
188 fn parse_cfg_if_inner(
190 mac: &'a ast::MacCall,
191 ) -> Result<Vec<ast::Item>, &'static str> {
192 let token_stream = mac.args.inner_tokens();
193 let mut parser = rustc_parse::stream_to_parser(sess.inner(), token_stream, Some(""));
195 let mut items = vec![];
196 let mut process_if_cfg = true;
198 while parser.token.kind != TokenKind::Eof {
200 if !parser.eat_keyword(kw::If) {
201 return Err("Expected `if`");
203 // Inner attributes are not actually syntactically permitted here, but we don't
204 // care about inner vs outer attributes in this position. Our purpose with this
205 // special case parsing of cfg_if macros is to ensure we can correctly resolve
206 // imported modules that may have a custom `path` defined.
208 // As such, we just need to advance the parser past the attribute and up to
209 // to the opening brace.
210 // See also https://github.com/rust-lang/rust/pull/79433
212 .parse_attribute(rustc_parse::parser::attr::InnerAttrPolicy::Permitted)
213 .map_err(|_| "Failed to parse attributes")?;
216 if !parser.eat(&TokenKind::OpenDelim(DelimToken::Brace)) {
217 return Err("Expected an opening brace");
220 while parser.token != TokenKind::CloseDelim(DelimToken::Brace)
221 && parser.token.kind != TokenKind::Eof
223 let item = match parser.parse_item(ForceCollect::No) {
224 Ok(Some(item_ptr)) => item_ptr.into_inner(),
225 Ok(None) => continue,
228 parser.sess.span_diagnostic.reset_err_count();
230 "Expected item inside cfg_if block, but failed to parse it as an item",
234 if let ast::ItemKind::Mod(..) = item.kind {
239 if !parser.eat(&TokenKind::CloseDelim(DelimToken::Brace)) {
240 return Err("Expected a closing brace");
243 if parser.eat(&TokenKind::Eof) {
247 if !parser.eat_keyword(kw::Else) {
248 return Err("Expected `else`");
251 process_if_cfg = parser.token.is_keyword(kw::If);