builtin echo returns

main
Jordan Orelli 11 months ago
parent 27ebbf7c97
commit 68909d22a8

@ -1,3 +1,33 @@
pub trait BuiltinFn { use crate::{
fn call(&self, args: Vec<&str>); error::ExecError,
syntax::{self, State},
};
pub enum Builtin {
Echo,
}
impl Builtin {
pub fn lookup(name: &str) -> Option<Self> {
match name {
"echo" => Some(Self::Echo),
_ => None,
}
}
pub fn call(
&self,
_: &mut State,
args: &Vec<syntax::Value>,
) -> Result<syntax::Value, ExecError> {
match self {
Builtin::Echo => {
let args: Result<Vec<String>, ExecError> =
args.into_iter().map(|arg| arg.try_as_string()).collect();
let args = args?;
println!("{}", args.join(" "));
Ok(syntax::Value::None)
}
}
}
} }

@ -20,7 +20,8 @@ pub enum LexError {
#[error("a word character was expected but none was encountered")] #[error("a word character was expected but none was encountered")]
ExpectedWordCharacter, ExpectedWordCharacter,
#[error("unexpected character: {0:?}")] // #[error("unexpected character {0.glyph} at {0.position}")]
#[error("unexpected character {g} at {pos:?}", g = .0.glyph, pos = .0.position)]
UnexpectedCharacter(Glyph), UnexpectedCharacter(Glyph),
#[error("unexpected eof")] #[error("unexpected eof")]

@ -5,7 +5,7 @@ pub struct Line {
/// the current contents of the line /// the current contents of the line
chars: Vec<char>, chars: Vec<char>,
/// the cursor position of our dit head within the vector of characters that we store as chars /// the cursor position of our head within the vector of characters that we store as chars
cursor: usize, cursor: usize,
} }

@ -150,10 +150,16 @@ impl Writer {
impl Write for Writer { impl Write for Writer {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let mut written = 0;
unsafe { unsafe {
Error::check(Console::WriteConsoleA(self.output, buf, None, None))?; Error::check(Console::WriteConsoleA(
} self.output,
Ok(0) buf,
Some(&mut written),
None,
))?;
}
Ok(written as usize)
} }
fn flush(&mut self) -> io::Result<()> { fn flush(&mut self) -> io::Result<()> {

@ -166,9 +166,9 @@ impl Shell {
fn render_error_helper<E: Error>(&mut self, e: E, depth: u8) -> io::Result<()> { fn render_error_helper<E: Error>(&mut self, e: E, depth: u8) -> io::Result<()> {
if depth > 0 { if depth > 0 {
println!(" {e}"); writeln!(self.output, " {e}")?;
} else { } else {
println!("{e}:"); writeln!(self.output, "{e}:")?;
} }
if let Some(cause) = e.source() { if let Some(cause) = e.source() {
self.render_error_helper(cause, depth + 1)?; self.render_error_helper(cause, depth + 1)?;

@ -1,5 +1,5 @@
use crate::{ use crate::{
builtins::BuiltinFn, builtins::Builtin,
error::{ExecError, ParseError}, error::{ExecError, ParseError},
lex::{Lexer, Token}, lex::{Lexer, Token},
log::debug, log::debug,
@ -11,14 +11,12 @@ use std::{
}; };
pub struct State { pub struct State {
builtins: HashMap<&'static str, Box<dyn BuiltinFn>>,
variables: HashMap<&'static str, syntax::Value>, variables: HashMap<&'static str, syntax::Value>,
} }
impl State { impl State {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
builtins: HashMap::new(),
variables: HashMap::new(), variables: HashMap::new(),
} }
} }
@ -54,7 +52,7 @@ pub enum Value {
} }
impl Eval for Value { impl Eval for Value {
fn eval(&self, ctx: &mut State) -> Result<Value, ExecError> { fn eval(&self, _: &mut State) -> Result<Value, ExecError> {
Ok(self.clone()) Ok(self.clone())
} }
} }
@ -69,6 +67,16 @@ impl Value {
)), )),
} }
} }
pub fn try_as_string(&self) -> Result<String, ExecError> {
match self {
Value::None => Err(ExecError::type_error("expected text value, saw None value")),
Value::Text(v) => Ok(v.clone()),
Value::ExitStatus(_) => Err(ExecError::type_error(
"expected text value, saw ExitStatus value",
)),
}
}
} }
#[derive(Debug)] #[derive(Debug)]
@ -100,9 +108,12 @@ pub struct Command {
args: Vec<Element>, args: Vec<Element>,
} }
impl Eval for Command { impl Command {
fn eval(&self, ctx: &mut State) -> Result<Value, ExecError> { fn eval_args(&self, ctx: &mut State) -> Result<Vec<Value>, ExecError> {
let name = self.name.eval(ctx)?.try_to_string()?; self.args.iter().map(|elem| elem.eval(ctx)).collect()
}
fn exec_command(&self, ctx: &mut State, name: &str) -> Result<Value, ExecError> {
let mut proc = process::Command::new(&name); let mut proc = process::Command::new(&name);
if self.args.len() > 0 { if self.args.len() > 0 {
@ -114,16 +125,32 @@ impl Eval for Command {
proc.args(args); proc.args(args);
} }
let mut child = proc.spawn().map_err(|e| ExecError::ProcessSpawnError { let mut child = proc.spawn().map_err(|e| ExecError::ProcessSpawnError {
name: name.clone(), name: name.to_string(),
source: e, source: e,
})?; })?;
let pid = child.id(); let pid = child.id();
let status = child.wait().map_err(|e| ExecError::ProcessWaitError { let status = child.wait().map_err(|e| ExecError::ProcessWaitError {
name, name: name.to_string(),
pid, pid,
source: e, source: e,
})?; })?;
return Ok(Value::ExitStatus(status)); Ok(Value::ExitStatus(status))
}
}
impl Eval for Command {
fn eval(&self, ctx: &mut State) -> Result<Value, ExecError> {
let name = self.name.eval(ctx)?.try_to_string()?;
match Builtin::lookup(&name) {
Some(builtin) => {
let args = self.eval_args(ctx)?;
// let args: Vec<&str> = args.into_iter().map(|arg| arg).collect();
builtin.call(ctx, &args)
}
None => self.exec_command(ctx, &name),
}
} }
} }
@ -199,11 +226,3 @@ mod test {
//Ok(()) //Ok(())
} }
} }
/*
> ls
command
name: ls
*/

Loading…
Cancel
Save