rustfmt_nightly/parse/
parser.rs

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