Put parsing details into one module

This commit is contained in:
Yuriy Dupyn 2024-01-26 19:45:15 +01:00
parent 61c0a34253
commit 6000b1f242
10 changed files with 30 additions and 29 deletions

View file

@ -1,164 +0,0 @@
use minisql::type_system::{IndexableValue, Value};
use nom::{
branch::alt,
character::complete::{u64, char, digit1, none_of},
combinator::opt,
multi::many0,
sequence::{delimited, pair, preceded},
IResult, error::make_error
};
pub fn parse_db_value(input: &str) -> IResult<&str, Value> {
alt((
parse_string,
parse_number,
parse_int,
parse_uuid,
))(input)
}
pub fn parse_number(input: &str) -> IResult<&str, Value> {
// Parse the integer part
let (input, (sign, digits)) = pair(opt(char('-')), digit1)(input)?;
// Parse the fractional part
let (input, frac_part) = opt(pair(char('.'), digit1))(input)?;
match frac_part {
Some((_fsign, fdigits)) => {
// Combine integer and fractional parts
let combined_parts = format!(
"{}{}",
format!("{}{}", sign.unwrap_or('+'), digits),
format!(".{}", fdigits)
);
// Parse the combined parts as a floating-point number
let value = combined_parts.parse::<f64>()
.map_err(|_| {
nom::Err::Failure(make_error(input, nom::error::ErrorKind::Fail))
})?;
Ok((input, Value::Number(value)))
}
None => {
let value = format!("{}{}", sign.unwrap_or('+'), digits).parse::<u64>()
.map_err(|_| {
nom::Err::Failure(make_error(input, nom::error::ErrorKind::Fail))
})?;
Ok((input, Value::Indexable(IndexableValue::Int(value))))
}
}
}
pub fn parse_int(input: &str) -> IResult<&str, Value> {
u64(input).map(|(input, v)| {
(input, Value::Indexable(IndexableValue::Int(v)))
})
}
fn escape_tab(input:&str) -> IResult<&str, char> {
let (input, _) = preceded(char('\\'), char('t'))(input)?;
Ok((input, '\t'))
}
fn escape_backslash(input:&str) -> IResult<&str, char> {
let (input, _) = preceded(char('\\'), char('\\'))(input)?;
Ok((input, '\\'))
}
fn escape_newline(input:&str) -> IResult<&str, char> {
let (input, _) = preceded(char('\\'), char('n'))(input)?;
Ok((input, '\n'))
}
fn escape_carriegereturn(input:&str) -> IResult<&str, char> {
let (input, _) = preceded(char('\\'), char('r'))(input)?;
Ok((input, '\r'))
}
fn escape_doublequote(input:&str) -> IResult<&str, char> {
preceded(char('\\'), char('"'))(input)
}
pub fn parse_string(input: &str) -> IResult<&str, Value> {
// Parse the content inside the double quotes
let (input, content) = delimited(
char('"'),
many0(alt((
escape_backslash,
escape_carriegereturn,
escape_newline,
escape_doublequote,
escape_tab,
none_of(r#"\""#)
))),
char('"'),
)(input)?;
// Combine the characters into a string
let value: String = content.into_iter().collect();
Ok((input, Value::Indexable(IndexableValue::String(value))))
}
fn parse_uuid(input: &str) -> IResult<&str, Value> {
// TODO: make it actually uuid
u64(input).map(|(input, v)| {
(input, Value::Indexable(IndexableValue::Uuid(v)))
})
}
#[cfg(test)]
mod tests {
use minisql::type_system::{IndexableValue, Value};
use crate::literal::{parse_db_value, parse_string};
#[test]
fn test_string_parser() {
assert_eq!(parse_string(r#""simple""#), Ok(("", Value::Indexable(IndexableValue::String(String::from("simple"))))));
assert_eq!(parse_string(r#""\"\t\r\n\\""#), Ok(("", Value::Indexable(IndexableValue::String(String::from("\"\t\r\n\\"))))));
assert_eq!(parse_string(r#""name is \"John\".""#), Ok(("", Value::Indexable(IndexableValue::String(String::from("name is \"John\"."))))));
}
#[test]
fn test_parse_db_value() {
let (input, value) = parse_db_value("5").expect("should parse");
assert_eq!(input, "");
assert_eq!(value, Value::Indexable(IndexableValue::Int(5)));
let (input, value) = parse_db_value("5.5").expect("should parse");
assert_eq!(input, "");
assert_eq!(value, Value::Number(5.5));
let (_, _) = parse_db_value("\"STRING\"").expect("should parse");
let (input, value) = parse_db_value("\"abcdefghkjklmnopqrstuvwxyz!@#$%^&*()_+ \"").expect("should parse");
assert_eq!(input, "");
assert_eq!(value, Value::Indexable(IndexableValue::String("abcdefghkjklmnopqrstuvwxyz!@#$%^&*()_+ ".to_string())));
}
#[test]
fn test_parse_positive_float() {
assert_eq!(parse_db_value("23.213313"), Ok(("", Value::Number(23.213313))));
assert_eq!(parse_db_value("2241.9734"), Ok(("", Value::Number(2241.9734))));
}
#[test]
fn test_parse_negative_float() {
assert_eq!(parse_db_value("-9241.873654"), Ok(("", Value::Number(-9241.873654))));
assert_eq!(parse_db_value("-62625.0"), Ok(("", Value::Number(-62625.0))));
}
#[test]
fn test_parse_float_between_0_and_1() {
assert_eq!(parse_db_value("0.873654"), Ok(("", Value::Number(0.873654))));
assert_eq!(parse_db_value("0.62625"), Ok(("", Value::Number(0.62625))));
}
#[test]
fn test_parse_int() {
assert_eq!(parse_db_value("5134616"), Ok(("", Value::Indexable(IndexableValue::Int(5134616)))));
}
}