Skip to content

Commit

Permalink
test: Include proptests
Browse files Browse the repository at this point in the history
  • Loading branch information
LeoRiether committed Jun 13, 2024
1 parent e75fdf2 commit e262958
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 23 deletions.
113 changes: 111 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ owo-colors = "3.5.0"
serde = { version = "1.0.171", features = ["derive"] }
toml = "0.7.6"
ahash = "0.8.11"
proptest = "1.4.0"

[dependencies.clap]
version = "4.5"
Expand Down
11 changes: 11 additions & 0 deletions proptest-regressions/parser/mod.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Seeds for failure cases proptest has generated in the past. It is
# automatically read and these particular cases re-run before any
# novel cases are generated.
#
# It is recommended to check this file in to source control so that
# everyone who runs the test benefits from these saved cases.
cc 407ea58689884bfff9c2a39384df853776b4dd55a0122283144837573b6eac0a # shrinks to s = ";"
cc 20080fd2cb666a3ffd533f75b19a24947f138ae0bd2af352127b1f709220013c # shrinks to s = "\""
cc 4a9f4b7272dadf4249b422581a333ae5645ac9e75d51115272e3af1a90400ad0 # shrinks to s = "\"\\"
cc 87448d7f9120eba78b89edebf33cc84139071f52a0137cdfcbc191274ca6f006 # shrinks to s = "-"
cc 78096578d744f3a6e05d123f95540e1bdab2d2cf815e870f2a65c9b023cd0404 # shrinks to s = "'"
15 changes: 15 additions & 0 deletions src/parser/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,21 @@ pub enum LexerError {

#[error("Expected '{}', but found '{}'", expected.bright_blue(), found.bright_yellow())]
UnexpectedChar { expected: char, found: char },

#[error("Unknown char '{0}'")]
UnknownChar(char),

#[error("Unexpected espace sequence '\\{0}'")]
UnexpectedEscapeSequence(char),

#[error("Expected escape sequence after '\\', found nothing")]
ExpectedEscapeSequence,

#[error("Expected character, found nothing")]
ExpectedChar,

#[error("Invalid number '{0}'")]
InvalidNumber(String),
}

#[derive(Debug, thiserror::Error)]
Expand Down
47 changes: 26 additions & 21 deletions src/parser/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,24 +104,26 @@ impl Lexer {
}

// WARN: assumes the '\' has already been consumed
fn next_escape_sequence(&mut self) -> char {
fn next_escape_sequence(&mut self) -> Result<char, Error> {
match self.consume() {
Some('n') => '\n',
Some('t') => '\t',
Some('r') => '\r',
Some('\\') => '\\',
Some('"') => '"',
_ => todo!("Return an Error::InvalidEscapeSequence"),
Some('n') => Ok('\n'),
Some('t') => Ok('\t'),
Some('r') => Ok('\r'),
Some('\\') => Ok('\\'),
Some('"') => Ok('"'),
Some(c) => Err(LexerError::UnexpectedEscapeSequence(c).into()),
None => Err(LexerError::ExpectedEscapeSequence.into()),
}
}

fn next_string_literal(&mut self) -> Result<Token, Error> {
let mut string = String::new();
expect!(Some('"') = self.consume());
while self.peek() != Some('"') {
// Consume chars while there are some to consume, but they're not the end of the string yet
while self.peek().is_some() && self.peek() != Some('"') {
let mut c = self.consume().unwrap();
if c == '\\' {
c = self.next_escape_sequence();
c = self.next_escape_sequence()?;
}
string.push(c);
}
Expand All @@ -132,16 +134,19 @@ impl Lexer {

fn next_char_literal(&mut self) -> Result<Token, Error> {
expect!(Some('\'') = self.consume());
let mut c = self.consume().unwrap();
let mut c = match self.consume() {
Some(c) => c,
None => return Err(LexerError::ExpectedChar.into()),
};
if c == '\\' {
c = self.next_escape_sequence();
c = self.next_escape_sequence()?;
}
expect!(Some('\'') = self.consume());

Ok(Token::new(Data::CharLiteral(c)))
}

fn next_number(&mut self) -> Token {
fn next_number(&mut self) -> Result<Token, Error> {
let cursor = self.cursor;
let mut i = 0;
while let Some('-' | '.' | '0'..='9' | 'x' | 'o' | 'a'..='f' | 'A'..='F') = self.peek() {
Expand Down Expand Up @@ -170,20 +175,20 @@ impl Lexer {
};

if res.is_err() {
let fres = slice.parse::<f32>();
if let Ok(mut x) = fres {
if negative {
x = -x;
}
return Token::new(Data::Float(x));
let mut fres = slice
.parse::<f32>()
.map_err(|_| LexerError::InvalidNumber(slice.to_string()))?;
if negative {
fres = -fres;
}
return Ok(Token::new(Data::Float(fres)));
}

let mut x = res.unwrap() as i32;
if negative {
x = -x;
}
Token::new(Data::Integer(x))
Ok(Token::new(Data::Integer(x)))
}
}

Expand Down Expand Up @@ -237,7 +242,7 @@ impl Iterator for Lexer {
Some(Ok(Token::new(Data::Char(next_char)).with_ctx(ctx)))
}

'-' | '0'..='9' => Some(Ok(self.next_number().with_ctx(ctx))),
'-' | '0'..='9' => Some(self.next_number().with_ctx(ctx)),

allowed_identifier!(start) => {
let identifier = self.next_identifier();
Expand All @@ -255,7 +260,7 @@ impl Iterator for Lexer {
}
}

_ => panic!("Unimplemented character: {}", next_char),
other => Some(Err(LexerError::UnknownChar(other).into())),
}
}
}
Expand Down
18 changes: 18 additions & 0 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ pub fn parse(entry_file: &str, data_segment_size: usize) -> ParseResult {
parse_tokens(tokens, data_segment_size)
}

pub fn parse_str(content: String, data_segment_size: usize) -> ParseResult {
let tokens = Lexer::from_content(content, "<no file>").preprocess().peekable();
parse_tokens(tokens, data_segment_size)
}

pub fn parse_tokens<I: Iterator<Item = Result<Token, Error>>>(
mut tokens: Peekable<I>,
data_segment_size: usize,
Expand Down Expand Up @@ -261,3 +266,16 @@ fn parse_globl(
_ => Err(ParserError::UnexpectedToken(Some(label.data)).with_context(label.ctx)),
}
}

#[cfg(test)]
mod tests {
use super::*;
use proptest::prelude::*;

proptest! {
#[test]
fn parse_doesnt_crash(s in "\\PC*") {
let _ = parse_str(s, 0x100);
}
}
}

0 comments on commit e262958

Please sign in to comment.