Implemented loops and redirection for shell structures

This commit is contained in:
2025-03-05 01:37:51 -05:00
parent 1b3e2c0887
commit 90ef005901
16 changed files with 277 additions and 98 deletions

View File

@@ -1,6 +1,6 @@
use shellenv::jobs::{ChildProc, JobBldr};
use crate::{parse::parse::{NdFlag, Node, NdRule}, prelude::*};
use crate::{parse::parse::{Node, NdRule}, prelude::*};
pub fn pwd(node: Node, shenv: &mut ShEnv) -> ShResult<()> {
let rule = node.into_rule();

View File

@@ -1,8 +1,9 @@
use crate::{parse::parse::SynTree, prelude::*};
use crate::prelude::*;
pub fn exec_if(node: Node, shenv: &mut ShEnv) -> ShResult<()> {
let rule = node.into_rule();
if let NdRule::IfThen { cond_blocks, else_block } = rule {
if let NdRule::IfThen { cond_blocks, else_block, redirs } = rule {
shenv.collect_redirs(redirs);
if shenv.ctx().flags().contains(ExecFlags::NO_FORK) {
shenv.ctx_mut().unset_flag(ExecFlags::NO_FORK);
}
@@ -11,17 +12,15 @@ pub fn exec_if(node: Node, shenv: &mut ShEnv) -> ShResult<()> {
while let Some(block) = cond_blocks.next() {
let cond = block.0;
let body = block.1;
let ast = SynTree::from_vec(cond);
Executor::new(ast,shenv).walk()?;
if shenv.get_code() == 0 {
let ast = SynTree::from_vec(body);
return Executor::new(ast,shenv).walk()
let ret = shenv.exec_as_cond(cond)?;
if ret == 0 {
shenv.exec_as_body(body)?;
return Ok(())
}
}
if let Some(block) = else_block {
let ast = SynTree::from_vec(block);
Executor::new(ast,shenv).walk()?;
shenv.exec_as_body(block)?;
}
} else { unreachable!() }
Ok(())

48
src/execute/loops.rs Normal file
View File

@@ -0,0 +1,48 @@
use crate::{parse::parse::LoopKind, prelude::*};
pub fn exec_loop(node: Node, shenv: &mut ShEnv) -> ShResult<()> {
let rule = node.into_rule();
if let NdRule::Loop { kind, cond, body, redirs } = rule {
shenv.collect_redirs(redirs);
if shenv.ctx().flags().contains(ExecFlags::NO_FORK) {
shenv.ctx_mut().unset_flag(ExecFlags::NO_FORK);
}
loop {
let ret = shenv.exec_as_cond(cond.clone())?;
match kind {
LoopKind::While => {
if ret == 0 {
match shenv.exec_as_body(body.clone()) {
Ok(_) => continue,
Err(e) => {
match e.kind() {
ShErrKind::LoopContinue => continue,
ShErrKind::LoopBreak => break,
_ => return Err(e.into())
}
}
}
} else { break }
}
LoopKind::Until => {
if ret != 0 {
match shenv.exec_as_body(body.clone()) {
Ok(_) => continue,
Err(e) => {
match e.kind() {
ShErrKind::LoopContinue => continue,
ShErrKind::LoopBreak => break,
_ => return Err(e.into())
}
}
}
} else { break }
}
}
}
} else { unreachable!() }
Ok(())
}

View File

@@ -5,6 +5,7 @@ use shellenv::jobs::{ChildProc, JobBldr};
use crate::{builtin::export::export, libsh::{error::Blame, sys::{execvpe, get_bin_path}, utils::{ArgVec, StrOps}}, parse::{lex::Token, parse::{CmdGuard, NdFlag, Node, NdRule, SynTree}}, prelude::*};
pub mod ifthen;
pub mod loops;
pub fn exec_input<S: Into<String>>(input: S, shenv: &mut ShEnv) -> ShResult<()> {
let input = input.into();
@@ -41,6 +42,7 @@ impl<'a> Executor<'a> {
Self { ast, shenv }
}
pub fn walk(&mut self) -> ShResult<()> {
self.shenv.ctx_mut().descend()?;
log!(DEBUG, "Starting walk");
while let Some(node) = self.ast.next_node() {
if let NdRule::CmdList { cmds } = node.clone().into_rule() {
@@ -48,6 +50,7 @@ impl<'a> Executor<'a> {
exec_list(cmds, self.shenv).try_blame(node.as_raw(self.shenv),node.span())?
} else { unreachable!() }
}
self.shenv.ctx_mut().ascend();
Ok(())
}
}
@@ -77,6 +80,7 @@ fn exec_list(list: Vec<(Option<CmdGuard>, Node)>, shenv: &mut ShEnv) -> ShResult
NdRule::Command {..} => dispatch_command(cmd, shenv).try_blame(cmd_raw, span)?,
NdRule::Subshell {..} => exec_subshell(cmd,shenv).try_blame(cmd_raw, span)?,
NdRule::IfThen {..} => ifthen::exec_if(cmd, shenv).try_blame(cmd_raw, span)?,
NdRule::Loop {..} => loops::exec_loop(cmd, shenv).try_blame(cmd_raw, span)?,
NdRule::FuncDef {..} => exec_funcdef(cmd,shenv).try_blame(cmd_raw, span)?,
NdRule::Assignment {..} => exec_assignment(cmd,shenv).try_blame(cmd_raw, span)?,
NdRule::Pipeline {..} => exec_pipeline(cmd, shenv).try_blame(cmd_raw, span)?,
@@ -244,6 +248,8 @@ fn exec_builtin(node: Node, shenv: &mut ShEnv) -> ShResult<()> {
"alias" => alias(node, shenv)?,
"exit" => sh_flow(node, shenv, ShErrKind::CleanExit)?,
"return" => sh_flow(node, shenv, ShErrKind::FuncReturn)?,
"break" => sh_flow(node, shenv, ShErrKind::LoopBreak)?,
"continue" => sh_flow(node, shenv, ShErrKind::LoopContinue)?,
_ => unimplemented!("Have not yet implemented support for builtin `{}'",command)
}
log!(TRACE, "done");

View File

@@ -1,7 +1,7 @@
use crate::prelude::*;
pub fn expand_cmdsub(token: Token, shenv: &mut ShEnv) -> ShResult<Vec<Token>> {
let mut new_tokens = vec![];
let new_tokens = vec![];
let cmdsub_raw = token.as_raw(shenv);
let body = &cmdsub_raw[2..cmdsub_raw.len() - 1].to_string(); // From '$(this)' to 'this'

View File

@@ -3,7 +3,6 @@ pub mod tilde;
pub mod alias;
pub mod cmdsub;
use alias::expand_aliases;
use vars::{expand_dquote, expand_var};
use tilde::expand_tilde;

View File

@@ -1,7 +1,6 @@
use core::{arch::asm, fmt::{self, Debug, Display, Write}, ops::Deref};
use std::{os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd}, str::FromStr};
use core::fmt::{Debug, Display, Write};
use std::{os::fd::{AsRawFd, BorrowedFd}, str::FromStr};
use nix::libc::getpgrp;
use crate::prelude::*;
@@ -311,7 +310,7 @@ impl CmdRedirs {
let Redir { src, op, tgt } = redir;
let src = borrow_fd(src);
let mut file_fd = if let RedirTarget::File(path) = tgt {
let file_fd = if let RedirTarget::File(path) = tgt {
let flags = match op {
RedirType::Input => OFlag::O_RDONLY,
RedirType::Output => OFlag::O_WRONLY | OFlag::O_CREAT | OFlag::O_TRUNC,
@@ -331,7 +330,7 @@ impl CmdRedirs {
pub fn open_fd_tgts(&mut self) -> ShResult<()> {
while let Some(redir) = self.targets_fd.pop() {
let Redir { src, op: _, tgt } = redir;
let mut tgt = if let RedirTarget::Fd(fd) = tgt {
let tgt = if let RedirTarget::Fd(fd) = tgt {
borrow_fd(fd)
} else { unreachable!() };
let src = borrow_fd(src);

View File

@@ -1,4 +1,4 @@
use std::{cell::Ref, fmt::{Debug, Display}};
use std::fmt::Debug;
use crate::prelude::*;

View File

@@ -1,5 +1,4 @@
use core::fmt::Display;
use std::{cell::Ref, str::FromStr};
use std::{iter::Peekable, str::FromStr};
use crate::prelude::*;
@@ -86,9 +85,9 @@ pub enum NdRule {
Command { argv: Vec<Token>, redirs: Vec<Redir> },
Assignment { assignments: Vec<Token>, cmd: Option<Box<Node>> },
FuncDef { name: Token, body: Token },
IfThen { cond_blocks: Vec<(Vec<Node>,Vec<Node>)>, else_block: Option<Vec<Node>> },
Loop { kind: LoopKind, cond: Vec<Node>, body: Vec<Node> },
ForLoop { vars: Vec<Token>, arr: Vec<Token>, body: Vec<Node> },
IfThen { cond_blocks: Vec<(Vec<Node>,Vec<Node>)>, else_block: Option<Vec<Node>>, redirs: Vec<Redir> },
Loop { kind: LoopKind, cond: Vec<Node>, body: Vec<Node>, redirs: Vec<Redir> },
ForLoop { vars: Vec<Token>, arr: Vec<Token>, body: Vec<Node>, redirs: Vec<Redir> },
Subshell { body: Token, argv: Vec<Token>, redirs: Vec<Redir> },
CmdList { cmds: Vec<(Option<CmdGuard>,Node)> },
Pipeline { cmds: Vec<Node> }
@@ -175,7 +174,7 @@ impl<'a> Parser<'a> {
}
}
fn get_span(toks: &Vec<Token>, shenv: &mut ShEnv) -> ShResult<Rc<RefCell<Span>>> {
pub fn get_span(toks: &Vec<Token>, shenv: &mut ShEnv) -> ShResult<Rc<RefCell<Span>>> {
if toks.is_empty() {
Err(ShErr::simple(ShErrKind::InternalErr, "Get_span was given an empty token list"))
} else {
@@ -202,6 +201,38 @@ fn get_lists(mut tokens: &[Token], shenv: &mut ShEnv) -> (usize,Vec<Node>) {
(tokens_eaten,lists)
}
fn get_redir(token: Token, token_slice: &[Token], shenv: &mut ShEnv) -> ShResult<(usize,Redir)> {
let mut tokens_eaten = 0;
let mut tokens_iter = token_slice.into_iter();
let redir_raw = shenv.input_slice(token.span());
let mut redir_bldr = RedirBldr::from_str(&redir_raw).unwrap();
// If there isn't an FD target, get the next token and use it as the filename
if redir_bldr.tgt().is_none() {
if let Some(filename) = tokens_iter.next() {
// Make sure it's a word and not an operator or something
if !matches!(filename.rule(), TkRule::SQuote | TkRule::DQuote | TkRule::Ident) || KEYWORDS.contains(&filename.rule()) {
let mut err = ShErr::simple(ShErrKind::ParseErr, "Did not find a target for this redirection");
let input = shenv.input_slice(token.span()).to_string();
err.blame(input, token.span());
return Err(err)
}
tokens_eaten += 1;
// Construct the Path object
let filename_raw = shenv.input_slice(filename.span()).to_string();
let filename_path = PathBuf::from(filename_raw);
let tgt = RedirTarget::File(filename_path);
// Update the builder
redir_bldr = redir_bldr.with_tgt(tgt);
} else {
let mut err = ShErr::simple(ShErrKind::ParseErr, "Did not find a target for this redirection");
let input = shenv.input_slice(token.span()).to_string();
err.blame(input, token.span());
return Err(err)
}
}
Ok((tokens_eaten,redir_bldr.build()))
}
// TODO: Redirs with FD sources appear to be looping endlessly for some reason
ndrule_def!(Main, shenv, |tokens: &[Token], shenv: &mut ShEnv| {
@@ -316,6 +347,7 @@ ndrule_def!(ForLoop, shenv, |mut tokens: &[Token], shenv: &mut ShEnv| {
let mut node_toks = vec![];
let mut vars = vec![];
let mut arr = vec![];
let mut redirs = vec![];
let body: Vec<Node>;
if let Some(token) = tokens_iter.next() {
@@ -376,20 +408,46 @@ ndrule_def!(ForLoop, shenv, |mut tokens: &[Token], shenv: &mut ShEnv| {
body = lists;
tokens_iter = tokens.iter().peekable();
if let Some(token) = tokens_iter.next() {
node_toks.push(token.clone());
if token.rule() != TkRule::Done {
let span = get_span(&node_toks, shenv)?;
return Err(err("Expected `done` after for loop",span,shenv))
let mut closed = false;
while let Some(token) = tokens_iter.next() {
match token.rule() {
TkRule::Done => {
node_toks.push(token.clone());
tokens = &tokens[1..];
closed = true;
}
TkRule::Sep => {
node_toks.push(token.clone());
tokens = &tokens[1..];
if closed { break }
}
TkRule::RedirOp if closed => {
node_toks.push(token.clone());
tokens = &tokens[1..];
let (used,redir) = get_redir(token.clone(), tokens, shenv)?;
for _ in 0..used {
if let Some(token) = tokens_iter.next() {
node_toks.push(token.clone());
}
}
tokens = &tokens[used..];
redirs.push(redir);
}
_ => {
let span = get_span(&node_toks, shenv)?;
return Err(err("Expected `done` after for loop",span,shenv))
}
}
} else {
}
if !closed {
let span = get_span(&node_toks, shenv)?;
return Err(err("Expected `done` after for loop",span,shenv))
}
let span = get_span(&node_toks, shenv)?;
let node = Node {
node_rule: NdRule::ForLoop { vars, arr, body },
node_rule: NdRule::ForLoop { vars, arr, body, redirs },
tokens: node_toks,
span,
flags: NdFlag::empty()
@@ -405,6 +463,7 @@ ndrule_def!(IfThen, shenv, |mut tokens: &[Token], shenv: &mut ShEnv| {
let mut tokens_iter = tokens.iter().peekable();
let mut node_toks = vec![];
let mut cond_blocks = vec![];
let mut redirs = vec![];
let mut else_block: Option<Vec<Node>> = None;
if let Some(token) = tokens_iter.next() {
@@ -518,14 +577,32 @@ ndrule_def!(IfThen, shenv, |mut tokens: &[Token], shenv: &mut ShEnv| {
node_toks.push(token.clone());
tokens = &tokens[1..];
}
TkRule::Sep | TkRule::Whitespace => {
TkRule::Whitespace => {
node_toks.push(token.clone());
tokens = &tokens[1..];
}
TkRule::Sep => {
node_toks.push(token.clone());
tokens = &tokens[1..];
if closed { break }
}
TkRule::RedirOp if closed => {
node_toks.push(token.clone());
tokens = &tokens[1..];
let (used,redir) = get_redir(token.clone(), tokens, shenv)?;
for _ in 0..used {
if let Some(token) = tokens_iter.next() {
node_toks.push(token.clone());
}
}
tokens = &tokens[used..];
log!(DEBUG,redir);
log!(DEBUG,tokens);
redirs.push(redir);
}
_ => {
let span = get_span(&node_toks, shenv)?;
return Err(err("Unexpected token in if statement",span,shenv))
return Err(err(&format!("Unexpected token in if statement: {:?}",token.rule()),span,shenv))
}
}
}
@@ -537,7 +614,7 @@ ndrule_def!(IfThen, shenv, |mut tokens: &[Token], shenv: &mut ShEnv| {
let span = get_span(&node_toks, shenv)?;
let node = Node {
node_rule: NdRule::IfThen { cond_blocks, else_block },
node_rule: NdRule::IfThen { cond_blocks, else_block, redirs },
tokens: node_toks,
span,
flags: NdFlag::empty()
@@ -552,6 +629,7 @@ ndrule_def!(Loop, shenv, |mut tokens: &[Token], shenv: &mut ShEnv| {
};
let mut tokens_iter = tokens.iter().peekable();
let mut node_toks = vec![];
let mut redirs = vec![];
let kind: LoopKind;
let cond: Vec<Node>;
let body: Vec<Node>;
@@ -621,6 +699,18 @@ ndrule_def!(Loop, shenv, |mut tokens: &[Token], shenv: &mut ShEnv| {
node_toks.push(token.clone());
tokens = &tokens[1..];
}
TkRule::RedirOp if closed => {
node_toks.push(token.clone());
tokens = &tokens[1..];
let (used,redir) = get_redir(token.clone(), tokens, shenv)?;
for _ in 0..used {
if let Some(token) = tokens_iter.next() {
node_toks.push(token.clone());
}
}
tokens = &tokens[used..];
redirs.push(redir);
}
_ => {
let span = get_span(&node_toks,shenv)?;
return Err(err("Unexpected token in loop",span,shenv))
@@ -635,7 +725,7 @@ ndrule_def!(Loop, shenv, |mut tokens: &[Token], shenv: &mut ShEnv| {
let span = get_span(&node_toks, shenv)?;
let node = Node {
node_rule: NdRule::Loop { kind, cond, body },
node_rule: NdRule::Loop { kind, cond, body, redirs },
tokens: node_toks,
span,
flags: NdFlag::empty()
@@ -684,7 +774,7 @@ ndrule_def!(FuncDef, shenv, |tokens: &[Token], shenv: &mut ShEnv| {
});
ndrule_def!(Subshell, shenv, |tokens: &[Token], shenv: &mut ShEnv| {
let mut tokens_iter = tokens.iter();
let mut tokens_iter = tokens.into_iter();
let mut node_toks = vec![];
let mut argv = vec![];
let mut redirs = vec![];
@@ -715,34 +805,14 @@ ndrule_def!(Subshell, shenv, |tokens: &[Token], shenv: &mut ShEnv| {
}
TkRule::RedirOp => {
node_toks.push(token.clone());
// Get the raw redirection text, e.g. "1>&2" or "2>" or ">>" or something
let redir_raw = shenv.input_slice(token.span());
let mut redir_bldr = RedirBldr::from_str(&redir_raw).unwrap();
// If there isn't an FD target, get the next token and use it as the filename
if redir_bldr.tgt().is_none() {
if let Some(filename) = tokens_iter.next() {
// Make sure it's a word and not an operator or something
if !matches!(filename.rule(), TkRule::SQuote | TkRule::DQuote | TkRule::Ident) || KEYWORDS.contains(&filename.rule()) {
let mut err = ShErr::simple(ShErrKind::ParseErr, "Did not find a target for this redirection");
let input = shenv.input_slice(token.span()).to_string();
err.blame(input, token.span());
return Err(err)
}
node_toks.push(filename.clone());
// Construct the Path object
let filename_raw = shenv.input_slice(filename.span()).to_string();
let filename_path = PathBuf::from(filename_raw);
let tgt = RedirTarget::File(filename_path);
// Update the builder
redir_bldr = redir_bldr.with_tgt(tgt);
} else {
let mut err = ShErr::simple(ShErrKind::ParseErr, "Did not find a target for this redirection");
let input = shenv.input_slice(token.span()).to_string();
err.blame(input, token.span());
return Err(err)
let slice = &tokens_iter.clone().map(|tk| tk.clone()).collect::<Vec<_>>();
let (used,redir) = get_redir(token.clone(), slice, shenv)?;
for _ in 0..used {
if let Some(token) = tokens_iter.next() {
node_toks.push(token.clone());
}
}
redirs.push(redir_bldr.build());
redirs.push(redir);
}
_ => break
}
@@ -841,19 +911,19 @@ ndrule_def!(Pipeline, shenv, |mut tokens: &[Token], shenv: &mut ShEnv| {
ndrule_def!(Command, shenv, |tokens: &[Token], shenv: &mut ShEnv| {
log!(TRACE, "Parsing command");
let mut tokens = tokens.iter().peekable();
let mut tokens_iter = tokens.iter().peekable();
let mut node_toks = vec![];
let mut argv = vec![];
let mut redirs = vec![];
while let Some(token) = tokens.peek() {
while let Some(token) = tokens_iter.peek() {
match token.rule() {
TkRule::AndOp | TkRule::OrOp | TkRule::PipeOp | TkRule::ErrPipeOp => {
break
}
_ => { /* Keep going */ }
}
let token = tokens.next().unwrap();
let token = tokens_iter.next().unwrap();
node_toks.push(token.clone());
match token.rule() {
TkRule::Ident |
@@ -865,34 +935,14 @@ ndrule_def!(Command, shenv, |tokens: &[Token], shenv: &mut ShEnv| {
argv.push(token.clone());
}
TkRule::RedirOp => {
// Get the raw redirection text, e.g. "1>&2" or "2>" or ">>" or something
let redir_raw = shenv.input_slice(token.span()).to_string();
let mut redir_bldr = RedirBldr::from_str(&redir_raw).unwrap();
// If there isn't an FD target, get the next token and use it as the filename
if redir_bldr.tgt().is_none() {
if let Some(filename) = tokens.next() {
// Make sure it's a word and not an operator or something
if !matches!(filename.rule(), TkRule::SQuote | TkRule::DQuote | TkRule::Ident) || KEYWORDS.contains(&filename.rule()) {
let mut err = ShErr::simple(ShErrKind::ParseErr, "Did not find a target for this redirection");
let input = shenv.input_slice(token.span()).to_string();
err.blame(input, token.span());
return Err(err)
}
node_toks.push(filename.clone());
// Construct the Path object
let filename_raw = shenv.input_slice(filename.span()).to_string();
let filename_path = PathBuf::from(filename_raw);
let tgt = RedirTarget::File(filename_path);
// Update the builder
redir_bldr = redir_bldr.with_tgt(tgt);
} else {
let mut err = ShErr::simple(ShErrKind::ParseErr, "Did not find a target for this redirection");
let input = shenv.input_slice(token.span()).to_string();
err.blame(input, token.span());
return Err(err)
let slice = &tokens_iter.clone().map(|tk| tk.clone()).collect::<Vec<_>>();
let (used,redir) = get_redir(token.clone(), slice, shenv)?;
for _ in 0..used {
if let Some(token) = tokens_iter.next() {
node_toks.push(token.clone());
}
}
redirs.push(redir_bldr.build());
redirs.push(redir);
}
TkRule::Sep => break,
_ => return Err(

View File

@@ -150,6 +150,7 @@ pub use crate::{
},
parse::{
parse::{
SynTree,
Node,
NdRule,
Parser,

View File

@@ -1,6 +1,6 @@
use crate::prelude::*;
use readline::SynHelper;
use rustyline::{config::Configurer, history::{DefaultHistory, History}, ColorMode, CompletionType, Config, DefaultEditor, EditMode, Editor};
use rustyline::{config::Configurer, history::{DefaultHistory, History}, ColorMode, CompletionType, Config, EditMode, Editor};
pub mod readline;
pub mod highlight;
@@ -8,7 +8,7 @@ pub mod validate;
fn init_rl<'a>(shenv: &'a mut ShEnv) -> Editor<SynHelper<'a>, DefaultHistory> {
let hist_path = std::env::var("FERN_HIST").unwrap_or_default();
let mut config = Config::builder()
let config = Config::builder()
.max_history_size(1000).unwrap()
.history_ignore_dups(true).unwrap()
.completion_prompt_limit(100)

View File

@@ -1,4 +1,4 @@
use rustyline::{completion::{Completer, FilenameCompleter}, highlight::Highlighter, hint::{Hint, Hinter}, history::{History, SearchDirection}, validate::{ValidationResult, Validator}, Helper};
use rustyline::{completion::{Completer, FilenameCompleter}, hint::{Hint, Hinter}, history::{History, SearchDirection}, Helper};
use crate::prelude::*;

View File

@@ -10,6 +10,9 @@ bitflags! {
#[derive(Clone,Debug)]
pub struct ExecCtx {
redirs: Vec<Redir>,
depth: usize,
state_stack: Vec<Self>,
max_depth: usize,
flags: ExecFlags,
io_masks: IoMasks,
saved_io: Option<SavedIo>
@@ -19,11 +22,63 @@ impl ExecCtx {
pub fn new() -> Self {
Self {
redirs: vec![],
depth: 0,
state_stack: vec![],
max_depth: 1500,
flags: ExecFlags::empty(),
io_masks: IoMasks::new(),
saved_io: None
}
}
pub fn push_state(&mut self) {
self.state_stack.push(self.clone());
}
pub fn pop_state(&mut self) {
if let Some(state) = self.state_stack.pop() {
*self = state;
}
}
pub fn descend(&mut self) -> ShResult<()> {
self.push_state();
self.depth += 1;
log!(DEBUG, "{}",self.depth);
if self.depth > self.max_depth {
return Err(
ShErr::simple(ShErrKind::ExecFail,"Exceeded maximum execution depth")
)
}
Ok(())
}
pub fn ascend(&mut self) {
self.pop_state();
self.depth = self.depth.saturating_sub(1);
}
pub fn as_cond(&self) -> Self {
let mut clone = self.clone();
let (cond_redirs,_) = self.sort_redirs();
clone.redirs = cond_redirs;
clone
}
pub fn as_body(&self) -> Self {
let mut clone = self.clone();
let (_,body_redirs) = self.sort_redirs();
clone.redirs = body_redirs;
clone
}
pub fn sort_redirs(&self) -> (Vec<Redir>,Vec<Redir>) {
let mut cond_redirs = vec![];
let mut body_redirs = vec![];
for redir in self.redirs.clone() {
match redir.op {
RedirType::Input |
RedirType::HereString |
RedirType::HereDoc => cond_redirs.push(redir),
RedirType::Output |
RedirType::Append => body_redirs.push(redir)
}
}
(cond_redirs,body_redirs)
}
pub fn masks(&self) -> &IoMasks {
&self.io_masks
}

View File

@@ -1,4 +1,3 @@
use std::cell::Ref;
use crate::prelude::*;

View File

@@ -1,8 +1,6 @@
use std::{fmt, sync::{Arc, LazyLock, RwLock}};
use nix::unistd::setpgid;
use shellenv::{disable_reaping, enable_reaping};
use sys::SIG_EXIT_OFFSET;
use crate::prelude::*;

View File

@@ -63,7 +63,32 @@ impl ShEnv {
}
}
self.input_man.clamp_all();
new_tokens
log!(DEBUG, new_tokens);
if new_tokens.is_empty() {
let empty = Token::new(
TkRule::Ident,
self.inputman_mut().new_span(repl_start, repl_start)
);
vec![empty]
} else {
new_tokens
}
}
pub fn exec_as_cond(&mut self, nodes: Vec<Node>) -> ShResult<i32> {
let saved = self.ctx().clone();
self.ctx = self.ctx().as_cond();
let ast = SynTree::from_vec(nodes);
Executor::new(ast, self).walk()?;
self.ctx = saved;
Ok(self.get_code())
}
pub fn exec_as_body(&mut self, nodes: Vec<Node>) -> ShResult<i32> {
let saved = self.ctx().clone();
self.ctx = self.ctx().as_body();
let ast = SynTree::from_vec(nodes);
Executor::new(ast, self).walk()?;
self.ctx = saved;
Ok(self.get_code())
}
pub fn new_input(&mut self, input: &str) {
self.input_man.clear();