* WIP on blocks

* Getting further

* add some tests
This commit is contained in:
Jonathan Turner
2020-04-20 18:41:51 +12:00
committed by GitHub
parent 6412bfd58d
commit eec94e4016
21 changed files with 384 additions and 155 deletions

View File

@ -29,11 +29,16 @@ impl LiteCommand {
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct LitePipeline {
pub commands: Vec<LiteCommand>,
}
#[derive(Debug, Clone)]
pub struct LiteBlock {
pub block: Vec<LitePipeline>,
}
fn skip_whitespace(src: &mut Input) {
while let Some((_, x)) = src.peek() {
if x.is_whitespace() {
@ -58,7 +63,8 @@ fn bare(src: &mut Input, span_offset: usize) -> Result<Spanned<String>, ParseErr
let mut inside_quote = false;
let mut block_level = vec![];
for (_, c) in src {
while let Some((_, c)) = src.peek() {
let c = *c;
if inside_quote {
if c == delimiter {
inside_quote = false;
@ -84,10 +90,11 @@ fn bare(src: &mut Input, span_offset: usize) -> Result<Spanned<String>, ParseErr
if let Some('(') = block_level.last() {
let _ = block_level.pop();
}
} else if block_level.is_empty() && c.is_whitespace() {
} else if block_level.is_empty() && (c.is_whitespace() || c == '|' || c == ';') {
break;
}
bare.push(c);
let _ = src.next();
}
let span = Span::new(
@ -139,16 +146,14 @@ fn quoted(
fn command(src: &mut Input, span_offset: usize) -> Result<LiteCommand, ParseError> {
let command = bare(src, span_offset)?;
if command.item.is_empty() {
Err(ParseError::unexpected_eof(
"unexpected end of input",
command.span,
))
Err(ParseError::unexpected_eof("command", command.span))
} else {
Ok(LiteCommand::new(command))
}
}
fn pipeline(src: &mut Input, span_offset: usize) -> Result<LitePipeline, ParseError> {
fn pipeline(src: &mut Input, span_offset: usize) -> Result<LiteBlock, ParseError> {
let mut block = vec![];
let mut commands = vec![];
skip_whitespace(src);
@ -167,6 +172,10 @@ fn pipeline(src: &mut Input, span_offset: usize) -> Result<LitePipeline, ParseEr
if let Some((_, c)) = src.peek() {
// The first character tells us a lot about each argument
match c {
';' => {
// this is the end of the command and the end of the pipeline
break;
}
'|' => {
let _ = src.next();
if let Some((pos, next_c)) = src.peek() {
@ -202,21 +211,35 @@ fn pipeline(src: &mut Input, span_offset: usize) -> Result<LitePipeline, ParseEr
}
commands.push(cmd);
skip_whitespace(src);
if let Some((_, ';')) = src.peek() {
let _ = src.next();
if !commands.is_empty() {
block.push(LitePipeline { commands });
commands = vec![];
}
}
}
Ok(LitePipeline { commands })
if !commands.is_empty() {
block.push(LitePipeline { commands });
}
Ok(LiteBlock { block })
}
pub fn lite_parse(src: &str, span_offset: usize) -> Result<LitePipeline, ParseError> {
pub fn lite_parse(src: &str, span_offset: usize) -> Result<LiteBlock, ParseError> {
pipeline(&mut src.char_indices().peekable(), span_offset)
}
#[test]
fn lite_simple_1() -> Result<(), ParseError> {
let result = lite_parse("foo", 0)?;
assert_eq!(result.commands.len(), 1);
assert_eq!(result.commands[0].name.span.start(), 0);
assert_eq!(result.commands[0].name.span.end(), 3);
assert_eq!(result.block.len(), 1);
assert_eq!(result.block[0].commands.len(), 1);
assert_eq!(result.block[0].commands[0].name.span.start(), 0);
assert_eq!(result.block[0].commands[0].name.span.end(), 3);
Ok(())
}
@ -224,9 +247,10 @@ fn lite_simple_1() -> Result<(), ParseError> {
#[test]
fn lite_simple_offset() -> Result<(), ParseError> {
let result = lite_parse("foo", 10)?;
assert_eq!(result.commands.len(), 1);
assert_eq!(result.commands[0].name.span.start(), 10);
assert_eq!(result.commands[0].name.span.end(), 13);
assert_eq!(result.block.len(), 1);
assert_eq!(result.block[0].commands.len(), 1);
assert_eq!(result.block[0].commands[0].name.span.start(), 10);
assert_eq!(result.block[0].commands[0].name.span.end(), 13);
Ok(())
}