mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 08:34:33 +00:00
Fix negative number literals
This commit is contained in:
parent
6cfc98b415
commit
3db0e9e5c6
1 changed files with 37 additions and 47 deletions
|
@ -11,10 +11,8 @@ pub fn number_literal<'a>() -> impl Parser<'a, Expr<'a>> {
|
||||||
|
|
||||||
match chars.next() {
|
match chars.next() {
|
||||||
Some(first_ch) => {
|
Some(first_ch) => {
|
||||||
if first_ch == '-' {
|
if first_ch == '-' || first_ch.is_ascii_digit() {
|
||||||
parse_number_literal(Sign::Negative, first_ch, &mut chars, arena, state)
|
parse_number_literal(first_ch, &mut chars, arena, state)
|
||||||
} else if first_ch.is_ascii_digit() {
|
|
||||||
parse_number_literal(Sign::Positive, first_ch, &mut chars, arena, state)
|
|
||||||
} else {
|
} else {
|
||||||
Err(unexpected(
|
Err(unexpected(
|
||||||
first_ch,
|
first_ch,
|
||||||
|
@ -31,7 +29,6 @@ pub fn number_literal<'a>() -> impl Parser<'a, Expr<'a>> {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn parse_number_literal<'a, I>(
|
fn parse_number_literal<'a, I>(
|
||||||
sign: Sign,
|
|
||||||
first_ch: char,
|
first_ch: char,
|
||||||
chars: &mut I,
|
chars: &mut I,
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
|
@ -40,22 +37,20 @@ fn parse_number_literal<'a, I>(
|
||||||
where
|
where
|
||||||
I: Iterator<Item = char>,
|
I: Iterator<Item = char>,
|
||||||
{
|
{
|
||||||
let mut digits_before_decimal = String::with_capacity_in(1, arena);
|
let mut before_decimal = String::with_capacity_in(1, arena);
|
||||||
let mut digits_after_decimal = String::new_in(arena);
|
let mut after_decimal = String::new_in(arena);
|
||||||
let mut chars_skipped = 0;
|
|
||||||
let mut has_decimal_point = false;
|
let mut has_decimal_point = false;
|
||||||
|
let mut chars_skipped = 0;
|
||||||
|
|
||||||
if sign == Sign::Positive {
|
before_decimal.push(first_ch);
|
||||||
digits_before_decimal.push(first_ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
while let Some(next_ch) = chars.next() {
|
while let Some(next_ch) = chars.next() {
|
||||||
match next_ch {
|
match next_ch {
|
||||||
digit if next_ch.is_ascii_digit() => {
|
digit if next_ch.is_ascii_digit() => {
|
||||||
if has_decimal_point {
|
if has_decimal_point {
|
||||||
digits_after_decimal.push(digit);
|
after_decimal.push(digit);
|
||||||
} else {
|
} else {
|
||||||
digits_before_decimal.push(digit);
|
before_decimal.push(digit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'_' => {
|
'_' => {
|
||||||
|
@ -65,8 +60,7 @@ where
|
||||||
'.' => {
|
'.' => {
|
||||||
if has_decimal_point {
|
if has_decimal_point {
|
||||||
// You only get one decimal point!
|
// You only get one decimal point!
|
||||||
let len =
|
let len = before_decimal.len() + after_decimal.len() + chars_skipped;
|
||||||
digits_before_decimal.len() + digits_after_decimal.len() + chars_skipped;
|
|
||||||
|
|
||||||
return Err(unexpected('.', len, state, Attempting::NumberLiteral));
|
return Err(unexpected('.', len, state, Attempting::NumberLiteral));
|
||||||
} else {
|
} else {
|
||||||
|
@ -75,10 +69,9 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
invalid_char => {
|
invalid_char => {
|
||||||
if digits_before_decimal.is_empty() {
|
if before_decimal.is_empty() {
|
||||||
// No digits! We likely parsed a minus sign that's actually an operator.
|
// No digits! We likely parsed a minus sign that's actually an operator.
|
||||||
let len =
|
let len = before_decimal.len() + after_decimal.len() + chars_skipped;
|
||||||
digits_before_decimal.len() + digits_after_decimal.len() + chars_skipped;
|
|
||||||
return Err(unexpected(
|
return Err(unexpected(
|
||||||
invalid_char,
|
invalid_char,
|
||||||
len,
|
len,
|
||||||
|
@ -96,35 +89,32 @@ where
|
||||||
// At this point we have a number, and will definitely succeed.
|
// At this point we have a number, and will definitely succeed.
|
||||||
// If the number is malformed (too large to fit), we'll succeed with
|
// If the number is malformed (too large to fit), we'll succeed with
|
||||||
// an appropriate Expr which records that.
|
// an appropriate Expr which records that.
|
||||||
let total_chars_parsed = digits_before_decimal.len() + chars_skipped;
|
let expr = if has_decimal_point {
|
||||||
|
let mut f64_buf = String::with_capacity_in(
|
||||||
|
before_decimal.len()
|
||||||
|
// +1 for the decimal point itself
|
||||||
|
+ 1
|
||||||
|
+ after_decimal.len(),
|
||||||
|
arena,
|
||||||
|
);
|
||||||
|
|
||||||
|
f64_buf.push_str(&before_decimal);
|
||||||
|
f64_buf.push('.');
|
||||||
|
f64_buf.push_str(&after_decimal);
|
||||||
|
|
||||||
|
match f64_buf.parse::<f64>() {
|
||||||
|
Ok(float) => Expr::Float(float),
|
||||||
|
Err(_) => Expr::MalformedNumber(Problem::TooLarge),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match before_decimal.parse::<i64>() {
|
||||||
|
Ok(int_val) => Expr::Int(int_val),
|
||||||
|
Err(_) => Expr::MalformedNumber(Problem::TooLarge),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let total_chars_parsed = before_decimal.len() + chars_skipped;
|
||||||
let state = state.advance_without_indenting(total_chars_parsed);
|
let state = state.advance_without_indenting(total_chars_parsed);
|
||||||
|
|
||||||
match digits_before_decimal.parse::<i64>() {
|
Ok((expr, state))
|
||||||
Ok(int_val) => {
|
|
||||||
if has_decimal_point {
|
|
||||||
let mut f64_buf = String::with_capacity_in(
|
|
||||||
digits_before_decimal.len() + 1 + digits_after_decimal.len(),
|
|
||||||
arena,
|
|
||||||
);
|
|
||||||
|
|
||||||
f64_buf.push_str(&digits_before_decimal);
|
|
||||||
f64_buf.push('.');
|
|
||||||
f64_buf.push_str(&digits_after_decimal);
|
|
||||||
|
|
||||||
match f64_buf.parse::<f64>() {
|
|
||||||
Ok(float) => Ok((Expr::Float(float), state)),
|
|
||||||
Err(_) => Ok((Expr::MalformedNumber(Problem::TooLarge), state)),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok((Expr::Int(int_val), state))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => Ok((Expr::MalformedNumber(Problem::TooLarge), state)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
enum Sign {
|
|
||||||
Positive,
|
|
||||||
Negative,
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue