Skip to content

Commit

Permalink
Make consume_number always advance through the source text.
Browse files Browse the repository at this point in the history
  • Loading branch information
jimblandy committed Jun 10, 2022
1 parent f086748 commit b9ee4c8
Showing 1 changed file with 52 additions and 45 deletions.
97 changes: 52 additions & 45 deletions src/front/wgsl/number.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,33 +17,40 @@ pub enum Number {
F32(f32),
}

impl Number {
/// Convert abstract numbers to a plausible concrete counterpart.
///
/// Return concrete numbers unchanged. If the conversion would be
/// lossy, return an error.
fn abstract_to_concrete(self) -> Result<Number, NumberError> {
match self {
Number::AbstractInt(num) => {
use std::convert::TryFrom;
i32::try_from(num)
.map(Number::I32)
.map_err(|_| NumberError::NotRepresentable)
}
Number::AbstractFloat(num) => {
let num = num as f32;
if num.is_finite() {
Ok(Number::F32(num))
} else {
Err(NumberError::NotRepresentable)
}
}
num => Ok(num),
}
}
}

// TODO: when implementing Creation-Time Expressions, remove the ability to match the minus sign

pub(super) fn consume_number(input: &str) -> (Token<'_>, &str) {
let res = if let Some((num, rest)) = parse(input) {
(num, rest)
} else {
(Err(NumberError::Invalid), input)
};

let num = match res.0 {
Ok(Number::AbstractInt(num)) => {
use std::convert::TryFrom;
i32::try_from(num)
.map(Number::I32)
.map_err(|_| NumberError::NotRepresentable)
}
Ok(Number::AbstractFloat(num)) => {
let num = num as f32;
if num.is_finite() {
Ok(Number::F32(num))
} else {
Err(NumberError::NotRepresentable)
}
}
num => num,
};
(Token::Number(num), res.1)
let (result, rest) = parse(input);
(
Token::Number(result.and_then(Number::abstract_to_concrete)),
rest,
)
}

enum Kind {
Expand Down Expand Up @@ -83,7 +90,7 @@ enum FloatKind {
// You could visualize the regex below via https://debuggex.com to get a rough idea what `parse` is doing
// -?(?:0[xX](?:([0-9a-fA-F]+\.[0-9a-fA-F]*|[0-9a-fA-F]*\.[0-9a-fA-F]+)(?:([pP][+-]?[0-9]+)([fh]?))?|([0-9a-fA-F]+)([pP][+-]?[0-9]+)([fh]?)|([0-9a-fA-F]+)([iu]?))|((?:[0-9]+[eE][+-]?[0-9]+|(?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+)(?:[eE][+-]?[0-9]+)?))([fh]?)|((?:[0-9]|[1-9][0-9]+))([iufh]?))

fn parse(input: &str) -> Option<(Result<Number, NumberError>, &str)> {
fn parse(input: &str) -> (Result<Number, NumberError>, &str) {
/// returns `true` and consumes `X` bytes from the given byte buffer
/// if the given `X` nr of patterns are found at the start of the buffer
macro_rules! consume {
Expand Down Expand Up @@ -170,7 +177,7 @@ fn parse(input: &str) -> Option<(Result<Number, NumberError>, &str)> {
let consumed_after_period = consume_hex_digits!(bytes);

if consumed + consumed_after_period == 0 {
return None;
return (Err(NumberError::Invalid), rest_to_str!(bytes));
}

let significand = general_extract.end(bytes);
Expand All @@ -180,23 +187,23 @@ fn parse(input: &str) -> Option<(Result<Number, NumberError>, &str)> {
let consumed = consume_dec_digits!(bytes);

if consumed == 0 {
return None;
return (Err(NumberError::Invalid), rest_to_str!(bytes));
}

let number = general_extract.end(bytes);

let kind = consume_map!(bytes, [b'f' => FloatKind::F32, b'h' => FloatKind::F16]);

Some((parse_hex_float(number, kind), rest_to_str!(bytes)))
(parse_hex_float(number, kind), rest_to_str!(bytes))
} else {
Some((
(
parse_hex_float_missing_exponent(significand, None),
rest_to_str!(bytes),
))
)
}
} else {
if consumed == 0 {
return None;
return (Err(NumberError::Invalid), rest_to_str!(bytes));
}

let significand = general_extract.end(bytes);
Expand All @@ -209,24 +216,24 @@ fn parse(input: &str) -> Option<(Result<Number, NumberError>, &str)> {
let consumed = consume_dec_digits!(bytes);

if consumed == 0 {
return None;
return (Err(NumberError::Invalid), rest_to_str!(bytes));
}

let exponent = exp_extract.end(bytes);

let kind = consume_map!(bytes, [b'f' => FloatKind::F32, b'h' => FloatKind::F16]);

Some((
(
parse_hex_float_missing_period(significand, exponent, kind),
rest_to_str!(bytes),
))
)
} else {
let kind = consume_map!(bytes, [b'i' => IntKind::I32, b'u' => IntKind::U32]);

Some((
(
parse_hex_int(is_negative, digits, kind),
rest_to_str!(bytes),
))
)
}
}
} else {
Expand All @@ -238,45 +245,45 @@ fn parse(input: &str) -> Option<(Result<Number, NumberError>, &str)> {
let consumed_after_period = consume_dec_digits!(bytes);

if consumed + consumed_after_period == 0 {
return None;
return (Err(NumberError::Invalid), rest_to_str!(bytes));
}

if consume!(bytes, b'e' | b'E') {
consume!(bytes, b'+' | b'-');
let consumed = consume_dec_digits!(bytes);

if consumed == 0 {
return None;
return (Err(NumberError::Invalid), rest_to_str!(bytes));
}
}

let number = general_extract.end(bytes);

let kind = consume_map!(bytes, [b'f' => FloatKind::F32, b'h' => FloatKind::F16]);

Some((parse_dec_float(number, kind), rest_to_str!(bytes)))
(parse_dec_float(number, kind), rest_to_str!(bytes))
} else {
if consumed == 0 {
return None;
return (Err(NumberError::Invalid), rest_to_str!(bytes));
}

if consume!(bytes, b'e' | b'E') {
consume!(bytes, b'+' | b'-');
let consumed = consume_dec_digits!(bytes);

if consumed == 0 {
return None;
return (Err(NumberError::Invalid), rest_to_str!(bytes));
}

let number = general_extract.end(bytes);

let kind = consume_map!(bytes, [b'f' => FloatKind::F32, b'h' => FloatKind::F16]);

Some((parse_dec_float(number, kind), rest_to_str!(bytes)))
(parse_dec_float(number, kind), rest_to_str!(bytes))
} else {
// make sure the multi-digit numbers don't start with zero
if consumed > 1 && is_first_zero {
return None;
return (Err(NumberError::Invalid), rest_to_str!(bytes));
}

let digits_with_sign = general_extract.end(bytes);
Expand All @@ -288,10 +295,10 @@ fn parse(input: &str) -> Option<(Result<Number, NumberError>, &str)> {
b'h' => Kind::Float(FloatKind::F16)
]);

Some((
(
parse_dec(is_negative, digits_with_sign, kind),
rest_to_str!(bytes),
))
)
}
}
}
Expand Down

0 comments on commit b9ee4c8

Please sign in to comment.