First pass

This commit is contained in:
ayazhafiz 2022-02-04 08:46:27 -05:00
parent d25e891fb0
commit 5e0d90ac53
8 changed files with 391 additions and 263 deletions

View file

@ -50,7 +50,7 @@ pub fn num_expr_from_result(
#[inline(always)]
pub fn int_expr_from_result(
var_store: &mut VarStore,
result: Result<(&str, IntValue, NumericBound<IntWidth>), (&str, IntErrorKind)>,
result: Result<(&str, IntValue, IntBound), (&str, IntErrorKind)>,
region: Region,
base: Base,
env: &mut Env,
@ -77,7 +77,7 @@ pub fn int_expr_from_result(
#[inline(always)]
pub fn float_expr_from_result(
var_store: &mut VarStore,
result: Result<(&str, f64, NumericBound<FloatWidth>), (&str, FloatErrorKind)>,
result: Result<(&str, f64, FloatBound), (&str, FloatErrorKind)>,
region: Region,
env: &mut Env,
) -> Expr {
@ -101,8 +101,8 @@ pub fn float_expr_from_result(
}
pub enum ParsedNumResult {
Int(IntValue, NumericBound<IntWidth>),
Float(f64, NumericBound<FloatWidth>),
Int(IntValue, IntBound),
Float(f64, FloatBound),
UnknownNum(IntValue),
}
@ -115,15 +115,13 @@ pub fn finish_parsing_num(raw: &str) -> Result<ParsedNumResult, (&str, IntErrorK
// Let's try to specialize the number
Ok(match bound {
NumericBound::None => ParsedNumResult::UnknownNum(num),
NumericBound::Exact(NumWidth::Int(iw)) => {
ParsedNumResult::Int(num, NumericBound::Exact(iw))
}
NumericBound::Exact(NumWidth::Float(fw)) => {
NumericBound::Int(ib) => ParsedNumResult::Int(num, ib),
NumericBound::Float(fb) => {
let num = match num {
IntValue::I128(n) => n as f64,
IntValue::U128(n) => n as f64,
};
ParsedNumResult::Float(num, NumericBound::Exact(fw))
ParsedNumResult::Float(num, fb)
}
})
}
@ -133,7 +131,7 @@ pub fn finish_parsing_base(
raw: &str,
base: Base,
is_negative: bool,
) -> Result<(IntValue, NumericBound<IntWidth>), (&str, IntErrorKind)> {
) -> Result<(IntValue, IntBound), (&str, IntErrorKind)> {
let radix = match base {
Base::Hex => 16,
Base::Decimal => 10,
@ -149,9 +147,9 @@ pub fn finish_parsing_base(
})
.and_then(|(n, bound)| {
let bound = match bound {
NumericBound::None => NumericBound::None,
NumericBound::Exact(NumWidth::Int(iw)) => NumericBound::Exact(iw),
NumericBound::Exact(NumWidth::Float(_)) => return Err(IntErrorKind::FloatSuffix),
NumericBound::None => IntBound::None,
NumericBound::Int(ib) => ib,
NumericBound::Float(_) => return Err(IntErrorKind::FloatSuffix),
};
Ok((n, bound))
})
@ -159,15 +157,13 @@ pub fn finish_parsing_base(
}
#[inline(always)]
pub fn finish_parsing_float(
raw: &str,
) -> Result<(f64, NumericBound<FloatWidth>), (&str, FloatErrorKind)> {
pub fn finish_parsing_float(raw: &str) -> Result<(f64, FloatBound), (&str, FloatErrorKind)> {
let (opt_bound, raw_without_suffix) = parse_literal_suffix(raw);
let bound = match opt_bound {
None => NumericBound::None,
Some(NumWidth::Float(fw)) => NumericBound::Exact(fw),
Some(NumWidth::Int(_)) => return Err((raw, FloatErrorKind::IntSuffix)),
None => FloatBound::None,
Some(ParsedWidth::Float(fw)) => FloatBound::Exact(fw),
Some(ParsedWidth::Int(_)) => return Err((raw, FloatErrorKind::IntSuffix)),
};
// Ignore underscores.
@ -184,7 +180,13 @@ pub fn finish_parsing_float(
}
}
fn parse_literal_suffix(num_str: &str) -> (Option<NumWidth>, &str) {
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
enum ParsedWidth {
Int(IntWidth),
Float(FloatWidth),
}
fn parse_literal_suffix(num_str: &str) -> (Option<ParsedWidth>, &str) {
macro_rules! parse_num_suffix {
($($suffix:expr, $width:expr)*) => {$(
if num_str.ends_with($suffix) {
@ -194,20 +196,20 @@ fn parse_literal_suffix(num_str: &str) -> (Option<NumWidth>, &str) {
}
parse_num_suffix! {
"u8", NumWidth::Int(IntWidth::U8)
"u16", NumWidth::Int(IntWidth::U16)
"u32", NumWidth::Int(IntWidth::U32)
"u64", NumWidth::Int(IntWidth::U64)
"u128", NumWidth::Int(IntWidth::U128)
"i8", NumWidth::Int(IntWidth::I8)
"i16", NumWidth::Int(IntWidth::I16)
"i32", NumWidth::Int(IntWidth::I32)
"i64", NumWidth::Int(IntWidth::I64)
"i128", NumWidth::Int(IntWidth::I128)
"nat", NumWidth::Int(IntWidth::Nat)
"dec", NumWidth::Float(FloatWidth::Dec)
"f32", NumWidth::Float(FloatWidth::F32)
"f64", NumWidth::Float(FloatWidth::F64)
"u8", ParsedWidth::Int(IntWidth::U8)
"u16", ParsedWidth::Int(IntWidth::U16)
"u32", ParsedWidth::Int(IntWidth::U32)
"u64", ParsedWidth::Int(IntWidth::U64)
"u128", ParsedWidth::Int(IntWidth::U128)
"i8", ParsedWidth::Int(IntWidth::I8)
"i16", ParsedWidth::Int(IntWidth::I16)
"i32", ParsedWidth::Int(IntWidth::I32)
"i64", ParsedWidth::Int(IntWidth::I64)
"i128", ParsedWidth::Int(IntWidth::I128)
"nat", ParsedWidth::Int(IntWidth::Nat)
"dec", ParsedWidth::Float(FloatWidth::Dec)
"f32", ParsedWidth::Float(FloatWidth::F32)
"f64", ParsedWidth::Float(FloatWidth::F64)
}
(None, num_str)
@ -221,10 +223,7 @@ fn parse_literal_suffix(num_str: &str) -> (Option<NumWidth>, &str) {
/// the LEGAL_DETAILS file in the root directory of this distribution.
///
/// Thanks to the Rust project and its contributors!
fn from_str_radix(
src: &str,
radix: u32,
) -> Result<(IntValue, NumericBound<NumWidth>), IntErrorKind> {
fn from_str_radix(src: &str, radix: u32) -> Result<(IntValue, NumericBound), IntErrorKind> {
use self::IntErrorKind::*;
assert!(
@ -268,19 +267,31 @@ fn from_str_radix(
match opt_exact_bound {
None => {
// TODO: use the lower bound
Ok((result, NumericBound::None))
// There's no exact bound, but we do have a lower bound.
let sign_demand = if is_negative {
SignDemand::Signed
} else {
SignDemand::NoDemand
};
Ok((
result,
IntBound::AtLeast {
sign: sign_demand,
width: lower_bound,
}
.into(),
))
}
Some(bound @ NumWidth::Float(_)) => {
Some(ParsedWidth::Float(fw)) => {
// For now, assume floats can represent all integers
// TODO: this is somewhat incorrect, revisit
Ok((result, NumericBound::Exact(bound)))
Ok((result, FloatBound::Exact(fw).into()))
}
Some(NumWidth::Int(exact_width)) => {
Some(ParsedWidth::Int(exact_width)) => {
// We need to check if the exact bound >= lower bound.
if exact_width.is_superset(&lower_bound, is_negative) {
// Great! Use the exact bound.
Ok((result, NumericBound::Exact(NumWidth::Int(exact_width))))
Ok((result, IntBound::Exact(exact_width).into()))
} else {
// This is something like 200i8; the lower bound is u8, which holds strictly more
// ints on the positive side than i8 does. Report an error depending on which side
@ -474,19 +485,47 @@ pub enum FloatWidth {
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum NumWidth {
Int(IntWidth),
Float(FloatWidth),
pub enum SignDemand {
/// Can be signed or unsigned.
NoDemand,
/// Must be signed.
Signed,
}
/// Describes a bound on the width of a numeric literal.
/// Describes a bound on the width of an integer.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum NumericBound<W>
where
W: Copy,
{
pub enum IntBound {
/// There is no bound on the width.
None,
/// Must have exactly the width `W`.
Exact(W),
/// Must have an exact width.
Exact(IntWidth),
/// Must have a certain sign and a minimum width.
AtLeast { sign: SignDemand, width: IntWidth },
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum FloatBound {
None,
Exact(FloatWidth),
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum NumericBound {
None,
Int(IntBound),
Float(FloatBound),
}
impl From<IntBound> for NumericBound {
#[inline(always)]
fn from(ib: IntBound) -> Self {
Self::Int(ib)
}
}
impl From<FloatBound> for NumericBound {
#[inline(always)]
fn from(fb: FloatBound) -> Self {
Self::Float(fb)
}
}