From 7abb60a3bc517e090bb3b6abf3c2075d8cc12e0a Mon Sep 17 00:00:00 2001 From: Jordan Orelli Date: Sun, 9 Apr 2023 13:37:38 -0500 Subject: [PATCH] this doesn't work but I wanna switch computers --- src/main.rs | 4 +- src/parse.rs | 271 +++++++++++++++++++++++++++++++++++++++++++++------ src/shell.rs | 22 +++-- 3 files changed, 256 insertions(+), 41 deletions(-) diff --git a/src/main.rs b/src/main.rs index db6a973..65a9611 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,7 +19,7 @@ use anyhow::Result; fn main() -> Result<()> { 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) { Ok(f) => { let target = Box::leak(Box::new(f)); @@ -63,7 +63,7 @@ fn main() -> Result<()> { info!("◇ {}", s); let tree = parse::parse(&s)?; debug!(" {:?}", tree); - shell.exec(tree)?; + shell.exec(tree.into())?; // 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. shell.reset()?; diff --git a/src/parse.rs b/src/parse.rs index 8589c31..c2e3dd1 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -1,4 +1,8 @@ use log::debug; +use std::{ + cell::RefCell, + rc::Rc, +}; use thiserror::Error; #[derive(Debug, Error)] @@ -104,42 +108,178 @@ impl<'text> Lexer<'text> { } } -struct Parser { - state: Node, +// struct Parser { +// state: Tree, +// } +// +// impl Parser { +// fn new() -> Self { +// Self { +// state: Tree::new(), +// } +// } +// +// fn parse(mut self, tokens: Vec) -> Result { +// Ok(Node::empty()) +// // for token in tokens { +// // self.take(token); +// // } +// // let t = self.state.replace(Node::empty()); +// // Ok(t.root()) +// } +// } + +#[derive(Debug, PartialEq, Clone)] +pub enum Element { + Empty, + Command(String), + Literal(String), } -impl Parser { - fn new() -> Self { +#[derive(Debug)] +pub struct Node { + pub elem: Element, + pub parent: Option>>, + pub children: Vec>>, +} + +impl Node { + pub fn new(elem: Element) -> Self { Self { - state: Node::Empty, + elem, + parent: None, + children: Vec::new(), } } - fn parse(mut self, tokens: Vec) -> Result { - for token in tokens { - match (self.state, token) { - (Node::Empty, Token::Ident(name)) => { - self.state = Node::Command{name, args: vec!()}; - }, - (Node::Command{name, mut args}, Token::Ident(s)) => { - args.push(s); - self.state = Node::Command{name, args}; - }, - _ => return Err(Error::UnexpectedToken), - } + pub fn empty() -> Self { + Self::new(Element::Empty) + } + + pub fn child_of(parent: Rc>, elem: Element) -> Self { + Self { + elem, + parent: Some(parent), + children: Vec::new(), } - Ok(self.state) } + pub fn visit(self) -> Tree { + self.into() + } } #[derive(Debug)] -pub enum Node { - Empty, - Command { - name: String, - args: Vec, - }, +pub struct Tree { + target: Rc>, +} + +impl Tree { + fn new() -> Self { + Node::empty().into() + } + + /// 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.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 { + target: Rc::clone(&self.target), + idx: 0, + last: None, + } + } +} + +pub struct ChildIter<'n> { + /// pointer to the node in the tree whose children we are looking at. + target: Rc>, + idx: usize, + last: Option<&'n Node>, +} + +impl <'n> Iterator for ChildIter<'n> { + type Item = &'n Node; + + fn next(&mut self) -> Option { + if self.idx >= self.target.borrow().children.len() { + None + } else { + let child = Rc::clone(&self.target.borrow().children[self.idx]); + self.idx += 1; + self.last = Some(&child.as_ref().borrow()); + None + + //Some(&child.as_ref().borrow()) + //Some(&*child.borrow()) + } + } +} + +impl From for Node { + fn from(value: Tree) -> Self { + value.target.replace(Node::empty()) + } +} + +impl From for Tree { + fn from(value: Node) -> Self { + Self { + target: Rc::new(RefCell::new(value)), + } + } } // I don't know how to write a parser lol @@ -167,11 +307,20 @@ pub enum Node { // ] // } -pub fn parse>(text: S) -> Result { - let tokens = lex(text)?; - let parser = Parser::new(); - debug!(" {:?}", tokens); - parser.parse(tokens) +pub fn parse>(text: S) -> Result { + let mut tree = Tree::new(); + for token in lex(text)? { + match (tree.peek(), token) { + (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)] @@ -241,4 +390,68 @@ mod tests { "one |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 test_parse() { + let res = parse("ls one two"); + assert!(res.is_ok()); + + let tree = res.unwrap(); + assert_eq!(tree.peek(), Element::Command(String::from("ls"))); + assert_eq!(tree.children().count(), 2); + + let args = tree.children(); + // assert_eq!(args.next().unwrap(), Element::Literal(String::from("one"))); + } + + /* + #[test] + fn tree_command() { + /* + Command(ls) + Literal(.) + */ + let root = Tree::new() + .push(Element::Command(String::from("ls"))) + .push(Element::Literal(String::from("."))) + .root(); + + assert!(root.is_root()); + assert_eq!(root.children().count(), 1); + // assert_eq!(root.elem, Element::Command(String::from("ls"))); + // assert_eq!(root.children.len(), 1); + // assert_eq!(root.children[0].borrow(), Element::Literal(String::from("."))); + } + */ } diff --git a/src/shell.rs b/src/shell.rs index 190e521..554607b 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -9,6 +9,7 @@ use crate::{ }; use std::path::{Path, PathBuf}; +use std::rc::Rc; use anyhow::Result; use dirs; @@ -97,16 +98,17 @@ impl Shell { } } - pub fn exec(&mut self, mut node: Node) -> Result { - loop { - match node { - Node::Empty => break, - Node::Command{name, args} => { - self.eval(name, args.iter().map(|s| s.as_str()).collect())?; - node = Node::Empty; - }, - } - } + pub fn exec(&mut self, root: Node) -> Result { + // match &tree.elem { + // Node::Command(name) => { + // let args: Vec<&str> = tree.children.iter().map(|t| match &t.elem { + // Node::Literal(arg) => arg.as_str(), + // _ => todo!(), + // }).collect(); + // self.eval(name.to_string(), args)?; + // }, + // _ => todo!(), + // } Ok(true) }