Early implementation of scripting elements

This commit is contained in:
2025-03-05 01:36:58 -05:00
parent 5dd9ee96ad
commit 1b3e2c0887
28 changed files with 1384 additions and 371 deletions

View File

@@ -6,12 +6,16 @@ pub fn alias(node: Node, shenv: &mut ShEnv) -> ShResult<()> {
let argv = argv.drop_first();
let mut argv_iter = argv.into_iter();
while let Some(arg) = argv_iter.next() {
let arg_raw = arg.to_string();
let arg_raw = shenv.input_slice(arg.span()).to_string();
if let Some((alias,body)) = arg_raw.split_once('=') {
log!(DEBUG, "{:?}",arg.span());
log!(DEBUG, arg_raw);
log!(DEBUG, body);
let clean_body = trim_quotes(&body);
log!(DEBUG, clean_body);
shenv.logic_mut().set_alias(alias, &clean_body);
} else {
return Err(ShErr::full(ShErrKind::SyntaxErr, "Expected an assignment in alias args", arg.span().clone()))
return Err(ShErr::full(ShErrKind::SyntaxErr, "Expected an assignment in alias args", shenv.get_input(), arg.span().clone()))
}
}
} else { unreachable!() }

View File

@@ -5,7 +5,7 @@ pub fn cd(node: Node, shenv: &mut ShEnv) -> ShResult<()> {
if let NdRule::Command { argv, redirs: _ } = rule {
let mut argv_iter = argv.into_iter();
argv_iter.next(); // Ignore 'cd'
let dir_raw = argv_iter.next().map(|arg| arg.to_string()).unwrap_or(std::env::var("HOME")?);
let dir_raw = argv_iter.next().map(|arg| shenv.input_slice(arg.span()).into()).unwrap_or(std::env::var("HOME")?);
let dir = PathBuf::from(&dir_raw);
std::env::set_current_dir(dir)?;
shenv.vars_mut().export("PWD",&dir_raw);

View File

@@ -0,0 +1,20 @@
use crate::prelude::*;
pub fn sh_flow(node: Node, shenv: &mut ShEnv, kind: ShErrKind) -> ShResult<()> {
let rule = node.into_rule();
let mut code: i32 = 0;
if let NdRule::Command { argv, redirs } = rule {
let mut argv_iter = argv.into_iter();
while let Some(arg) = argv_iter.next() {
if let Ok(code_arg) = shenv.input_slice(arg.span()).parse() {
code = code_arg
}
}
} else { unreachable!() }
shenv.set_code(code);
// Our control flow keywords are used as ShErrKinds
// This design will halt the execution flow and start heading straight back upward
// Function returns and loop breaks/continues will be caught in the proper context to allow
// Execution to continue at the proper return point.
Err(ShErr::simple(kind, ""))
}

View File

@@ -6,7 +6,7 @@ pub fn export(node: Node, shenv: &mut ShEnv) -> ShResult<()> {
let mut argv_iter = argv.into_iter();
argv_iter.next(); // Ignore 'export'
while let Some(arg) = argv_iter.next() {
let arg_raw = arg.to_string();
let arg_raw = shenv.input_slice(arg.span()).to_string();
if let Some((var,val)) = arg_raw.split_once('=') {
shenv.vars_mut().export(var, val);
} else {

View File

@@ -14,6 +14,7 @@ pub fn continue_job(node: Node, shenv: &mut ShEnv, fg: bool) -> ShResult<()> {
ShErr::full(
ShErrKind::InternalErr,
format!("Somehow called {} with an existing foreground job",cmd),
shenv.get_input(),
blame
)
)
@@ -22,11 +23,11 @@ pub fn continue_job(node: Node, shenv: &mut ShEnv, fg: bool) -> ShResult<()> {
let curr_job_id = if let Some(id) = read_jobs(|j| j.curr_job()) {
id
} else {
return Err(ShErr::full(ShErrKind::ExecFail, "No jobs found", blame))
return Err(ShErr::full(ShErrKind::ExecFail, "No jobs found", shenv.get_input(), blame))
};
let tabid = match argv_s.next() {
Some(arg) => parse_job_id(&arg, blame.clone())?,
Some(arg) => parse_job_id(&arg, blame.clone(),shenv)?,
None => curr_job_id
};
@@ -36,7 +37,14 @@ pub fn continue_job(node: Node, shenv: &mut ShEnv, fg: bool) -> ShResult<()> {
if query_result.is_some() {
Ok(j.remove_job(id.clone()).unwrap())
} else {
Err(ShErr::full(ShErrKind::ExecFail, format!("Job id `{}' not found", tabid), blame))
Err(
ShErr::full(
ShErrKind::ExecFail,
format!("Job id `{}' not found", tabid),
shenv.get_input(),
blame
)
)
}
})?;
@@ -54,7 +62,7 @@ pub fn continue_job(node: Node, shenv: &mut ShEnv, fg: bool) -> ShResult<()> {
Ok(())
}
fn parse_job_id(arg: &str, blame: Span) -> ShResult<usize> {
fn parse_job_id(arg: &str, blame: Rc<RefCell<Span>>, shenv: &mut ShEnv) -> ShResult<usize> {
if arg.starts_with('%') {
let arg = arg.strip_prefix('%').unwrap();
if arg.chars().all(|ch| ch.is_ascii_digit()) {
@@ -66,7 +74,14 @@ fn parse_job_id(arg: &str, blame: Span) -> ShResult<usize> {
});
match result {
Some(id) => Ok(id),
None => Err(ShErr::full(ShErrKind::InternalErr,"Found a job but no table id in parse_job_id()",blame))
None => Err(
ShErr::full(
ShErrKind::InternalErr,
"Found a job but no table id in parse_job_id()",
shenv.get_input(),
blame
)
)
}
}
} else if arg.chars().all(|ch| ch.is_ascii_digit()) {
@@ -86,10 +101,24 @@ fn parse_job_id(arg: &str, blame: Span) -> ShResult<usize> {
match result {
Some(id) => Ok(id),
None => Err(ShErr::full(ShErrKind::InternalErr,"Found a job but no table id in parse_job_id()",blame))
None => Err(
ShErr::full(
ShErrKind::InternalErr,
"Found a job but no table id in parse_job_id()",
shenv.get_input(),
blame
)
)
}
} else {
Err(ShErr::full(ShErrKind::SyntaxErr,format!("Invalid fd arg: {}", arg),blame))
Err(
ShErr::full(
ShErrKind::SyntaxErr,
format!("Invalid fd arg: {}", arg),
shenv.get_input(),
blame
)
)
}
}
@@ -100,10 +129,17 @@ pub fn jobs(node: Node, shenv: &mut ShEnv) -> ShResult<()> {
let mut flags = JobCmdFlags::empty();
while let Some(arg) = argv.next() {
let arg_s = arg.to_string();
let arg_s = shenv.input_slice(arg.span());
let mut chars = arg_s.chars().peekable();
if chars.peek().is_none_or(|ch| *ch != '-') {
return Err(ShErr::full(ShErrKind::SyntaxErr, "Invalid flag in jobs call", arg.span().clone()))
return Err(
ShErr::full(
ShErrKind::SyntaxErr,
"Invalid flag in jobs call",
shenv.get_input(),
arg.span()
)
)
}
chars.next();
while let Some(ch) = chars.next() {
@@ -113,7 +149,14 @@ pub fn jobs(node: Node, shenv: &mut ShEnv) -> ShResult<()> {
'n' => JobCmdFlags::NEW_ONLY,
'r' => JobCmdFlags::RUNNING,
's' => JobCmdFlags::STOPPED,
_ => return Err(ShErr::full(ShErrKind::SyntaxErr, "Invalid flag in jobs call", arg.span().clone()))
_ => return Err(
ShErr::full(
ShErrKind::SyntaxErr,
"Invalid flag in jobs call",
shenv.get_input(),
arg.span()
)
)
};
flags |= flag

View File

@@ -5,8 +5,9 @@ pub mod export;
pub mod jobctl;
pub mod read;
pub mod alias;
pub mod control_flow;
pub const BUILTINS: [&str;9] = [
pub const BUILTINS: [&str;13] = [
"echo",
"cd",
"pwd",
@@ -15,5 +16,9 @@ pub const BUILTINS: [&str;9] = [
"bg",
"jobs",
"read",
"alias"
"alias",
"exit",
"continue",
"return",
"break",
];

View File

@@ -27,7 +27,8 @@ pub fn read_builtin(node: Node, shenv: &mut ShEnv) -> ShResult<()> {
shenv.vars_mut().set_var(&first_var.to_string(), &read_input);
}
*/
shenv.vars_mut().set_var(&var.to_string(), &read_input);
let var_name = shenv.input_slice(var.span()).to_string();
shenv.vars_mut().set_var(&var_name, &read_input);
}
} else {
unreachable!()