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    pub fn parse<R: Read>(
11        &self,
12        reader: R,
13    ) -> Result<shrub_parser::ast::Program, shrub_parser::ParseError> {
14        let mut parser = create_parser(reader, &self.parser_options());
15
16        tracing::debug!(target: trace_categories::PARSE, "Parsing reader as program...");
17        parser.parse_program()
18    }
19
20    /// Parses the given string as a shell program, returning the resulting
21    /// Abstract Syntax Tree for the program.
22    ///
23    /// # Arguments
24    ///
25    /// * `s` - The string to parse as a program.
26    pub fn parse_string<S: Into<String>>(
27        &self,
28        s: S,
29    ) -> Result<shrub_parser::ast::Program, shrub_parser::ParseError> {
30        let s: String = s.into();
31        parse_string_impl(&s, &self.parser_options())
32    }
33
34    /// Returns the options that should be used for parsing shell programs;
35    /// reflects the current configuration state of the shell and may change
36    /// over time.
37    pub const fn parser_options(&self) -> shrub_parser::ParserOptions {
38        shrub_parser::ParserOptions {
39            enable_extended_globbing: self.options.extended_globbing,
40            posix_mode: self.options.posix_mode,
41            sh_mode: self.options.sh_mode,
42            tilde_expansion_at_word_start: true,
43            tilde_expansion_after_colon: false,
44            parser_impl: self.parser_impl,
45        }
46    }
47}
48
49#[cached::macros::cached(
50    max_size = 64,
51    key = "(String, shrub_parser::ParserOptions)",
52    convert = r#"{ (s.to_owned(), parser_options.to_owned()) }"#
53)]
54fn parse_string_impl(
55    s: &str,
56    parser_options: &shrub_parser::ParserOptions,
57) -> Result<shrub_parser::ast::Program, shrub_parser::ParseError> {
58    let mut parser = create_parser(s.as_bytes(), parser_options);
59
60    tracing::debug!(target: trace_categories::PARSE, "Parsing string as program...");
61    parser.parse_program()
62}
63
64pub(super) fn create_parser<R: Read>(
65    r: R,
66    parser_options: &shrub_parser::ParserOptions,
67) -> shrub_parser::Parser<std::io::BufReader<R>> {
68    let reader = std::io::BufReader::new(r);
69    shrub_parser::Parser::new(reader, parser_options)
70}