1 use std::panic::{catch_unwind, AssertUnwindSafe};
2 use std::path::{Path, PathBuf};
4 use rustc_ast::token::TokenKind;
5 use rustc_ast::{ast, ptr};
6 use rustc_errors::Diagnostic;
7 use rustc_parse::{new_parser_from_file, parser::Parser as RawParser};
8 use rustc_span::{sym, Span};
10 use crate::attr::first_attr_value_str_by_name;
11 use crate::parse::session::ParseSess;
14 pub(crate) type DirectoryOwnership = rustc_expand::module::DirOwnership;
15 pub(crate) type ModulePathSuccess = rustc_expand::module::ModulePathSuccess;
16 pub(crate) type ModError<'a> = rustc_expand::module::ModError<'a>;
19 pub(crate) struct Directory {
20 pub(crate) path: PathBuf,
21 pub(crate) ownership: DirectoryOwnership,
24 /// A parser for Rust source code.
25 pub(crate) struct Parser<'a> {
26 parser: RawParser<'a>,
29 /// A builder for the `Parser`.
31 pub(crate) struct ParserBuilder<'a> {
32 sess: Option<&'a ParseSess>,
36 impl<'a> ParserBuilder<'a> {
37 pub(crate) fn input(mut self, input: Input) -> ParserBuilder<'a> {
38 self.input = Some(input);
42 pub(crate) fn sess(mut self, sess: &'a ParseSess) -> ParserBuilder<'a> {
43 self.sess = Some(sess);
47 pub(crate) fn build(self) -> Result<Parser<'a>, ParserError> {
48 let sess = self.sess.ok_or(ParserError::NoParseSess)?;
49 let input = self.input.ok_or(ParserError::NoInput)?;
51 let parser = match Self::parser(sess.inner(), input) {
54 if let Some(diagnostics) = db {
55 sess.emit_diagnostics(diagnostics);
56 return Err(ParserError::ParserCreationError);
58 return Err(ParserError::ParsePanicError);
66 sess: &'a rustc_session::parse::ParseSess,
68 ) -> Result<rustc_parse::parser::Parser<'a>, Option<Vec<Diagnostic>>> {
70 Input::File(ref file) => catch_unwind(AssertUnwindSafe(move || {
71 new_parser_from_file(sess, file, None)
74 Input::Text(text) => rustc_parse::maybe_new_parser_from_source_str(
76 rustc_span::FileName::Custom("stdin".to_owned()),
84 #[derive(Debug, PartialEq)]
85 pub(crate) enum ParserError {
94 pub(crate) fn submod_path_from_attr(attrs: &[ast::Attribute], path: &Path) -> Option<PathBuf> {
95 let path_sym = first_attr_value_str_by_name(attrs, sym::path)?;
96 let path_str = path_sym.as_str();
98 // On windows, the base path might have the form
99 // `\\?\foo\bar` in which case it does not tolerate
100 // mixed `/` and `\` separators, so canonicalize
103 let path_str = path_str.replace("/", "\\");
105 Some(path.join(path_str))
108 pub(crate) fn parse_file_as_module(
112 ) -> Result<(Vec<ast::Attribute>, Vec<ptr::P<ast::Item>>, Span), ParserError> {
113 let result = catch_unwind(AssertUnwindSafe(|| {
114 let mut parser = new_parser_from_file(sess.inner(), path, Some(span));
115 match parser.parse_mod(&TokenKind::Eof) {
116 Ok((a, i, ast::ModSpans { inner_span, inject_use_span: _ })) => Some((a, i, inner_span)),
119 if sess.can_reset_errors() {
127 Ok(Some(m)) if !sess.has_errors() => Ok(m),
128 Ok(Some(m)) if sess.can_reset_errors() => {
132 Ok(_) => Err(ParserError::ParseError),
133 Err(..) if path.exists() => Err(ParserError::ParseError),
134 Err(_) => Err(ParserError::ParsePanicError),
138 pub(crate) fn parse_crate(
141 ) -> Result<ast::Crate, ParserError> {
142 let krate = Parser::parse_crate_inner(input, sess)?;
143 if !sess.has_errors() {
147 if sess.can_reset_errors() {
152 Err(ParserError::ParseError)
155 fn parse_crate_inner(input: Input, sess: &'a ParseSess) -> Result<ast::Crate, ParserError> {
156 ParserBuilder::default()
163 fn parse_crate_mod(&mut self) -> Result<ast::Crate, ParserError> {
164 let mut parser = AssertUnwindSafe(&mut self.parser);
166 match catch_unwind(move || parser.parse_crate_mod()) {
170 Err(ParserError::ParseError)
172 Err(_) => Err(ParserError::ParsePanicError),