|
|
|
@ -1,10 +1,4 @@
|
|
|
|
|
use log::debug;
|
|
|
|
|
use std::{
|
|
|
|
|
fmt,
|
|
|
|
|
ops::Deref,
|
|
|
|
|
cell::RefCell,
|
|
|
|
|
rc::Rc,
|
|
|
|
|
};
|
|
|
|
|
use std::{cell::RefCell, fmt, rc::Rc};
|
|
|
|
|
use thiserror::Error;
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Error)]
|
|
|
|
@ -17,6 +11,7 @@ pub enum Error {
|
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
|
pub enum Token {
|
|
|
|
|
Ident(String),
|
|
|
|
|
Glob(String),
|
|
|
|
|
Pipe,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -28,6 +23,7 @@ fn lex<S: AsRef<str>>(text: S) -> Result<Vec<Token>, Error> {
|
|
|
|
|
struct Lexer<'text> {
|
|
|
|
|
chars: std::str::Chars<'text>,
|
|
|
|
|
peeked: Option<char>,
|
|
|
|
|
kept: Vec<char>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'text> Lexer<'text> {
|
|
|
|
@ -35,6 +31,7 @@ impl<'text> Lexer<'text> {
|
|
|
|
|
Self {
|
|
|
|
|
chars: text.chars(),
|
|
|
|
|
peeked: None,
|
|
|
|
|
kept: Vec::new(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -48,6 +45,9 @@ impl<'text> Lexer<'text> {
|
|
|
|
|
tokens.push(Token::Pipe);
|
|
|
|
|
self.skip();
|
|
|
|
|
}
|
|
|
|
|
Some('*') => {
|
|
|
|
|
tokens.push(self.glob());
|
|
|
|
|
}
|
|
|
|
|
Some(_) => {
|
|
|
|
|
tokens.push(self.ident());
|
|
|
|
|
}
|
|
|
|
@ -92,50 +92,66 @@ impl<'text> Lexer<'text> {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn keep(&mut self) {
|
|
|
|
|
match self.peeked {
|
|
|
|
|
Some(c) => {
|
|
|
|
|
self.kept.push(c);
|
|
|
|
|
self.peeked = None;
|
|
|
|
|
}
|
|
|
|
|
None => match self.chars.next() {
|
|
|
|
|
Some(c) => self.kept.push(c),
|
|
|
|
|
None => todo!(),
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn ident(&mut self) -> Token {
|
|
|
|
|
let mut kept: Vec<char> = vec![];
|
|
|
|
|
loop {
|
|
|
|
|
match self.peek() {
|
|
|
|
|
None => break,
|
|
|
|
|
Some('*') => {
|
|
|
|
|
self.keep();
|
|
|
|
|
self.glob();
|
|
|
|
|
},
|
|
|
|
|
Some(c) => {
|
|
|
|
|
if c.is_whitespace() {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
kept.push(c);
|
|
|
|
|
self.skip();
|
|
|
|
|
self.keep();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Token::Ident(self.pop())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn glob(&mut self) -> Token {
|
|
|
|
|
loop {
|
|
|
|
|
match self.peek() {
|
|
|
|
|
None => break,
|
|
|
|
|
Some(c) => {
|
|
|
|
|
if c.is_whitespace() {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
self.keep();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Token::Ident(kept.iter().collect())
|
|
|
|
|
}
|
|
|
|
|
Token::Glob(self.pop())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// struct Parser {
|
|
|
|
|
// 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())
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
fn pop(&mut self) -> String {
|
|
|
|
|
let s: String = self.kept.iter().collect();
|
|
|
|
|
self.kept.clear();
|
|
|
|
|
s
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(PartialEq, Clone)]
|
|
|
|
|
pub enum Element {
|
|
|
|
|
Empty,
|
|
|
|
|
Command(String),
|
|
|
|
|
Literal(String),
|
|
|
|
|
Glob(String),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl fmt::Debug for Element {
|
|
|
|
@ -144,6 +160,7 @@ impl fmt::Debug for Element {
|
|
|
|
|
Element::Empty => write!(f, "()"),
|
|
|
|
|
Element::Command(cmd) => write!(f, "cmd<{}>", cmd),
|
|
|
|
|
Element::Literal(lit) => write!(f, "lit<{}>", lit),
|
|
|
|
|
Element::Glob(glob) => write!(f, "glob<{}>", glob),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -211,7 +228,9 @@ impl Tree {
|
|
|
|
|
self
|
|
|
|
|
} else {
|
|
|
|
|
let child = Node::child_of(Rc::clone(&self.target), elem);
|
|
|
|
|
Tree{target: Rc::new(RefCell::new(child))}
|
|
|
|
|
Tree {
|
|
|
|
|
target: Rc::new(RefCell::new(child)),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -306,31 +325,6 @@ impl From<Node> for Tree {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// I don't know how to write a parser lol
|
|
|
|
|
|
|
|
|
|
// ls
|
|
|
|
|
// Command{name: "ls"}
|
|
|
|
|
|
|
|
|
|
// echo one two three
|
|
|
|
|
// Command{name: "echo", args: [Lit("one"), Lit("two"), Lit("three")]}
|
|
|
|
|
|
|
|
|
|
// echo *.rs
|
|
|
|
|
// Command{name: "echo", args: [Glob("*.rs")]}
|
|
|
|
|
// Command{name: "echo", args: [Path("main.rs"), Path("parse.rs"), ...]}
|
|
|
|
|
|
|
|
|
|
// cat main.rs | wc -l
|
|
|
|
|
// Pipe{
|
|
|
|
|
// src: Command{name: "cat", args: [Lit("main.rs")]}
|
|
|
|
|
// dest: Command{name: "wc", args: [Lit("-l")]}
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// echo one ; echo two
|
|
|
|
|
// Sequence{
|
|
|
|
|
// children: [
|
|
|
|
|
// Command{Name:
|
|
|
|
|
// ]
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
pub fn parse<S: AsRef<str>>(text: S) -> Result<Tree, Error> {
|
|
|
|
|
let mut tree = Tree::new();
|
|
|
|
|
for token in lex(text)? {
|
|
|
|
@ -435,8 +429,7 @@ mod tests {
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn tree_push() {
|
|
|
|
|
let tree = Tree::new()
|
|
|
|
|
.push(Element::Command(String::from("ls")));
|
|
|
|
|
let tree = Tree::new().push(Element::Command(String::from("ls")));
|
|
|
|
|
assert_eq!(tree.peek(), Element::Command(String::from("ls")));
|
|
|
|
|
|
|
|
|
|
let tree = Tree::new()
|
|
|
|
@ -455,9 +448,18 @@ mod tests {
|
|
|
|
|
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_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());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|