|
|
|
@ -7,6 +7,15 @@ pub enum Error {
|
|
|
|
|
UnexpectedToken,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct Tok {
|
|
|
|
|
start_line: usize,
|
|
|
|
|
start_col: usize,
|
|
|
|
|
end_line: usize,
|
|
|
|
|
end_col: usize,
|
|
|
|
|
text: String,
|
|
|
|
|
kind: Token,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
|
pub enum Token {
|
|
|
|
@ -17,7 +26,7 @@ pub enum Token {
|
|
|
|
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
fn lex<S: AsRef<str>>(text: S) -> Result<Vec<Token>, Error> {
|
|
|
|
|
Lexer::new(text.as_ref()).lex()
|
|
|
|
|
Ok(Lexer::new(text.as_ref()).collect())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct Lexer<'text> {
|
|
|
|
@ -35,27 +44,6 @@ impl<'text> Lexer<'text> {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn lex(&mut self) -> Result<Vec<Token>, Error> {
|
|
|
|
|
let mut tokens = vec![];
|
|
|
|
|
while self.peek().is_some() {
|
|
|
|
|
self.skip_whitespace();
|
|
|
|
|
match self.peek() {
|
|
|
|
|
None => return Ok(tokens),
|
|
|
|
|
Some('|') => {
|
|
|
|
|
tokens.push(Token::Pipe);
|
|
|
|
|
self.skip();
|
|
|
|
|
}
|
|
|
|
|
Some('*') => {
|
|
|
|
|
tokens.push(self.glob());
|
|
|
|
|
}
|
|
|
|
|
Some(_) => {
|
|
|
|
|
tokens.push(self.ident());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(tokens)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn skip_whitespace(&mut self) {
|
|
|
|
|
loop {
|
|
|
|
|
match self.peek() {
|
|
|
|
@ -112,7 +100,7 @@ impl<'text> Lexer<'text> {
|
|
|
|
|
Some('*') => {
|
|
|
|
|
self.keep();
|
|
|
|
|
self.glob();
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
Some(c) => {
|
|
|
|
|
if c.is_whitespace() {
|
|
|
|
|
break;
|
|
|
|
@ -146,6 +134,24 @@ impl<'text> Lexer<'text> {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl <'text> Iterator for Lexer<'text> {
|
|
|
|
|
type Item = Token;
|
|
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Token> {
|
|
|
|
|
self.skip_whitespace();
|
|
|
|
|
self.kept.clear();
|
|
|
|
|
match self.peek() {
|
|
|
|
|
Some('|') => {
|
|
|
|
|
self.skip();
|
|
|
|
|
Some(Token::Pipe)
|
|
|
|
|
}
|
|
|
|
|
Some('*') => Some(self.glob()),
|
|
|
|
|
Some(_) => Some(self.ident()),
|
|
|
|
|
None => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(PartialEq, Clone)]
|
|
|
|
|
pub enum Element {
|
|
|
|
|
Empty,
|
|
|
|
@ -350,6 +356,10 @@ mod tests {
|
|
|
|
|
Token::Ident(s.into())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn glob<S: Into<String>>(s: S) -> Token {
|
|
|
|
|
Token::Glob(s.into())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
macro_rules! lex {
|
|
|
|
|
(
|
|
|
|
|
$($name:ident: $line:literal $($token:expr)* ;)+
|
|
|
|
@ -407,6 +417,26 @@ mod tests {
|
|
|
|
|
pipeline_2:
|
|
|
|
|
"one |two"
|
|
|
|
|
ident("one") Pipe ident("two");
|
|
|
|
|
|
|
|
|
|
simple_glob:
|
|
|
|
|
"*"
|
|
|
|
|
glob("*");
|
|
|
|
|
|
|
|
|
|
ext_glob:
|
|
|
|
|
"*.rs"
|
|
|
|
|
glob("*.rs");
|
|
|
|
|
|
|
|
|
|
mixed:
|
|
|
|
|
"ls *.rs"
|
|
|
|
|
ident("ls") glob("*.rs");
|
|
|
|
|
|
|
|
|
|
globby_pipeline:
|
|
|
|
|
"ls *.rs | wc -l"
|
|
|
|
|
ident("ls") glob("*.rs") Pipe ident("wc") ident("-l");
|
|
|
|
|
|
|
|
|
|
mid_glob:
|
|
|
|
|
"a*b"
|
|
|
|
|
glob("a*b");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|