ls and pwd

main
Jordan Orelli 9 months ago
parent d25382ee10
commit e71c3f89f7

@ -1,12 +1,16 @@
/// changes directory /// changes directory
mod cd; mod cd;
mod ls;
/// prints stuff /// prints stuff
mod echo; mod echo;
/// prints environment variables /// prints environment variables
mod printenv; mod printenv;
mod pwd;
/// removes files /// removes files
mod rm; mod rm;
@ -27,7 +31,9 @@ use std::collections::HashMap;
pub enum Builtin { pub enum Builtin {
Changedir, Changedir,
Echo, Echo,
Ls,
Printenv, Printenv,
Pwd,
Rm, Rm,
Tail, Tail,
Which, Which,
@ -39,7 +45,9 @@ impl Builtin {
match self { match self {
Changedir => &cd::Changedir, Changedir => &cd::Changedir,
Echo => &echo::Echo, Echo => &echo::Echo,
Ls => &ls::Ls,
Printenv => &printenv::Printenv, Printenv => &printenv::Printenv,
Pwd => &pwd::Pwd,
Rm => &rm::Rm, Rm => &rm::Rm,
Tail => &tail::Tail, Tail => &tail::Tail,
Which => &which::Which, Which => &which::Which,
@ -59,7 +67,9 @@ pub fn all() -> HashMap<&'static str, Builtin> {
HashMap::from([ HashMap::from([
("cd", Changedir), ("cd", Changedir),
("echo", Echo), ("echo", Echo),
("ls", Ls),
("printenv", Printenv), ("printenv", Printenv),
("pwd", Pwd),
("rm", Rm), ("rm", Rm),
("tail", Tail), ("tail", Tail),
("which", Which), ("which", Which),

@ -0,0 +1,19 @@
use crate::{
error::ExecError,
run::{Call, Context, Value},
};
use std::{env, fs, io::Write};
pub struct Ls;
impl Call for Ls {
fn call(&self, ctx: &mut Context, args: &[Value]) -> Result<Value, ExecError> {
let cwd = env::current_dir()?;
let dir = fs::read_dir(&cwd)?;
for child in dir {
let child = child?;
_ = write!(ctx.stdout, "{}\n", child.path().display());
}
Ok(Value::None)
}
}

@ -0,0 +1,15 @@
use crate::{
error::ExecError,
run::{Call, Context, Value},
};
use std::{env, io::Write};
pub struct Pwd;
impl Call for Pwd {
fn call(&self, ctx: &mut Context, args: &[Value]) -> Result<Value, ExecError> {
let cwd = env::current_dir()?;
_ = write!(ctx.stdout, "{}\n", cwd.display());
Ok(Value::None)
}
}

@ -112,6 +112,9 @@ pub enum ExecError {
source: io::Error, source: io::Error,
}, },
#[error("i/o error")]
IOError(#[from] std::io::Error),
#[error("value type error: {0}")] #[error("value type error: {0}")]
ValueTypeError(String), ValueTypeError(String),

@ -72,6 +72,8 @@ pub enum Token {
Glob(Lexeme), Glob(Lexeme),
Semi(Glyph), Semi(Glyph),
Pipe(Glyph),
} }
impl Token { impl Token {
@ -100,7 +102,7 @@ impl Token {
match self { match self {
Word(lexeme) | Glob(lexeme) => lexeme.text(), Word(lexeme) | Glob(lexeme) => lexeme.text(),
Semi(glyph) => String::from(glyph.glyph), Pipe(glyph) | Semi(glyph) => String::from(glyph.glyph),
} }
} }
} }
@ -127,6 +129,7 @@ impl<'text> Tokenizer<'text> {
match next.glyph { match next.glyph {
_ if next.is_word() => Some(self.lex_bare_string(vec![next])), _ if next.is_word() => Some(self.lex_bare_string(vec![next])),
_ if next.is_glob() => Some(self.lex_glob(vec![next])), _ if next.is_glob() => Some(self.lex_glob(vec![next])),
'|' => Some(Ok(Token::Pipe(next))),
'@' => Some(self.lex_var(vec![next])), '@' => Some(self.lex_var(vec![next])),
'\'' => Some(self.lex_raw_string(vec![next])), '\'' => Some(self.lex_raw_string(vec![next])),
'"' => Some(self.lex_string_literal(vec![])), '"' => Some(self.lex_string_literal(vec![])),
@ -144,7 +147,7 @@ impl<'text> Tokenizer<'text> {
progress.push(self.source.pop()?); progress.push(self.source.pop()?);
return self.lex_glob(progress); return self.lex_glob(progress);
} }
';' => break, ';' | '|' => break,
_ => { _ => {
return Err(LexError::UnexpectedCharacterInBareString( return Err(LexError::UnexpectedCharacterInBareString(
self.source.pop()?, self.source.pop()?,

@ -16,7 +16,7 @@ pub enum Value {
/// The children of a statement symbol make up the components of what will become a statement /// The children of a statement symbol make up the components of what will become a statement
/// in our ast /// in our ast
Statement, Command,
/// Each of the tokens from the lex stage becomes a terminal node on our tree /// Each of the tokens from the lex stage becomes a terminal node on our tree
Terminal(Token), Terminal(Token),
@ -220,7 +220,7 @@ impl<'text> Parser<'text> {
fn step(&mut self) -> Result<bool, ParseError> { fn step(&mut self) -> Result<bool, ParseError> {
match self.output.value() { match self.output.value() {
Value::Start => self.step_start(), Value::Start => self.step_start(),
Value::Statement => self.step_statement(), Value::Command => self.step_statement(),
Value::Terminal(_) => panic!(), Value::Terminal(_) => panic!(),
} }
} }
@ -229,7 +229,7 @@ impl<'text> Parser<'text> {
assert!(matches!(self.output.value(), Value::Start)); assert!(matches!(self.output.value(), Value::Start));
match self.input.peek()? { match self.input.peek()? {
Some(Token::Word(_)) => { Some(Token::Word(_)) => {
self.output.push(Value::Statement)?; self.output.push(Value::Command)?;
let token = self.input.next().unwrap()?; let token = self.input.next().unwrap()?;
self.output.push(Value::Terminal(token))?; self.output.push(Value::Terminal(token))?;
self.output.up()?; self.output.up()?;
@ -240,19 +240,23 @@ impl<'text> Parser<'text> {
Err(ParseError::UnexpectedToken(token)) Err(ParseError::UnexpectedToken(token))
} }
Some(Token::Semi(_)) => { Some(Token::Semi(_)) => {
self.output.push(Value::Statement)?; self.output.push(Value::Command)?;
let token = self.input.next().unwrap()?; let token = self.input.next().unwrap()?;
self.output.push(Value::Terminal(token))?; self.output.push(Value::Terminal(token))?;
self.output.up()?; self.output.up()?;
self.output.up()?; self.output.up()?;
Ok(true) Ok(true)
} }
Some(Token::Pipe(_)) => {
let token = self.input.next().unwrap()?;
Err(ParseError::UnexpectedToken(token))
}
None => Ok(false), None => Ok(false),
} }
} }
fn step_statement(&mut self) -> Result<bool, ParseError> { fn step_statement(&mut self) -> Result<bool, ParseError> {
assert!(matches!(self.output.value(), Value::Statement)); assert!(matches!(self.output.value(), Value::Command));
match self.input.peek()? { match self.input.peek()? {
Some(Token::Word(_) | Token::Glob(_)) => { Some(Token::Word(_) | Token::Glob(_)) => {
let token = self.input.next().unwrap()?; let token = self.input.next().unwrap()?;
@ -260,6 +264,9 @@ impl<'text> Parser<'text> {
self.output.up()?; self.output.up()?;
Ok(true) Ok(true)
} }
Some(Token::Pipe(_)) => {
todo!()
}
Some(Token::Semi(_)) => { Some(Token::Semi(_)) => {
let token = self.input.next().unwrap()?; let token = self.input.next().unwrap()?;
self.output.push(Value::Terminal(token))?; self.output.push(Value::Terminal(token))?;
@ -272,6 +279,29 @@ impl<'text> Parser<'text> {
} }
} }
/*
a b
command
terminal
a
terminal
b
a | b
pipeline
command
terminal
a
terminal
|
command
terminal
b
*/
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
@ -297,7 +327,7 @@ mod test {
let mut tokens = lex(" ls ").unwrap(); let mut tokens = lex(" ls ").unwrap();
let ls = tokens.pop().unwrap(); let ls = tokens.pop().unwrap();
assert!(cursor.push(Value::Statement).is_ok()); assert!(cursor.push(Value::Command).is_ok());
assert!(cursor.push(Value::Terminal(ls.clone())).is_ok()); assert!(cursor.push(Value::Terminal(ls.clone())).is_ok());
assert!(cursor.push(Value::Terminal(ls.clone())).is_err()); assert!(cursor.push(Value::Terminal(ls.clone())).is_err());
assert!(cursor.target.value == Value::Terminal(ls)); assert!(cursor.target.value == Value::Terminal(ls));

@ -136,7 +136,7 @@ impl TreeBuilder {
} }
Element::Block(root) Element::Block(root)
} }
parse::Value::Statement => { parse::Value::Command => {
let mut children = source.iter_children(); let mut children = source.iter_children();
let mut first = match children.next() { let mut first = match children.next() {
Some(child) => child, Some(child) => child,
@ -175,6 +175,9 @@ impl TreeBuilder {
parse::Value::Terminal(Token::Glob(_)) => { parse::Value::Terminal(Token::Glob(_)) => {
todo!() todo!()
} }
parse::Value::Terminal(Token::Pipe(_)) => {
todo!()
}
parse::Value::Terminal(Token::Semi(_)) => { parse::Value::Terminal(Token::Semi(_)) => {
return Err(ParseError::WhyParseSemicolon); return Err(ParseError::WhyParseSemicolon);
} }

Loading…
Cancel
Save