added 'map', 'pop', 'push', 'fpop', 'fpush', and 'rotate' builtins

This commit is contained in:
2026-02-27 20:37:58 -05:00
parent ab2ce36af4
commit 0c40f17b60
10 changed files with 734 additions and 44 deletions

View File

@@ -5,23 +5,7 @@ use std::{
use crate::{
builtin::{
alias::{alias, unalias},
cd::cd,
complete::{compgen_builtin, complete_builtin},
dirstack::{dirs, popd, pushd},
echo::echo,
eval, exec,
flowctl::flowctl,
jobctl::{JobBehavior, continue_job, disown, jobs},
pwd::pwd,
read::read_builtin,
shift::shift,
shopt::shopt,
source::source,
test::double_bracket_test,
trap::{TrapTarget, trap},
varcmds::{export, local, readonly, unset},
zoltraak::zoltraak,
alias::{alias, unalias}, arrops::{arr_pop, arr_fpop, arr_push, arr_fpush, arr_rotate}, cd::cd, complete::{compgen_builtin, complete_builtin}, dirstack::{dirs, popd, pushd}, echo::echo, eval, exec, flowctl::flowctl, jobctl::{JobBehavior, continue_job, disown, jobs}, map, pwd::pwd, read::read_builtin, shift::shift, shopt::shopt, source::source, test::double_bracket_test, trap::{TrapTarget, trap}, varcmds::{export, local, readonly, unset}, zoltraak::zoltraak
},
expand::{expand_aliases, glob_to_regex},
jobs::{ChildProc, JobStack, dispatch_job},
@@ -817,6 +801,12 @@ impl Dispatcher {
"unset" => unset(cmd, io_stack_mut, curr_job_mut),
"complete" => complete_builtin(cmd, io_stack_mut, curr_job_mut),
"compgen" => compgen_builtin(cmd, io_stack_mut, curr_job_mut),
"map" => map::map(cmd, io_stack_mut, curr_job_mut),
"pop" => arr_pop(cmd, io_stack_mut, curr_job_mut),
"fpop" => arr_fpop(cmd, io_stack_mut, curr_job_mut),
"push" => arr_push(cmd, io_stack_mut, curr_job_mut),
"fpush" => arr_fpush(cmd, io_stack_mut, curr_job_mut),
"rotate" => arr_rotate(cmd, io_stack_mut, curr_job_mut),
"true" | ":" => {
state::set_status(0);
Ok(())

View File

@@ -912,6 +912,35 @@ pub fn ends_with_unescaped(slice: &str, pat: &str) -> bool {
slice.ends_with(pat) && !pos_is_escaped(slice, slice.len() - pat.len())
}
pub fn split_all_unescaped(slice: &str, pat: &str) -> Vec<String> {
let mut cursor = 0;
let mut splits = vec![];
while let Some(split) = split_at_unescaped(&slice[cursor..], pat) {
cursor += split.0.len() + pat.len();
splits.push(split.0);
}
if let Some(remaining) = slice.get(cursor..) {
splits.push(remaining.to_string());
}
splits
}
pub fn split_at_unescaped(slice: &str, pat: &str) -> Option<(String,String)> {
let mut window_start = 0;
let mut window_end = pat.len();
if window_end > slice.len() {
return None;
}
while window_end <= slice.len() {
if &slice[window_start..window_end] == pat && !pos_is_escaped(slice, window_start) {
return Some((slice[..window_start].to_string(), slice[window_end..].to_string()));
}
window_start += 1;
window_end += 1;
}
None
}
pub fn pos_is_escaped(slice: &str, pos: usize) -> bool {
let bytes = slice.as_bytes();
let mut escaped = false;

View File

@@ -955,6 +955,7 @@ impl ParseStream {
};
case_blocks.push(case_node);
self.catch_separator(&mut node_tks);
if self.check_keyword("esac") {
node_tks.push(self.next_tk().unwrap());
self.assert_separator(&mut node_tks)?;
@@ -1057,6 +1058,7 @@ impl ParseStream {
}
}
self.catch_separator(&mut node_tks);
if !self.check_keyword("fi") || !self.next_tk_is_some() {
self.panic_mode(&mut node_tks);
return Err(parse_err_full(
@@ -1139,6 +1141,7 @@ impl ParseStream {
body.push(node)
}
self.catch_separator(&mut node_tks);
if !self.check_keyword("done") || !self.next_tk_is_some() {
self.panic_mode(&mut node_tks);
return Err(parse_err_full(
@@ -1210,6 +1213,7 @@ impl ParseStream {
));
};
self.catch_separator(&mut node_tks);
if !self.check_keyword("done") || !self.next_tk_is_some() {
self.panic_mode(&mut node_tks);
return Err(parse_err_full(