Return error for unterminated string in bareword parser (#2103)

* add some tests

* add failing tests

* use some; fix test

* clean up code, flesh out tests

* cargo fmt
This commit is contained in:
Philip Peterson 2020-07-03 22:14:31 -07:00 committed by GitHub
parent eb02c773d0
commit 0629c896eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -49,6 +49,12 @@ fn skip_whitespace(src: &mut Input) {
}
}
enum BlockKind {
Paren,
CurlyBracket,
SquareBracket,
}
fn bare(src: &mut Input, span_offset: usize) -> Result<Spanned<String>, ParseError> {
skip_whitespace(src);
@ -59,35 +65,33 @@ fn bare(src: &mut Input, span_offset: usize) -> Result<Spanned<String>, ParseErr
0
};
let mut delimiter = ' ';
let mut inside_quote = false;
let mut block_level = vec![];
let mut inside_quote: Option<char> = None;
let mut block_level: Vec<BlockKind> = vec![];
while let Some((_, c)) = src.peek() {
let c = *c;
if inside_quote {
if c == delimiter {
inside_quote = false;
if inside_quote.is_some() {
if Some(c) == inside_quote {
inside_quote = None;
}
} else if c == '\'' || c == '"' || c == '`' {
inside_quote = true;
delimiter = c;
inside_quote = Some(c);
} else if c == '[' {
block_level.push(c);
block_level.push(BlockKind::SquareBracket);
} else if c == ']' {
if let Some('[') = block_level.last() {
if let Some(BlockKind::SquareBracket) = block_level.last() {
let _ = block_level.pop();
}
} else if c == '{' {
block_level.push(c);
block_level.push(BlockKind::CurlyBracket);
} else if c == '}' {
if let Some('{') = block_level.last() {
if let Some(BlockKind::CurlyBracket) = block_level.last() {
let _ = block_level.pop();
}
} else if c == '(' {
block_level.push(c);
block_level.push(BlockKind::Paren);
} else if c == ')' {
if let Some('(') = block_level.last() {
if let Some(BlockKind::Paren) = block_level.last() {
let _ = block_level.pop();
}
} else if block_level.is_empty() && (c.is_whitespace() || c == '|' || c == ';') {
@ -101,9 +105,191 @@ fn bare(src: &mut Input, span_offset: usize) -> Result<Spanned<String>, ParseErr
start_offset + span_offset,
start_offset + span_offset + bare.len(),
);
if let Some(block) = block_level.last() {
return Err(ParseError::unexpected_eof(
match block {
BlockKind::Paren => ")",
BlockKind::SquareBracket => "]",
BlockKind::CurlyBracket => "}",
},
span,
));
}
if let Some(delimiter) = inside_quote {
return Err(ParseError::unexpected_eof(delimiter.to_string(), span));
}
Ok(bare.spanned(span))
}
#[test]
fn bare_simple_1() -> Result<(), ParseError> {
let input = "foo bar baz";
let input = &mut input.char_indices().peekable();
let result = bare(input, 0)?;
assert_eq!(result.span.start(), 0);
assert_eq!(result.span.end(), 3);
Ok(())
}
#[test]
fn bare_simple_2() -> Result<(), ParseError> {
let input = "'foo bar' baz";
let input = &mut input.char_indices().peekable();
let result = bare(input, 0)?;
assert_eq!(result.span.start(), 0);
assert_eq!(result.span.end(), 9);
Ok(())
}
#[test]
fn bare_simple_3() -> Result<(), ParseError> {
let input = "'foo\" bar' baz";
let input = &mut input.char_indices().peekable();
let result = bare(input, 0)?;
assert_eq!(result.span.start(), 0);
assert_eq!(result.span.end(), 10);
Ok(())
}
#[test]
fn bare_simple_4() -> Result<(), ParseError> {
let input = "[foo bar] baz";
let input = &mut input.char_indices().peekable();
let result = bare(input, 0)?;
assert_eq!(result.span.start(), 0);
assert_eq!(result.span.end(), 9);
Ok(())
}
#[test]
fn bare_simple_5() -> Result<(), ParseError> {
let input = "'foo 'bar baz";
let input = &mut input.char_indices().peekable();
let result = bare(input, 0)?;
assert_eq!(result.span.start(), 0);
assert_eq!(result.span.end(), 9);
Ok(())
}
#[test]
fn bare_simple_6() -> Result<(), ParseError> {
let input = "''foo baz";
let input = &mut input.char_indices().peekable();
let result = bare(input, 0)?;
assert_eq!(result.span.start(), 0);
assert_eq!(result.span.end(), 5);
Ok(())
}
#[test]
fn bare_simple_7() -> Result<(), ParseError> {
let input = "'' foo";
let input = &mut input.char_indices().peekable();
let result = bare(input, 0)?;
assert_eq!(result.span.start(), 0);
assert_eq!(result.span.end(), 2);
Ok(())
}
#[test]
fn bare_simple_8() -> Result<(), ParseError> {
let input = " '' foo";
let input = &mut input.char_indices().peekable();
let result = bare(input, 0)?;
assert_eq!(result.span.start(), 1);
assert_eq!(result.span.end(), 3);
Ok(())
}
#[test]
fn bare_simple_9() -> Result<(), ParseError> {
let input = " 'foo' foo";
let input = &mut input.char_indices().peekable();
let result = bare(input, 0)?;
assert_eq!(result.span.start(), 1);
assert_eq!(result.span.end(), 6);
Ok(())
}
#[test]
fn bare_ignore_future() -> Result<(), ParseError> {
let input = "foo 'bar";
let input = &mut input.char_indices().peekable();
let result = bare(input, 0)?;
assert_eq!(result.span.start(), 0);
assert_eq!(result.span.end(), 3);
Ok(())
}
#[test]
fn bare_invalid_1() -> Result<(), ParseError> {
let input = "'foo bar";
let input = &mut input.char_indices().peekable();
let result = bare(input, 0);
assert_eq!(result.is_ok(), false);
Ok(())
}
#[test]
fn bare_invalid_2() -> Result<(), ParseError> {
let input = "'bar";
let input = &mut input.char_indices().peekable();
let result = bare(input, 0);
assert_eq!(result.is_ok(), false);
Ok(())
}
#[test]
fn bare_invalid_4() -> Result<(), ParseError> {
let input = " 'bar";
let input = &mut input.char_indices().peekable();
let result = bare(input, 0);
assert_eq!(result.is_ok(), false);
Ok(())
}
fn command(src: &mut Input, span_offset: usize) -> Result<LiteCommand, ParseError> {
let command = bare(src, span_offset)?;
if command.item.is_empty() {