Compare commits

...

2 Commits

@ -19,7 +19,7 @@ use anyhow::Result;
fn main() -> Result<()> { fn main() -> Result<()> {
let mut shell = Shell::new()?; let mut shell = Shell::new()?;
let log_path = shell.expand_path("~/wash.log"); let log_path = shell.expand_path("~/clyde.log");
match Log::file(log_path) { match Log::file(log_path) {
Ok(f) => { Ok(f) => {
let target = Box::leak(Box::new(f)); let target = Box::leak(Box::new(f));
@ -63,7 +63,7 @@ fn main() -> Result<()> {
info!("◇ {}", s); info!("◇ {}", s);
let tree = parse::parse(&s)?; let tree = parse::parse(&s)?;
debug!(" {:?}", tree); debug!(" {:?}", tree);
shell.exec(tree)?; shell.exec(tree.into())?;
// Some commands don't leave the terminal in a clean state, so we use reset // Some commands don't leave the terminal in a clean state, so we use reset
// to ensure that our input and output modes are what we expect them to be. // to ensure that our input and output modes are what we expect them to be.
shell.reset()?; shell.reset()?;

@ -1,4 +1,10 @@
use log::debug; use log::debug;
use std::{
fmt,
ops::Deref,
cell::RefCell,
rc::Rc,
};
use thiserror::Error; use thiserror::Error;
#[derive(Debug, Error)] #[derive(Debug, Error)]
@ -104,42 +110,200 @@ impl<'text> Lexer<'text> {
} }
} }
struct Parser { // struct Parser {
state: Node, // state: Tree,
// }
//
// impl Parser {
// fn new() -> Self {
// Self {
// state: Tree::new(),
// }
// }
//
// fn parse(mut self, tokens: Vec<Token>) -> Result<Node, Error> {
// Ok(Node::empty())
// // for token in tokens {
// // self.take(token);
// // }
// // let t = self.state.replace(Node::empty());
// // Ok(t.root())
// }
// }
#[derive(PartialEq, Clone)]
pub enum Element {
Empty,
Command(String),
Literal(String),
} }
impl Parser { impl fmt::Debug for Element {
fn new() -> Self { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
Element::Empty => write!(f, "()"),
Element::Command(cmd) => write!(f, "cmd<{}>", cmd),
Element::Literal(lit) => write!(f, "lit<{}>", lit),
}
}
}
pub struct Node {
pub elem: Element,
pub parent: Option<Rc<RefCell<Node>>>,
pub children: Vec<Rc<RefCell<Node>>>,
}
impl Node {
pub fn new(elem: Element) -> Self {
Self {
elem,
parent: None,
children: Vec::new(),
}
}
pub fn empty() -> Self {
Self::new(Element::Empty)
}
pub fn child_of(parent: Rc<RefCell<Self>>, elem: Element) -> Self {
Self { Self {
state: Node::Empty, elem,
parent: Some(parent),
children: Vec::new(),
} }
} }
fn parse(mut self, tokens: Vec<Token>) -> Result<Node, Error> { pub fn visit(self) -> Tree {
for token in tokens { self.into()
match (self.state, token) { }
(Node::Empty, Token::Ident(name)) => { }
self.state = Node::Command{name, args: vec!()};
}, impl fmt::Debug for Node {
(Node::Command{name, mut args}, Token::Ident(s)) => { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
args.push(s); write!(f, "{:?}", self.elem)?;
self.state = Node::Command{name, args}; if self.children.len() > 0 {
}, write!(f, "[")?;
_ => return Err(Error::UnexpectedToken), for child in self.children.iter() {
write!(f, "{:?}", child.borrow())?;
} }
write!(f, "]")?;
} }
Ok(self.state) Ok(())
} }
}
pub struct Tree {
target: Rc<RefCell<Node>>,
} }
#[derive(Debug)] impl Tree {
pub enum Node { fn new() -> Self {
Empty, Node::empty().into()
Command { }
name: String,
args: Vec<String>, /// Adds an element as a node as a child of the current node, then descends the tree to select
}, /// that child node. This is similar to how pushing a value changes the top element of a stack.
fn push(self, elem: Element) -> Self {
if self.is_empty() {
self.target.replace(Node::new(elem));
self
} else {
let child = Node::child_of(Rc::clone(&self.target), elem);
Tree{target: Rc::new(RefCell::new(child))}
}
}
/// Adds a child node with a given element value to the currently selected node without chaning
/// our selection.
fn append(self, elem: Element) -> Self {
if self.is_empty() {
self.target.replace(Node::new(elem));
} else {
let node = Node::child_of(Rc::clone(&self.target), elem);
let child = Rc::new(RefCell::new(node));
self.target.borrow_mut().children.push(child);
}
self
}
/// Tells us whether or not the currently selected node is an empty node
fn is_empty(&self) -> bool {
self.target.borrow().elem == Element::Empty
}
fn parent(&self) -> Option<Self> {
self.target.borrow().parent.as_ref().map(|parent| Self {
target: Rc::clone(parent),
})
}
fn is_root(&self) -> bool {
self.parent().is_none()
}
pub fn root(self) -> Self {
match self.parent() {
Some(parent) => parent.root(),
None => self,
}
}
fn peek(&self) -> Element {
self.target.borrow().elem.clone()
}
fn into_node(self) -> Node {
self.into()
}
fn children(&self) -> ChildIter {
ChildIter {
parent: Rc::clone(&self.target),
idx: 0,
}
}
}
impl fmt::Debug for Tree {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
write!(f, "{:?}", self.target.borrow())
}
}
pub struct ChildIter {
/// pointer to the node in the tree whose children we are looking at.
parent: Rc<RefCell<Node>>,
idx: usize,
}
impl Iterator for ChildIter {
type Item = Tree;
fn next(&mut self) -> Option<Self::Item> {
if self.idx >= self.parent.borrow().children.len() {
None
} else {
let child = Rc::clone(&self.parent.borrow().children[self.idx]);
self.idx += 1;
Some(Tree{target: child})
}
}
}
impl From<Tree> for Node {
fn from(value: Tree) -> Self {
value.target.replace(Node::empty())
}
}
impl From<Node> for Tree {
fn from(value: Node) -> Self {
Self {
target: Rc::new(RefCell::new(value)),
}
}
} }
// I don't know how to write a parser lol // I don't know how to write a parser lol
@ -167,11 +331,20 @@ pub enum Node {
// ] // ]
// } // }
pub fn parse<S: AsRef<str>>(text: S) -> Result<Node, Error> { pub fn parse<S: AsRef<str>>(text: S) -> Result<Tree, Error> {
let tokens = lex(text)?; let mut tree = Tree::new();
let parser = Parser::new(); for token in lex(text)? {
debug!(" {:?}", tokens); match (tree.peek(), token) {
parser.parse(tokens) (Element::Empty, Token::Ident(cmd)) => {
tree = tree.push(Element::Command(cmd));
}
(Element::Command(_), Token::Ident(arg)) => {
tree = tree.append(Element::Literal(arg));
}
_ => todo!(),
}
}
Ok(tree.root())
} }
#[cfg(test)] #[cfg(test)]
@ -210,8 +383,8 @@ mod tests {
ident("one"); ident("one");
two_tokens: two_tokens:
"one two" "ls one two"
ident("one") ident("two"); ident("ls") ident("one") ident("two");
leading_whitespace: leading_whitespace:
" one" " one"
@ -241,4 +414,50 @@ mod tests {
"one |two" "one |two"
ident("one") Pipe ident("two"); ident("one") Pipe ident("two");
} }
#[test]
fn empty_tree() {
let root = Tree::new().root();
assert!(root.is_root());
assert_eq!(root.peek(), Element::Empty);
assert_eq!(root.children().count(), 0);
}
#[test]
fn tree_root() {
let root = Tree::new()
.push(Element::Command(String::from("ls")))
.root();
assert!(root.is_root());
assert_eq!(root.children().count(), 0);
assert_eq!(root.into_node().elem, Element::Command(String::from("ls")));
}
#[test]
fn tree_push() {
let tree = Tree::new()
.push(Element::Command(String::from("ls")));
assert_eq!(tree.peek(), Element::Command(String::from("ls")));
let tree = Tree::new()
.push(Element::Command(String::from("ls")))
.append(Element::Command(String::from("one")));
assert_eq!(tree.peek(), Element::Command(String::from("ls")));
}
#[test]
fn parse_args() {
let res = parse("ls one two three");
assert!(res.is_ok());
let tree = res.unwrap();
assert_eq!(tree.peek(), Element::Command(String::from("ls")));
assert_eq!(tree.children().count(), 3);
let mut args = tree.children();
assert_eq!(args.next().unwrap().peek(), Element::Literal(String::from("one")));
assert_eq!(args.next().unwrap().peek(), Element::Literal(String::from("two")));
assert_eq!(args.next().unwrap().peek(), Element::Literal(String::from("three")));
assert!(args.next().is_none());
}
} }

