Skip to content

Commit

Permalink
fix: support here documents in command substitutions (#255)
Browse files Browse the repository at this point in the history
  • Loading branch information
reubeno authored Nov 3, 2024
1 parent 7dcbe7c commit 9e16201
Show file tree
Hide file tree
Showing 6 changed files with 527 additions and 139 deletions.
17 changes: 17 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions brush-core/src/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ impl Shell {
brush_parser::Parser::new(&mut reader, &self.parser_options(), source_info);

tracing::debug!(target: trace_categories::PARSE, "Parsing sourced file: {}", source_info.source);
let parse_result = parser.parse(false);
let parse_result = parser.parse();

let mut other_positional_parameters = args.iter().map(|s| s.as_ref().to_owned()).collect();
let mut other_shell_name = Some(source_info.source.clone());
Expand Down Expand Up @@ -1180,5 +1180,5 @@ fn parse_string_impl(
brush_parser::Parser::new(&mut reader, &parser_options, &source_info);

tracing::debug!(target: trace_categories::PARSE, "Parsing string as program...");
parser.parse(true)
parser.parse()
}
1 change: 1 addition & 0 deletions brush-parser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ utf8-chars = "3.0.5"
anyhow = "1.0.91"
assert_matches = "1.5.0"
criterion = { version = "0.5.1", features = ["html_reports"] }
pretty_assertions = { version = "1.4.1", features = ["unstable"] }

[target.'cfg(unix)'.dev-dependencies]
pprof = { version = "0.13.0", features = ["criterion", "flamegraph"] }
Expand Down
37 changes: 12 additions & 25 deletions brush-parser/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,7 @@ impl<R: std::io::BufRead> Parser<R> {
}

/// Parses the input into an abstract syntax tree (AST) of a shell program.
///
/// # Arguments
///
/// * `stop_on_unescaped_newline` - Whether or not to stop parsing when an unescaped newline is
/// encountered.
pub fn parse(
&mut self,
stop_on_unescaped_newline: bool,
) -> Result<ast::Program, error::ParseError> {
pub fn parse(&mut self) -> Result<ast::Program, error::ParseError> {
//
// References:
// * https://www.gnu.org/software/bash/manual/bash.html#Shell-Syntax
Expand Down Expand Up @@ -90,18 +82,13 @@ impl<R: std::io::BufRead> Parser<R> {
}
};

let reason = result.reason;
if let Some(token) = result.token {
tracing::debug!(target: "tokenize", "TOKEN {}: {:?}", tokens.len(), token);
tracing::debug!(target: "tokenize", "TOKEN {}: {:?} {reason:?}", tokens.len(), token);
tokens.push(token);
}

if matches!(result.reason, TokenEndReason::EndOfInput) {
break;
}

if stop_on_unescaped_newline
&& matches!(result.reason, TokenEndReason::UnescapedNewLine)
{
if matches!(reason, TokenEndReason::EndOfInput) {
break;
}
}
Expand Down Expand Up @@ -646,27 +633,27 @@ peg::parser! {
rule filename() -> &'input Token =
word()

rule io_here() -> ast::IoHereDocument =
specific_operator("<<-") here_end:here_end() doc:[_] {
let requires_expansion = !here_end.to_str().contains(['\'', '"', '\\']);
pub(crate) rule io_here() -> ast::IoHereDocument =
specific_operator("<<-") here_tag:here_tag() doc:[_] closing_tag:here_tag() {
let requires_expansion = !here_tag.to_str().contains(['\'', '"', '\\']);
ast::IoHereDocument {
remove_tabs: true,
requires_expansion,
here_end: ast::Word::from(here_end),
here_end: ast::Word::from(here_tag),
doc: ast::Word::from(doc)
}
} /
specific_operator("<<") here_end:here_end() doc:[_] {
let requires_expansion = !here_end.to_str().contains(['\'', '"', '\\']);
specific_operator("<<") here_tag:here_tag() doc:[_] closing_tag:here_tag() {
let requires_expansion = !here_tag.to_str().contains(['\'', '"', '\\']);
ast::IoHereDocument {
remove_tabs: false,
requires_expansion,
here_end: ast::Word::from(here_end),
here_end: ast::Word::from(here_tag),
doc: ast::Word::from(doc)
}
}

rule here_end() -> &'input Token =
rule here_tag() -> &'input Token =
word()

rule process_substitution() -> (ast::ProcessSubstitutionKind, ast::SubshellCommand) =
Expand Down
Loading

0 comments on commit 9e16201

Please sign in to comment.