Implemented case statements

This commit is contained in:
2025-03-06 15:32:28 -05:00
parent d2554777f5
commit 3034f6c8d2
17 changed files with 1528 additions and 1138 deletions

View File

@@ -1,15 +1,16 @@
use crate::prelude::*;
#[derive(Clone,Debug)]
#[derive(Clone,Debug,PartialEq)]
pub struct InputMan {
input: Option<String>,
saved_input: Option<String>,
spans: Vec<Rc<RefCell<Span>>>,
saved_spans: Vec<Span>
}
impl InputMan {
pub fn new() -> Self {
Self { input: None, spans: vec![] }
Self { input: None, saved_input: None, spans: vec![], saved_spans: vec![] }
}
pub fn clear(&mut self) {
*self = Self::new();
@@ -23,6 +24,24 @@ impl InputMan {
pub fn get_input_mut(&mut self) -> Option<&mut String> {
self.input.as_mut()
}
pub fn save_state(&mut self) {
self.saved_input = self.input.clone();
self.saved_spans.clear();
for span in &self.spans {
self.saved_spans.push(span.borrow().clone());
}
}
pub fn load_state(&mut self) {
if self.saved_input.is_some() {
self.input = self.saved_input.take();
for (span, saved_span) in self.spans.iter_mut().zip(self.saved_spans.iter()) {
*span.borrow_mut() = saved_span.clone();
}
self.saved_spans.clear();
}
}
pub fn new_span(&mut self, start: usize, end: usize) -> Rc<RefCell<Span>> {
if let Some(_input) = &self.input {
let span = Rc::new(RefCell::new(Span::new(start, end)));

View File

@@ -32,6 +32,11 @@ impl ShEnv {
&self.input_man.get_slice(span).unwrap_or_default()
}
pub fn expand_input(&mut self, new: &str, repl_span: Rc<RefCell<Span>>) -> Vec<Token> {
log!(DEBUG,repl_span);
if repl_span.borrow().expanded {
return vec![];
}
repl_span.borrow_mut().expanded = true;
let saved_spans = self.input_man.spans_mut().clone();
let mut new_tokens = Lexer::new(new.to_string(), self).lex();
*self.input_man.spans_mut() = saved_spans;
@@ -45,9 +50,10 @@ impl ShEnv {
let repl_end = repl_span.borrow().end();
let range = repl_start..repl_end;
if let Some(ref mut input) = self.input_man.get_input_mut() {
if let Some(input) = self.input_man.get_input_mut() {
let old = &input[range.clone()];
let delta: isize = new.len() as isize - old.len() as isize;
log!(DEBUG, input);
input.replace_range(range, new);
let expanded = input.clone();
log!(DEBUG, expanded);
@@ -74,6 +80,11 @@ impl ShEnv {
new_tokens
}
}
/// Executes a group of command lists, and only uses redirections that operate on input
/// For instance:
/// `if cat; then echo foo; fi < file.txt > otherfile.txt`
/// `cat` will be executed as a condition, meaning the input from file.txt will be the only
/// redirection used.
pub fn exec_as_cond(&mut self, nodes: Vec<Node>) -> ShResult<i32> {
let saved = self.ctx().clone();
self.ctx = self.ctx().as_cond();
@@ -82,6 +93,11 @@ impl ShEnv {
self.ctx = saved;
Ok(self.get_code())
}
/// Executes a group of command lists, and only uses redirections that operate on output
/// For instance:
/// `if cat; then echo foo; fi < file.txt > otherfile.txt`
/// `echo foo` will be executed as a body, meaning the output to otherfile.txt will be the only
/// redirection used.
pub fn exec_as_body(&mut self, nodes: Vec<Node>) -> ShResult<i32> {
let saved = self.ctx().clone();
self.ctx = self.ctx().as_body();
@@ -96,7 +112,7 @@ impl ShEnv {
}
pub fn get_input(&self) -> String {
let input = self.input_man.get_input().map(|s| s.to_string()).unwrap_or_default();
log!(DEBUG, input);
log!(TRACE, input);
input
}
pub fn inputman(&self) -> &shellenv::input::InputMan {

View File

@@ -155,6 +155,9 @@ impl VarTab {
pub fn set_var(&mut self, var: &str, val: &str) {
self.vars.insert(var.to_string(), val.to_string());
}
pub fn unset_var(&mut self, var: &str) {
self.vars.remove(var);
}
pub fn export(&mut self, var: &str, val: &str) {
self.env.insert(var.to_string(),val.to_string());
std::env::set_var(var, val);