@ -2,13 +2,14 @@ use crate::{
ext::{Command, Echo, Printenv, Tail, Which}, ext::{Command, Echo, Printenv, Tail, Which},
input, input,
line::Line, line::Line,
parse::Node,
log::*, log::*,
output, output,
// parse::parse, // parse::parse,
parse::{Element, Node},
}; };
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::rc::Rc;
use anyhow::Result; use anyhow::Result;
use dirs; use dirs;
@ -97,17 +98,25 @@ impl Shell {
} }
} }
pub fn exec(&mut self, mut node: Node) -> Result<bool> { pub fn exec(&mut self, root: Node) -> Result<bool> {
loop { match root.elem {
match node { Element::Empty => Ok(true),
Node::Empty => break, Element::Command(cmd) => {
Node::Command{name, args} => { let args: Vec<String> = root
self.eval(name, args.iter().map(|s| s.as_str()).collect())?; .children
node = Node::Empty; .iter()
}, .map(|node| match &node.borrow().elem {
Element::Literal(v) => v.clone(),
_ => todo!(),
})
.collect();
self.eval(
cmd.to_string(),
args.iter().map(|arg| arg.as_str()).collect(),
)
} }
Element::Literal(_) => todo!(),
} }
Ok(true)
} }
pub fn eval(&mut self, cmd: String, args: Vec<&str>) -> Result<bool> { pub fn eval(&mut self, cmd: String, args: Vec<&str>) -> Result<bool> {

Loading…
Cancel
Save