Various additions and improvements
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user