builtin echo returns

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

@ -1,3 +1,33 @@
pub trait BuiltinFn {
fn call(&self, args: Vec<&str>);
use crate::{
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")]
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),
#[error("unexpected eof")]

@ -5,7 +5,7 @@ pub struct Line {
/// the current contents of the line
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,
}

@ -150,10 +150,16 @@ impl Writer {
impl Write for Writer {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let mut written = 0;
unsafe {
Error::check(Console::WriteConsoleA(self.output, buf, None, None))?;
}
Ok(0)
Error::check(Console::WriteConsoleA(
self.output,
buf,
Some(&mut written),
None,
))?;
}
Ok(written as usize)
}
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<()> {
if depth > 0 {
println!(" {e}");
writeln!(self.output, " {e}")?;
} else {
println!("{e}:");
writeln!(self.output, "{e}:")?;
}
if let Some(cause) = e.source() {
self.render_error_helper(cause, depth + 1)?;

@ -1,5 +1,5 @@
use crate::{
builtins::BuiltinFn,
builtins::Builtin,
error::{ExecError, ParseError},
lex::{Lexer, Token},
log::debug,
@ -11,14 +11,12 @@ use std::{
};
pub struct State {
builtins: HashMap<&'static str, Box<dyn BuiltinFn>>,
variables: HashMap<&'static str, syntax::Value>,
}
impl State {
pub fn new() -> Self {
Self {
builtins: HashMap::new(),
variables: HashMap::new(),
}
}
@ -54,7 +52,7 @@ pub enum 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())
}
}
@ -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)]
@ -100,9 +108,12 @@ pub struct Command {
args: Vec<Element>,
}
impl Eval for Command {
fn eval(&self, ctx: &mut State) -> Result<Value, ExecError> {
let name = self.name.eval(ctx)?.try_to_string()?;
impl Command {
fn eval_args(&self, ctx: &mut State) -> Result<Vec<Value>, ExecError> {
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);
if self.args.len() > 0 {
@ -114,16 +125,32 @@ impl Eval for Command {
proc.args(args);
}
let mut child = proc.spawn().map_err(|e| ExecError::ProcessSpawnError {
name: name.clone(),
name: name.to_string(),
source: e,
})?;
let pid = child.id();
let status = child.wait().map_err(|e| ExecError::ProcessWaitError {
name,
name: name.to_string(),
pid,
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(())
}
}
/*
> ls
command
name: ls
*/

Loading…
Cancel
Save