mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-01 07:41:12 +00:00
First pass
This commit is contained in:
parent
d25e891fb0
commit
5e0d90ac53
8 changed files with 391 additions and 263 deletions
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue