Parse numbers as either integers or decimals

This commit is contained in:
Tobie Morgan Hitchcock 2022-03-16 23:19:50 +00:00
parent 636eee4a25
commit 97c0e50654

View file

@ -1,4 +1,5 @@
use crate::sql::comment::comment; use crate::sql::comment::comment;
use crate::sql::error::Error::ParserError;
use crate::sql::error::IResult; use crate::sql::error::IResult;
use crate::sql::operator::{assigner, operator}; use crate::sql::operator::{assigner, operator};
use dec::prelude::FromPrimitive; use dec::prelude::FromPrimitive;
@ -6,12 +7,14 @@ use dec::prelude::ToPrimitive;
use dec::Decimal; use dec::Decimal;
use dec::MathematicalOps; use dec::MathematicalOps;
use nom::branch::alt; use nom::branch::alt;
use nom::bytes::complete::tag; use nom::character::complete::char;
use nom::character::complete::digit1;
use nom::character::complete::multispace1; use nom::character::complete::multispace1;
use nom::combinator::eof; use nom::combinator::eof;
use nom::combinator::map; use nom::combinator::map;
use nom::combinator::peek; use nom::combinator::peek;
use nom::number::complete::recognize_float; use nom::number::complete::recognize_float;
use nom::Err::Error;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::cmp::Ordering; use std::cmp::Ordering;
use std::fmt; use std::fmt;
@ -499,17 +502,41 @@ impl<'a> Product<&'a Self> for Number {
} }
pub fn number(i: &str) -> IResult<&str, Number> { pub fn number(i: &str) -> IResult<&str, Number> {
alt((integer, decimal))(i)
}
fn integer(i: &str) -> IResult<&str, Number> {
let (i, v) = digit1(i)?;
let (i, _) = peek(alt((
map(multispace1, |_| ()),
map(operator, |_| ()),
map(assigner, |_| ()),
map(comment, |_| ()),
map(char(')'), |_| ()),
map(char(']'), |_| ()),
map(char('}'), |_| ()),
map(char(';'), |_| ()),
map(char(','), |_| ()),
map(eof, |_| ()),
)))(i)?;
match v.parse::<i64>() {
Ok(v) => Ok((i, Number::from(v))),
_ => Err(Error(ParserError(i))),
}
}
fn decimal(i: &str) -> IResult<&str, Number> {
let (i, v) = recognize_float(i)?; let (i, v) = recognize_float(i)?;
let (i, _) = peek(alt(( let (i, _) = peek(alt((
map(multispace1, |_| ()), map(multispace1, |_| ()),
map(operator, |_| ()), map(operator, |_| ()),
map(assigner, |_| ()), map(assigner, |_| ()),
map(comment, |_| ()), map(comment, |_| ()),
map(tag(")"), |_| ()), map(char(')'), |_| ()),
map(tag("]"), |_| ()), map(char(']'), |_| ()),
map(tag("}"), |_| ()), map(char('}'), |_| ()),
map(tag(";"), |_| ()), map(char(';'), |_| ()),
map(tag(","), |_| ()), map(char(','), |_| ()),
map(eof, |_| ()), map(eof, |_| ()),
)))(i)?; )))(i)?;
Ok((i, Number::from(v))) Ok((i, Number::from(v)))