rustfmt_nightly/parse/
parser.rs

1use std::panic::{AssertUnwindSafe, catch_unwind};
2use std::path::{Path, PathBuf};
3
4use rustc_ast::{ast, attr};
5use rustc_errors::Diag;
6use rustc_parse::lexer::StripTokens;
7use rustc_parse::parser::Parser as RawParser;
8use rustc_parse::{exp, new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
9use rustc_span::{Span, sym};
10use thin_vec::ThinVec;
11
12use crate::Input;
13use crate::parse::session::ParseSess;
14
15pub(crate) type DirectoryOwnership = rustc_expand::module::DirOwnership;
16pub(crate) type ModulePathSuccess = rustc_expand::module::ModulePathSuccess;
17pub(crate) type ModError<'a> = rustc_expand::module::ModError<'a>;
18
19#[derive(Clone)]
20pub(crate) struct Directory {
21    pub(crate) path: PathBuf,
22    pub(crate) ownership: DirectoryOwnership,
23}
24
25/// A parser for Rust source code.
26pub(crate) struct Parser<'a> {
27    parser: RawParser<'a>,
28}
29
30/// A builder for the `Parser`.
31#[derive(Default)]
32pub(crate) struct ParserBuilder<'a> {
33    psess: Option<&'a ParseSess>,
34    input: Option<Input>,
35}
36
37impl<'a> ParserBuilder<'a> {
38    pub(crate) fn input(mut self, input: Input) -> ParserBuilder<'a> {
39        self.input = Some(input);
40        self
41    }
42
43    pub(crate) fn psess(mut self, psess: &'a ParseSess) -> ParserBuilder<'a> {
44        self.psess = Some(psess);
45        self
46    }
47
48    pub(crate) fn build(self) -> Result<Parser<'a>, ParserError> {
49        let psess = self.psess.ok_or(ParserError::NoParseSess)?;
50        let input = self.input.ok_or(ParserError::NoInput)?;
51
52        let parser = match Self::parser(psess.inner(), input) {
53            Ok(p) => p,
54            Err(diagnostics) => {
55                psess.emit_diagnostics(diagnostics);
56                return Err(ParserError::ParserCreationError);
57            }
58        };
59
60        Ok(Parser { parser })
61    }
62
63    fn parser(
64        psess: &'a rustc_session::parse::ParseSess,
65        input: Input,
66    ) -> Result<RawParser<'a>, Vec<Diag<'a>>> {
67        match input {
68            Input::File(ref file) => {
69                new_parser_from_file(psess, file, StripTokens::ShebangAndFrontmatter, None)
70            }
71            Input::Text(text) => new_parser_from_source_str(
72                psess,
73                rustc_span::FileName::Custom("stdin".to_owned()),
74                text,
75                StripTokens::ShebangAndFrontmatter,
76            ),
77        }
78    }
79}
80
81#[derive(Debug, PartialEq)]
82pub(crate) enum ParserError {
83    NoParseSess,
84    NoInput,
85    ParserCreationError,
86    ParseError,
87    ParsePanicError,
88}
89
90impl<'a> Parser<'a> {
91    pub(crate) fn submod_path_from_attr(attrs: &[ast::Attribute], path: &Path) -> Option<PathBuf> {
92        let path_sym = attr::first_attr_value_str_by_name(attrs, sym::path)?;
93        let path_str = path_sym.as_str();
94
95        // On windows, the base path might have the form
96        // `\\?\foo\bar` in which case it does not tolerate
97        // mixed `/` and `\` separators, so canonicalize
98        // `/` to `\`.
99        #[cfg(windows)]
100        let path_str = path_str.replace("/", "\\");
101
102        Some(path.join(path_str))
103    }
104
105    pub(crate) fn parse_file_as_module(
106        psess: &'a ParseSess,
107        path: &Path,
108        span: Span,
109    ) -> Result<(ast::AttrVec, ThinVec<Box<ast::Item>>, Span), ParserError> {
110        let result = catch_unwind(AssertUnwindSafe(|| {
111            let mut parser = unwrap_or_emit_fatal(new_parser_from_file(
112                psess.inner(),
113                path,
114                StripTokens::ShebangAndFrontmatter,
115                Some(span),
116            ));
117            match parser.parse_mod(exp!(Eof)) {
118                Ok((a, i, spans)) => Some((a, i, spans.inner_span)),
119                Err(e) => {
120                    e.emit();
121                    if psess.can_reset_errors() {
122                        psess.reset_errors();
123                    }
124                    None
125                }
126            }
127        }));
128        match result {
129            Ok(Some(m)) if !psess.has_errors() => Ok(m),
130            Ok(Some(m)) if psess.can_reset_errors() => {
131                psess.reset_errors();
132                Ok(m)
133            }
134            Ok(_) => Err(ParserError::ParseError),
135            Err(..) if path.exists() => Err(ParserError::ParseError),
136            Err(_) => Err(ParserError::ParsePanicError),
137        }
138    }
139
140    pub(crate) fn parse_crate(
141        input: Input,
142        psess: &'a ParseSess,
143    ) -> Result<ast::Crate, ParserError> {
144        let krate = Parser::parse_crate_inner(input, psess)?;
145        if !psess.has_errors() {
146            return Ok(krate);
147        }
148
149        if psess.can_reset_errors() {
150            psess.reset_errors();
151            return Ok(krate);
152        }
153
154        Err(ParserError::ParseError)
155    }
156
157    fn parse_crate_inner(input: Input, psess: &'a ParseSess) -> Result<ast::Crate, ParserError> {
158        ParserBuilder::default()
159            .input(input)
160            .psess(psess)
161            .build()?
162            .parse_crate_mod()
163    }
164
165    fn parse_crate_mod(&mut self) -> Result<ast::Crate, ParserError> {
166        let mut parser = AssertUnwindSafe(&mut self.parser);
167        let err = Err(ParserError::ParsePanicError);
168        match catch_unwind(move || parser.parse_crate_mod()) {
169            Ok(Ok(k)) => Ok(k),
170            Ok(Err(db)) => {
171                db.emit();
172                err
173            }
174            Err(_) => err,
175        }
176    }
177}