Various additions and improvements

This commit is contained in:
2025-03-15 21:04:45 -04:00
parent ecfef2274f
commit 98739ba63a
31 changed files with 1421 additions and 341 deletions

View File

@@ -1,9 +1,9 @@
use std::collections::VecDeque;
use crate::{builtin::echo::echo, jobs::{dispatch_job, ChildProc, Job, JobBldr}, libsh::error::ShResult, prelude::*, procio::{IoFrame, IoPipe, IoStack}, state::{self, write_vars}};
use crate::{builtin::{cd::cd, echo::echo, export::export, pwd::pwd, shift::shift, source::source}, jobs::{dispatch_job, ChildProc, Job, JobBldr}, libsh::error::ShResult, prelude::*, procio::{IoFrame, IoPipe, IoStack}, state::{self, write_vars}};
use super::{lex::{Tk, TkFlags}, AssignKind, ConjunctNode, ConjunctOp, NdFlags, NdRule, Node, Redir, RedirType};
use super::{lex::{Span, Tk, TkFlags}, AssignKind, ConjunctNode, ConjunctOp, NdFlags, NdRule, Node, Redir, RedirType};
pub enum AssignBehavior {
Export,
@@ -26,11 +26,11 @@ impl ExecArgs {
let envp = Self::get_envp();
Self { cmd, argv, envp }
}
pub fn get_cmd(argv: &[String]) -> CString {
CString::new(argv[0].as_str()).unwrap()
pub fn get_cmd(argv: &[(String,Span)]) -> CString {
CString::new(argv[0].0.as_str()).unwrap()
}
pub fn get_argv(argv: Vec<String>) -> Vec<CString> {
argv.into_iter().map(|s| CString::new(s).unwrap()).collect()
pub fn get_argv(argv: Vec<(String,Span)>) -> Vec<CString> {
argv.into_iter().map(|s| CString::new(s.0).unwrap()).collect()
}
pub fn get_envp() -> Vec<CString> {
std::env::vars().map(|v| CString::new(format!("{}={}",v.0,v.1)).unwrap()).collect()
@@ -128,8 +128,14 @@ impl<'t> Dispatcher<'t> {
let cmd_raw = cmd.get_command().unwrap();
flog!(TRACE, "doing builtin");
let curr_job_mut = self.curr_job.as_mut().unwrap();
let io_stack_mut = &mut self.io_stack;
let result = match cmd_raw.span.as_str() {
"echo" => echo(cmd, &mut self.io_stack, curr_job_mut),
"echo" => echo(cmd, io_stack_mut, curr_job_mut),
"cd" => cd(cmd, curr_job_mut),
"export" => export(cmd, curr_job_mut),
"pwd" => pwd(cmd, io_stack_mut, curr_job_mut),
"source" => source(cmd, curr_job_mut),
"shift" => shift(cmd, curr_job_mut),
_ => unimplemented!("Have not yet added support for builtin '{}'", cmd_raw.span.as_str())
};
@@ -152,13 +158,13 @@ impl<'t> Dispatcher<'t> {
};
env_vars_to_unset = self.set_assignments(assignments, assign_behavior);
}
for redir in cmd.redirs {
self.io_stack.push_to_frame(redir);
}
if argv.is_empty() {
return Ok(())
}
self.io_stack.append_to_frame(cmd.redirs);
let exec_args = ExecArgs::new(argv);
let io_frame = self.io_stack.pop_frame();
run_fork(
@@ -216,14 +222,16 @@ impl<'t> Dispatcher<'t> {
}
}
pub fn prepare_argv(argv: Vec<Tk>) -> Vec<String> {
pub fn prepare_argv(argv: Vec<Tk>) -> Vec<(String,Span)> {
let mut args = vec![];
for arg in argv {
let flags = arg.flags;
let span = arg.span.clone();
let expanded = arg.expand(span, flags);
args.extend(expanded.get_words());
let expanded = arg.expand(span.clone(), flags);
for exp in expanded.get_words() {
args.push((exp,span.clone()))
}
}
args
}

View File

@@ -2,7 +2,7 @@ use std::{fmt::Display, ops::{Bound, Deref, Range, RangeBounds}};
use bitflags::bitflags;
use crate::{builtin::BUILTINS, prelude::*};
use crate::{builtin::BUILTINS, libsh::error::{ShErr, ShErrKind, ShResult}, prelude::*};
pub const KEYWORDS: [&'static str;14] = [
"if",
@@ -87,33 +87,9 @@ impl Default for TkRule {
}
}
#[derive(Clone,Copy,PartialEq,Debug)]
pub enum TkErr {
Null,
UntermQuote,
UntermSubsh,
UntermEscape,
UntermBrace,
BadRedir,
BadPipe,
HangingDelim,
}
impl Default for TkErr {
fn default() -> Self {
TkErr::Null
}
}
pub enum TkState {
Raw,
}
#[derive(Clone,Debug,PartialEq,Default)]
pub struct Tk<'s> {
pub class: TkRule,
pub err_span: Option<Span<'s>>,
pub err: TkErr,
pub span: Span<'s>,
pub flags: TkFlags
}
@@ -121,7 +97,7 @@ pub struct Tk<'s> {
// There's one impl here and then another in expand.rs which has the expansion logic
impl<'s> Tk<'s> {
pub fn new(class: TkRule, span: Span<'s>) -> Self {
Self { class, err_span: None, err: TkErr::Null, span, flags: TkFlags::empty() }
Self { class, span, flags: TkFlags::empty() }
}
pub fn to_string(&self) -> String {
match &self.class {
@@ -129,13 +105,6 @@ impl<'s> Tk<'s> {
_ => self.span.as_str().to_string()
}
}
pub fn set_err(&mut self, range: Range<usize>, slice: &'s str, err: TkErr) {
self.err_span = Some(Span::new(range, slice));
self.err = err
}
pub fn is_err(&self) -> bool {
self.err_span.is_some()
}
pub fn source(&self) -> &'s str {
self.span.source
}
@@ -231,7 +200,7 @@ impl<'t> LexStream<'t> {
pub fn next_is_not_cmd(&mut self) {
self.flags &= !LexFlags::NEXT_IS_CMD;
}
pub fn read_redir(&mut self) -> Option<Tk<'t>> {
pub fn read_redir(&mut self) -> Option<ShResult<Tk<'t>>> {
assert!(self.cursor <= self.source.len());
let slice = self.slice(self.cursor..)?;
let mut pos = self.cursor;
@@ -259,10 +228,13 @@ impl<'t> LexStream<'t> {
if !found_fd {
let err = TkErr::BadRedir;
tk = self.get_token(self.cursor..pos, TkRule::Redir);
tk.set_err(self.cursor..pos, self.source, err);
break
return Some(Err(
ShErr::full(
ShErrKind::ParseErr,
"Invalid redirection",
Span::new(self.cursor..pos, self.source).into()
)
));
} else {
tk = self.get_token(self.cursor..pos, TkRule::Redir);
break
@@ -304,9 +276,9 @@ impl<'t> LexStream<'t> {
}
self.cursor = pos;
Some(tk)
Some(Ok(tk))
}
pub fn read_string(&mut self) -> Tk<'t> {
pub fn read_string(&mut self) -> ShResult<Tk<'t>> {
assert!(self.cursor <= self.source.len());
let slice = self.slice_from_cursor().unwrap();
let mut pos = self.cursor;
@@ -351,10 +323,12 @@ impl<'t> LexStream<'t> {
}
let mut new_tk = self.get_token(self.cursor..pos, TkRule::Str);
if self.in_quote && !self.flags.contains(LexFlags::LEX_UNFINISHED) {
new_tk.set_err(
quote_pos.unwrap()..pos,
self.source,
TkErr::UntermQuote
return Err(
ShErr::full(
ShErrKind::ParseErr,
"Unterminated quote",
new_tk.span.into(),
)
);
}
if self.flags.contains(LexFlags::NEXT_IS_CMD) {
@@ -373,7 +347,7 @@ impl<'t> LexStream<'t> {
}
}
self.cursor = pos;
new_tk
Ok(new_tk)
}
pub fn get_token(&self, range: Range<usize>, class: TkRule) -> Tk<'t> {
let span = Span::new(range, self.source);
@@ -382,7 +356,7 @@ impl<'t> LexStream<'t> {
}
impl<'t> Iterator for LexStream<'t> {
type Item = Tk<'t>;
type Item = ShResult<Tk<'t>>;
fn next(&mut self) -> Option<Self::Item> {
assert!(self.cursor <= self.source.len());
// We are at the end of the input
@@ -394,14 +368,14 @@ impl<'t> Iterator for LexStream<'t> {
// Return the EOI token
let token = self.get_token(self.cursor..self.cursor, TkRule::EOI);
self.flags |= LexFlags::STALE;
return Some(token)
return Some(Ok(token))
}
}
// Return the SOI token
if self.flags.contains(LexFlags::FRESH) {
self.flags &= !LexFlags::FRESH;
let token = self.get_token(self.cursor..self.cursor, TkRule::SOI);
return Some(token)
return Some(Ok(token))
}
// If we are just reading raw words, short circuit here
@@ -486,13 +460,19 @@ impl<'t> Iterator for LexStream<'t> {
_ => {
if let Some(tk) = self.read_redir() {
self.next_is_not_cmd();
tk
match tk {
Ok(tk) => tk,
Err(e) => return Some(Err(e))
}
} else {
self.read_string()
match self.read_string() {
Ok(tk) => tk,
Err(e) => return Some(Err(e))
}
}
}
};
Some(token)
Some(Ok(token))
}
}

View File

@@ -25,6 +25,16 @@ impl<'t> Node<'t> {
let command = argv.iter().find(|tk| tk.flags.contains(TkFlags::IS_CMD))?;
Some(command)
}
pub fn get_span(&'t self) -> Span<'t> {
let Some(first_tk) = self.tokens.first() else {
unreachable!()
};
let Some(last_tk) = self.tokens.last() else {
unreachable!()
};
Span::new(first_tk.span.start..last_tk.span.end, first_tk.span.get_source())
}
}
bitflags! {
@@ -267,10 +277,12 @@ impl<'t> ParseStream<'t> {
};
let conjunction = ConjunctNode { cmd: Box::new(block), operator: conjunct_op };
elements.push(conjunction);
let Some(tk) = self.next_tk() else {
break
};
node_tks.push(tk);
if conjunct_op != ConjunctOp::Null {
let Some(tk) = self.next_tk() else {
break
};
node_tks.push(tk);
}
if conjunct_op == ConjunctOp::Null {
break
}
@@ -385,7 +397,7 @@ impl<'t> ParseStream<'t> {
ShErr::full(
ShErrKind::ParseErr,
"Expected a filename after this redirection",
tk.span.clone()
tk.span.clone().into()
)
)
};
@@ -420,7 +432,7 @@ impl<'t> ParseStream<'t> {
ShErr::full(
ShErrKind::InternalErr,
"Error opening file for redirection",
path_tk.span.clone()
path_tk.span.clone().into()
)
)
};
@@ -565,7 +577,9 @@ impl<'t> Iterator for ParseStream<'t> {
}
}
match self.parse_cmd_list() {
Ok(Some(node)) => return Some(Ok(node)),
Ok(Some(node)) => {
return Some(Ok(node));
}
Ok(None) => return None,
Err(e) => return Some(Err(e))
}