Skip to main content

shrub_core/shell/
parsing.rs

1//! Parsing for shell instances.
2
3use std::io::Read;
4
5use crate::{Shell, extensions, trace_categories};
6
7impl<SE: extensions::ShellExtensions> Shell<SE> {
8    /// Parses the given reader as a shell program, returning the resulting
9    /// Abstract Syntax Tree for the program.
10    ///
11    /// # Errors
12    ///
13    /// - [`shrub_parser::ParseError::Tokenizing`] if the input cannot be
14    ///   tokenized.
15    /// - [`shrub_parser::ParseError::ParsingNear`] or
16    ///   [`shrub_parser::ParseError::ParsingAtEndOfInput`] if the input is not
17    ///   a valid program.
18    pub fn parse<R: Read>(
19        &self,
20        reader: R,
21    ) -> Result<shrub_parser::ast::Program, shrub_parser::ParseError> {
22        let mut parser = create_parser(reader, &self.parser_options());
23
24        tracing::debug!(target: trace_categories::PARSE, "Parsing reader as program...");
25        parser.parse_program()
26    }
27
28    /// Parses the given string as a shell program, returning the resulting
29    /// Abstract Syntax Tree for the program.
30    ///
31    /// # Arguments
32    ///
33    /// * `s` - The string to parse as a program.
34    ///
35    /// # Errors
36    ///
37    /// - [`shrub_parser::ParseError::Tokenizing`] if the input cannot be
38    ///   tokenized.
39    /// - [`shrub_parser::ParseError::ParsingNear`] or
40    ///   [`shrub_parser::ParseError::ParsingAtEndOfInput`] if the input is not
41    ///   a valid program.
42    pub fn parse_string<S: Into<String>>(
43        &self,
44        s: S,
45    ) -> Result<shrub_parser::ast::Program, shrub_parser::ParseError> {
46        let s: String = s.into();
47        parse_string_impl(&s, &self.parser_options())
48    }
49
50    /// Returns the options that should be used for parsing shell programs;
51    /// reflects the current configuration state of the shell and may change
52    /// over time.
53    pub const fn parser_options(&self) -> shrub_parser::ParserOptions {
54        shrub_parser::ParserOptions {
55            enable_extended_globbing: self.options.extended_globbing,
56            posix_mode: self.options.posix_mode,
57            sh_mode: self.options.sh_mode,
58            tilde_expansion_at_word_start: true,
59            tilde_expansion_after_colon: false,
60            parser_impl: self.parser_impl,
61        }
62    }
63}
64
65#[cached::macros::cached(
66    max_size = 64,
67    key = "(String, shrub_parser::ParserOptions)",
68    convert = r#"{ (s.to_owned(), parser_options.to_owned()) }"#
69)]
70fn parse_string_impl(
71    s: &str,
72    parser_options: &shrub_parser::ParserOptions,
73) -> Result<shrub_parser::ast::Program, shrub_parser::ParseError> {
74    let mut parser = create_parser(s.as_bytes(), parser_options);
75
76    tracing::debug!(target: trace_categories::PARSE, "Parsing string as program...");
77    parser.parse_program()
78}
79
80pub(super) fn create_parser<R: Read>(
81    r: R,
82    parser_options: &shrub_parser::ParserOptions,
83) -> shrub_parser::Parser<std::io::BufReader<R>> {
84    let reader = std::io::BufReader::new(r);
85    shrub_parser::Parser::new(reader, parser_options)
86}