Frac+Approx --> Float

This commit is contained in:
Richard Feldman 2019-09-01 00:50:11 -04:00
parent 695d1eb467
commit 04595a9e71
11 changed files with 112 additions and 207 deletions

View file

@ -13,8 +13,7 @@ use self::PatternType::*;
pub enum Expr { pub enum Expr {
// Literals // Literals
Int(i64), Int(i64),
Frac(i64, i64), Float(f64),
Approx(f64),
EmptyStr, EmptyStr,
Str(String), Str(String),
Char(char), Char(char),
@ -72,8 +71,8 @@ pub enum Problem {
pub enum Pattern { pub enum Pattern {
Identifier(Symbol), Identifier(Symbol),
Variant(Symbol, Option<Vec<Located<Pattern>>>), Variant(Symbol, Option<Vec<Located<Pattern>>>),
Integer(i64), IntLiteral(i64),
Fraction(i64, i64), FloatLiteral(f64),
ExactString(String), ExactString(String),
EmptyRecordLiteral, EmptyRecordLiteral,
Underscore, Underscore,
@ -303,8 +302,7 @@ fn canonicalize(
let (expr, output) = match loc_expr.value { let (expr, output) = match loc_expr.value {
expr::Expr::Int(num) => ( Int(num), Output::new() ), expr::Expr::Int(num) => ( Int(num), Output::new() ),
expr::Expr::Frac(numerator, denominator) => ( Frac(numerator, denominator), Output::new()), expr::Expr::Float(num) => ( Float(num), Output::new() ),
expr::Expr::Approx(num) => ( Approx(num), Output::new()),
expr::Expr::EmptyRecord => ( EmptyRecord, Output::new()), expr::Expr::EmptyRecord => ( EmptyRecord, Output::new()),
expr::Expr::Str(string) => ( Str(string), Output::new()), expr::Expr::Str(string) => ( Str(string), Output::new()),
expr::Expr::Char(ch) => ( Char(ch), Output::new()), expr::Expr::Char(ch) => ( Char(ch), Output::new()),
@ -577,7 +575,6 @@ fn canonicalize(
// Store the referenced locals in the refs_by_assignment map, so we can later figure out // Store the referenced locals in the refs_by_assignment map, so we can later figure out
// which assigned names reference each other. // which assigned names reference each other.
for (ident, (symbol, region)) in idents_from_patterns(std::iter::once(&loc_pattern), &scope) { for (ident, (symbol, region)) in idents_from_patterns(std::iter::once(&loc_pattern), &scope) {
println!("* * * symbol: {:?}, is_closure_defn: {:?}", symbol, renamed_closure_assignment);
let refs = let refs =
// Functions' references don't count in assignments. // Functions' references don't count in assignments.
// See 3d5a2560057d7f25813112dfa5309956c0f9e6a9 and its // See 3d5a2560057d7f25813112dfa5309956c0f9e6a9 and its
@ -1024,7 +1021,7 @@ fn add_idents_from_pattern(
} }
} }
}, },
&Integer(_) | &Fraction(_, _) | &ExactString(_) &IntLiteral(_) | &FloatLiteral(_) | &ExactString(_)
| &EmptyRecordLiteral | &Underscore => () | &EmptyRecordLiteral | &Underscore => ()
} }
} }
@ -1042,7 +1039,7 @@ fn remove_idents(
remove_idents(loc_arg.value, idents); remove_idents(loc_arg.value, idents);
} }
}, },
Variant(_, None) | Integer(_) | Fraction(_, _) | ExactString(_) Variant(_, None) | IntLiteral(_) | FloatLiteral(_) | ExactString(_)
| EmptyRecordLiteral | Underscore => {} | EmptyRecordLiteral | Underscore => {}
} }
} }
@ -1234,16 +1231,16 @@ fn canonicalize_pattern(
} }
}, },
&Integer(ref num) => { &IntLiteral(ref num) => {
match pattern_type { match pattern_type {
CaseBranch => Pattern::Integer(*num), CaseBranch => Pattern::IntLiteral(*num),
ptype @ Assignment | ptype @ FunctionArg => unsupported_pattern(env, *ptype, &region, &loc_pattern.value) ptype @ Assignment | ptype @ FunctionArg => unsupported_pattern(env, *ptype, &region, &loc_pattern.value)
} }
}, },
&Fraction(ref numerator, ref denominator) => { &FloatLiteral(ref num) => {
match pattern_type { match pattern_type {
CaseBranch => Pattern::Fraction(*numerator, *denominator), CaseBranch => Pattern::FloatLiteral(*num),
ptype @ Assignment | ptype @ FunctionArg => unsupported_pattern(env, *ptype, &region, &loc_pattern.value) ptype @ Assignment | ptype @ FunctionArg => unsupported_pattern(env, *ptype, &region, &loc_pattern.value)
} }
}, },

View file

@ -28,9 +28,8 @@ pub fn constrain(
let region = loc_expr.region; let region = loc_expr.region;
match loc_expr.value { match loc_expr.value {
Int(_) => { Eq(num(subs.mk_flex_var()), expected, region) }, Int(_) => { int_literal(subs, expected, region) },
Frac(_, _) => { fractional(subs, expected, region) }, Float(_) => { float_literal(subs, expected, region) },
Approx(_) => { fractional(subs, expected, region) },
Str(_) => { Eq(string(), expected, region) }, Str(_) => { Eq(string(), expected, region) },
EmptyStr => { Eq(string(), expected, region) }, EmptyStr => { Eq(string(), expected, region) },
InterpolatedStr(pairs, _) => { InterpolatedStr(pairs, _) => {
@ -337,33 +336,43 @@ fn list(loc_elems: Vec<Located<Expr>>, bound_vars: &BoundTypeVars, subs: &mut Su
And(constraints) And(constraints)
} }
fn fractional(subs: &mut Subs, expected: Expected<Type>, region: Region) -> Constraint { #[inline(always)]
// We'll make a Num var1 and a Fractional var2, fn int_literal(subs: &mut Subs, expected: Expected<Type>, region: Region) -> Constraint {
// and then add a constraint that var1 needs to equal Fractional var2 let typ = number_literal_type("Int", "Integer");
let num_var = subs.mk_flex_var(); // Num var1 let reason = Reason::IntLiteral;
let fractional_var = subs.mk_flex_var(); // Fractional var2
let fractional_type = num_literal(typ, reason, subs, expected, region)
Type::Apply( }
"Num".to_string(),
"Fractional".to_string(), #[inline(always)]
vec![Type::Variable(fractional_var)] fn float_literal(subs: &mut Subs, expected: Expected<Type>, region: Region) -> Constraint {
); let typ = number_literal_type("Float", "FloatingPoint");
let num_var_type = Type::Variable(num_var); let reason = Reason::FloatLiteral;
let num_type =
Type::Apply( num_literal(typ, reason, subs, expected, region)
"Num".to_string(), }
"Num".to_string(),
vec![num_var_type.clone()]
); #[inline(always)]
let expected_fractional = fn num_literal(literal_type: Type, reason: Reason, subs: &mut Subs, expected: Expected<Type>, region: Region) -> Constraint {
ForReason(Reason::FractionalLiteral, fractional_type, region.clone()); let num_var = subs.mk_flex_var();
let num_type = Variable(num_var);
let expected_literal = ForReason(reason, literal_type, region.clone());
And(vec![ And(vec![
Eq(num_type, expected, region.clone()), Eq(num_type.clone(), expected_literal, region.clone()),
Eq(num_var_type, expected_fractional, region), Eq(num_type, expected, region.clone())
]) ])
} }
#[inline(always)]
fn number_literal_type(module_name: &str, type_name: &str) -> Type {
builtin_type("Num", "Num",
vec![builtin_type(module_name, type_name, Vec::new())]
)
}
#[inline(always)]
fn builtin_type(module_name: &str, type_name: &str, args: Vec<Type>) -> Type { fn builtin_type(module_name: &str, type_name: &str, args: Vec<Type>) -> Type {
Type::Apply(module_name.to_string(), type_name.to_string(), args) Type::Apply(module_name.to_string(), type_name.to_string(), args)
} }

View file

@ -6,8 +6,7 @@ use std::fmt;
pub enum Expr { pub enum Expr {
// Literals // Literals
Int(i64), Int(i64),
Frac(i64, i64), Float(f64),
Approx(f64),
EmptyStr, EmptyStr,
Str(String), Str(String),
Char(char), Char(char),
@ -99,8 +98,8 @@ impl fmt::Display for VariantName {
pub enum Pattern { pub enum Pattern {
Identifier(String), Identifier(String),
Variant(Located<VariantName>, Option<Vec<Located<Pattern>>>), Variant(Located<VariantName>, Option<Vec<Located<Pattern>>>),
Integer(i64), IntLiteral(i64),
Fraction(i64, i64), FloatLiteral(f64),
ExactString(String), ExactString(String),
EmptyRecordLiteral, EmptyRecordLiteral,
Underscore, Underscore,
@ -115,7 +114,7 @@ impl Expr {
let transformed = transform(self); let transformed = transform(self);
match transformed { match transformed {
Int(_) | Frac(_, _) | Approx(_) | EmptyStr | Str(_) | Char(_) | Var(_) | EmptyRecord | InterpolatedStr(_, _) | EmptyList => transformed, Int(_) | Float(_) | EmptyStr | Str(_) | Char(_) | Var(_) | EmptyRecord | InterpolatedStr(_, _) | EmptyList => transformed,
List(elems) => { List(elems) => {
let new_elems = let new_elems =
elems.into_iter() elems.into_iter()

View file

@ -199,9 +199,6 @@ parser! {
string_literal(), string_literal(),
int_or_frac_literal(), int_or_frac_literal(),
negative_int_or_frac_literal(), negative_int_or_frac_literal(),
char('~').with(
negative_approx_literal().or(approx_literal())
),
char_literal(), char_literal(),
if_expr(min_indent), if_expr(min_indent),
case_expr(min_indent), case_expr(min_indent),
@ -895,68 +892,6 @@ where I: Stream<Item = char, Position = IndentablePosition>,
) )
} }
pub fn negative_approx_literal<I>() -> impl Parser<Input = I, Output = Expr>
where I: Stream<Item = char, Position = IndentablePosition>,
I::Error: ParseError<I::Item, I::Range, I::Position>
{
char('-')
.with(digits_before_decimal())
.and(optional(char('.').with(digits_after_decimal())))
.then(|(int_digits, decimals): (Vec<char>, Option<Vec<char>>)| {
// TODO check length of digits and make sure not to overflow
let int_str: String = int_digits.into_iter().collect();
match decimals {
Some(nums) => {
let decimal_str: String = nums.into_iter().collect();
match format!("-{}.{}", int_str, decimal_str).parse::<f64>() {
Ok(float) => {
value(Expr::Approx(float)).right()
},
Err(_) => {
unexpected_any("looked like a negative number literal but was actually malformed identifier").left()
}
}
},
None => {
unexpected_any("negative number literal with ~ but without the decimal point that ~ number literals require").left()
}
}
})
}
pub fn approx_literal<I>() -> impl Parser<Input = I, Output = Expr>
where I: Stream<Item = char, Position = IndentablePosition>,
I::Error: ParseError<I::Item, I::Range, I::Position>
{
digits_before_decimal()
.and(optional(char('.').with(digits_after_decimal())))
.then(|(int_digits, decimals): (Vec<char>, Option<Vec<char>>)| {
// TODO check length of digits and make sure not to overflow
let int_str: String = int_digits.into_iter().collect();
match decimals {
Some(nums) => {
let decimal_str: String = nums.into_iter().collect();
match format!("{}.{}", int_str, decimal_str).parse::<f64>() {
Ok(float) => {
value(Expr::Approx(float)).right()
},
Err(_) => {
unexpected_any("looked like a negative number literal but was actually malformed identifier").left()
}
}
},
None => {
unexpected_any("negative number literal with ~ but without the decimal point that ~ number literals require").left()
}
}
})
}
pub fn negative_int_or_frac_literal<I>() -> impl Parser<Input = I, Output = Expr> pub fn negative_int_or_frac_literal<I>() -> impl Parser<Input = I, Output = Expr>
where I: Stream<Item = char, Position = IndentablePosition>, where I: Stream<Item = char, Position = IndentablePosition>,
I::Error: ParseError<I::Item, I::Range, I::Position> I::Error: ParseError<I::Item, I::Range, I::Position>
@ -978,21 +913,15 @@ where I: Stream<Item = char, Position = IndentablePosition>,
(Ok(int_val), None) => { (Ok(int_val), None) => {
value(Expr::Int(-int_val as i64)).right() value(Expr::Int(-int_val as i64)).right()
}, },
(Ok(int_val), Some(nums)) => { (Ok(_), Some(nums)) => {
let decimal_str: String = nums.into_iter().collect(); let decimal_str: String = nums.into_iter().collect();
// calculate numerator and denominator
// e.g. 123.45 == 12345 / 100
let denom = (10 as i64).pow(decimal_str.len() as u32);
match decimal_str.parse::<u32>() { match format!("{}.{}", int_str, decimal_str).parse::<f64>() {
Ok(decimal) => { Ok(float) => {
// Only the numerator may ever be signed! value(Expr::Float(-float)).right()
let numerator = (int_val * denom) + (decimal as i64);
value(Expr::Frac(-numerator, denom)).right()
}, },
Err(_) => { Err(_) => {
unexpected_any("non-digit characters after decimal point in a negative number literal").left() unexpected_any("looked like a negative Float literal but was actually malformed identifier").left()
} }
} }
}, },
@ -1020,16 +949,10 @@ where I: Stream<Item = char, Position = IndentablePosition>,
}, },
(Ok(int_val), Some(nums)) => { (Ok(int_val), Some(nums)) => {
let decimal_str: String = nums.into_iter().collect(); let decimal_str: String = nums.into_iter().collect();
// calculate numerator and denominator
// e.g. 123.45 == 12345 / 100
let denom = (10 as i64).pow(decimal_str.len() as u32);
match decimal_str.parse::<u32>() { match format!("{}.{}", int_str, decimal_str).parse::<f64>() {
Ok(decimal) => { Ok(float) => {
// Only the numerator may ever be signed! value(Expr::Float(float)).right()
let numerator = (int_val * denom) + (decimal as i64);
value(Expr::Frac(numerator, denom)).right()
}, },
Err(_) => { Err(_) => {
unexpected_any("non-digit characters after decimal point in a number literal").left() unexpected_any("non-digit characters after decimal point in a number literal").left()
@ -1087,27 +1010,17 @@ where I: Stream<Item = char, Position = IndentablePosition>,
match ( int_str.parse::<i64>(), decimals ) { match ( int_str.parse::<i64>(), decimals ) {
(Ok(int_val), None) => { (Ok(int_val), None) => {
if is_positive { if is_positive {
value(Pattern::Integer(int_val as i64)).right() value(Pattern::IntLiteral(int_val as i64)).right()
} else { } else {
value(Pattern::Integer(-int_val as i64)).right() value(Pattern::IntLiteral(-int_val as i64)).right()
} }
}, },
(Ok(int_val), Some(nums)) => { (Ok(int_val), Some(nums)) => {
let decimal_str: String = nums.into_iter().collect(); let decimal_str: String = nums.into_iter().collect();
// calculate numerator and denominator
// e.g. 123.45 == 12345 / 100
let denom = (10 as i64).pow(decimal_str.len() as u32);
match decimal_str.parse::<u32>() { match format!("{}.{}", int_str, decimal_str).parse::<f64>() {
Ok(decimal) => { Ok(float) => {
// Only the numerator may ever be signed. value(Pattern::FloatLiteral(float)).right()
let numerator = (int_val * denom) + (decimal as i64);
if is_positive {
value(Pattern::Fraction(numerator, denom)).right()
} else {
value(Pattern::Fraction(-numerator, denom)).right()
}
}, },
Err(_) => { Err(_) => {
unexpected_any("non-digit characters after decimal point in a number literal").left() unexpected_any("non-digit characters after decimal point in a number literal").left()

View file

@ -22,7 +22,7 @@ use types::Type::{self, *};
type Env = ImMap<Symbol, Variable>; type Env = ImMap<Symbol, Variable>;
pub fn solve(env: &Env, subs: &mut Subs, constraint: Constraint) { pub fn solve(env: &Env, subs: &mut Subs, constraint: Constraint) {
println!("\nSolving:\n\n\t{:?}\n\n", constraint); // println!("\nSolving:\n\n\t{:?}\n\n", constraint);
match constraint { match constraint {
True => (), True => (),
Eq(typ, expected_type, region) => { Eq(typ, expected_type, region) => {

View file

@ -151,6 +151,6 @@ pub enum FlatType {
#[derive(PartialEq, Eq, Debug, Clone, Copy)] #[derive(PartialEq, Eq, Debug, Clone, Copy)]
pub enum Builtin { pub enum Builtin {
Str, Int, Frac, Approx, Str, Int, Float,
EmptyRecord, EmptyRecord,
} }

View file

@ -75,7 +75,8 @@ pub enum Reason {
NamedFnCall(String /* function name */, u8 /* arity */), NamedFnCall(String /* function name */, u8 /* arity */),
OperatorArg(Operator, ArgSide), OperatorArg(Operator, ArgSide),
OperatorRet(Operator), OperatorRet(Operator),
FractionalLiteral, FloatLiteral,
IntLiteral,
InterpolatedStringVar, InterpolatedStringVar,
ElemInList, ElemInList,
} }

View file

@ -33,7 +33,7 @@ pub fn unify(subs: &mut Subs, left: &Descriptor, right: &Descriptor) -> Descript
} }
}; };
println!("\nUnifying:\n\n\t{:?}\n\n\t{:?}\n\n\t-----\n\n\t{:?}\n\n", left.content, right.content, answer.content); // println!("\nUnifying:\n\n\t{:?}\n\n\t{:?}\n\n\t-----\n\n\t{:?}\n\n", left.content, right.content, answer.content);
answer answer
} }

View file

@ -38,7 +38,7 @@ pub fn zero_loc_expr(expr: Expr) -> Expr {
use roc::expr::Expr::*; use roc::expr::Expr::*;
match expr { match expr {
Int(_) | Frac(_, _) | Approx(_) | EmptyStr | Str(_) | Char(_) | Var(_) | EmptyRecord | EmptyList => expr, Int(_) | Float(_) | EmptyStr | Str(_) | Char(_) | Var(_) | EmptyRecord | EmptyList => expr,
InterpolatedStr(pairs, string) => InterpolatedStr(pairs.into_iter().map(|( prefix, ident )| ( prefix, zero_loc(ident))).collect(), string), InterpolatedStr(pairs, string) => InterpolatedStr(pairs.into_iter().map(|( prefix, ident )| ( prefix, zero_loc(ident))).collect(), string),
List(elems) => { List(elems) => {
let zeroed_elems = let zeroed_elems =
@ -78,7 +78,7 @@ pub fn zero_loc_pattern(loc_pattern: Located<Pattern>) -> Located<Pattern> {
let pattern = loc_pattern.value; let pattern = loc_pattern.value;
match pattern { match pattern {
Identifier(_) | Integer(_) | Fraction(_, _) | ExactString(_) | EmptyRecordLiteral | Underscore => loc(pattern), Identifier(_) | IntLiteral(_) | FloatLiteral(_) | ExactString(_) | EmptyRecordLiteral | Underscore => loc(pattern),
Variant(loc_name, None) => Variant(loc_name, None) =>
loc(Variant(loc(loc_name.value), None)), loc(Variant(loc(loc_name.value), None)),
Variant(loc_name, Some(opt_located_patterns)) => Variant(loc_name, Some(opt_located_patterns)) =>

View file

@ -74,12 +74,12 @@ mod test_infer {
#[test] #[test]
fn int_literal() { fn int_literal() {
infer_eq("5", "Num.Num *"); infer_eq("5", "Int");
} }
#[test] #[test]
fn fractional_literal() { fn fractional_literal() {
infer_eq("0.5", "Num.Num (Num.Fractional *)"); infer_eq("0.5", "Float");
} }
#[test] #[test]
@ -112,7 +112,7 @@ mod test_infer {
indoc!(r#" indoc!(r#"
[] []
"#), "#),
"List.List *" "List *"
); );
} }
@ -122,7 +122,7 @@ mod test_infer {
indoc!(r#" indoc!(r#"
[[]] [[]]
"#), "#),
"List.List (List.List *)" "List (List *)"
); );
} }
@ -132,7 +132,7 @@ mod test_infer {
indoc!(r#" indoc!(r#"
[[[]]] [[[]]]
"#), "#),
"List.List (List.List (List.List *))" "List (List (List *))"
); );
} }
@ -142,47 +142,47 @@ mod test_infer {
indoc!(r#" indoc!(r#"
[ [], [ [] ] ] [ [], [ [] ] ]
"#), "#),
"List.List (List.List (List.List *))" "List (List (List *))"
); );
} }
#[test] #[test]
fn list_of_one_num() { fn list_of_one_int() {
infer_eq( infer_eq(
indoc!(r#" indoc!(r#"
[42] [42]
"#), "#),
"List.List (Num.Num *)" "List Int"
); );
} }
#[test] #[test]
fn triple_nested_num_list() { fn triple_nested_int_list() {
infer_eq( infer_eq(
indoc!(r#" indoc!(r#"
[[[ 5 ]]] [[[ 5 ]]]
"#), "#),
"List.List (List.List (List.List (Num.Num *)))" "List (List (List Int))"
); );
} }
#[test] #[test]
fn list_of_nums() { fn list_of_ints() {
infer_eq( infer_eq(
indoc!(r#" indoc!(r#"
[ 1, 2, 3 ] [ 1, 2, 3 ]
"#), "#),
"List.List (Num.Num *)" "List Int"
); );
} }
#[test] #[test]
fn nested_list_of_nums() { fn nested_list_of_ints() {
infer_eq( infer_eq(
indoc!(r#" indoc!(r#"
[ [ 1 ], [ 2, 3 ] ] [ [ 1 ], [ 2, 3 ] ]
"#), "#),
"List.List (List.List (Num.Num *))" "List (List Int)"
); );
} }
@ -192,7 +192,7 @@ mod test_infer {
indoc!(r#" indoc!(r#"
[ "cowabunga" ] [ "cowabunga" ]
"#), "#),
"List.List String.String" "List String.String"
); );
} }
@ -202,7 +202,7 @@ mod test_infer {
indoc!(r#" indoc!(r#"
[[[ "foo" ]]] [[[ "foo" ]]]
"#), "#),
"List.List (List.List (List.List String.String))" "List (List (List String.String))"
); );
} }
@ -212,7 +212,7 @@ mod test_infer {
indoc!(r#" indoc!(r#"
[ "foo", "bar" ] [ "foo", "bar" ]
"#), "#),
"List.List String.String" "List String.String"
); );
} }
@ -239,7 +239,7 @@ mod test_infer {
indoc!(r#" indoc!(r#"
[ "foo", 5 ] [ "foo", 5 ]
"#), "#),
"List.List <type mismatch>" "List <type mismatch>"
); );
} }
@ -249,7 +249,7 @@ mod test_infer {
indoc!(r#" indoc!(r#"
[ [ "foo", 5 ] ] [ [ "foo", 5 ] ]
"#), "#),
"List.List (List.List <type mismatch>)" "List (List <type mismatch>)"
); );
} }
@ -259,7 +259,7 @@ mod test_infer {
indoc!(r#" indoc!(r#"
[ [ 1 ], [ [] ] ] [ [ 1 ], [ [] ] ]
"#), "#),
"List.List (List.List <type mismatch>)" "List (List <type mismatch>)"
); );
} }
@ -276,12 +276,12 @@ mod test_infer {
} }
#[test] #[test]
fn two_arg_return_num() { fn two_arg_return_int() {
infer_eq( infer_eq(
indoc!(r#" indoc!(r#"
\_ _ -> 42 \_ _ -> 42
"#), "#),
"*, * -> Num.Num *" "*, * -> Int"
); );
} }
@ -341,7 +341,7 @@ mod test_infer {
func func
"#), "#),
"*, * -> Num.Num *" "*, * -> Int"
); );
} }
@ -397,7 +397,7 @@ mod test_infer {
c c
"#), "#),
"Num.Num *" "Int"
); );
} }
@ -411,7 +411,7 @@ mod test_infer {
alwaysFive "stuff" alwaysFive "stuff"
"#), "#),
"Num.Num *" "Int"
); );
} }
@ -423,7 +423,7 @@ mod test_infer {
enlist 5 enlist 5
"#), "#),
"List.List (Num.Num *)" "List Int"
); );
} }
@ -474,7 +474,7 @@ mod test_infer {
indoc!(r#" indoc!(r#"
\l r -> l / r \l r -> l / r
"#), "#),
"Num.Num Float.FloatingPoint, Num.Num Float.FloatingPoint -> Num.Num Float.FloatingPoint" "Float, Float -> Float"
); );
} }
@ -484,7 +484,7 @@ mod test_infer {
indoc!(r#" indoc!(r#"
1 / 2 1 / 2
"#), "#),
"Num.Num Float.FloatingPoint" "Float"
); );
} }
@ -494,7 +494,7 @@ mod test_infer {
// indoc!(r#" // indoc!(r#"
// 1 + 2 // 1 + 2
// "#), // "#),
// "Num.Num *" // "Num *"
// ); // );
// } // }

View file

@ -295,18 +295,14 @@ mod test_parse {
// // NUMBER LITERALS // // NUMBER LITERALS
fn expect_parsed_approx<'a>(expected: f64, actual: &str) { fn expect_parsed_float<'a>(expected: f64, actual: &str) {
assert_eq!(Ok((Approx(expected), "".to_string())), parse_without_loc(actual)); assert_eq!(Ok((Float(expected), "".to_string())), parse_without_loc(actual));
} }
fn expect_parsed_int<'a>(expected: i64, actual: &str) { fn expect_parsed_int<'a>(expected: i64, actual: &str) {
assert_eq!(Ok((Int(expected), "".to_string())), parse_without_loc(actual)); assert_eq!(Ok((Int(expected), "".to_string())), parse_without_loc(actual));
} }
fn expect_parsed_ratio<'a>(expected_numerator: i64, expected_denominator: i64, actual: &str) {
assert_eq!(Ok((Frac(expected_numerator, expected_denominator), "".to_string())), parse_without_loc(actual));
}
#[test] #[test]
fn positive_int() { fn positive_int() {
expect_parsed_int(1234, "1234"); expect_parsed_int(1234, "1234");
@ -318,25 +314,15 @@ mod test_parse {
} }
#[test] #[test]
fn positive_approx() { fn positive_float() {
expect_parsed_approx(123.4, "~123.4"); expect_parsed_float(123.45, "123.45");
expect_parsed_float(42.00, "42.00");
} }
#[test] #[test]
fn negative_approx() { fn negative_float() {
expect_parsed_approx(-123.4, "~-123.4"); expect_parsed_float(-1234.567, "-1234.567");
} expect_parsed_float(-192.0, "-192.0");
#[test]
fn positive_frac() {
expect_parsed_ratio(12345, 100, "123.45");
expect_parsed_ratio(4200, 100, "42.00");
}
#[test]
fn negative_ratio() {
expect_parsed_ratio(-1234567, 1000, "-1234.567");
expect_parsed_ratio(-1920, 10, "-192.0");
} }
#[test] #[test]
@ -347,10 +333,10 @@ mod test_parse {
#[test] #[test]
fn fracs_with_spaces() { fn fracs_with_spaces() {
expect_parsed_ratio(-1234567, 1000, "-1_23_4.567"); expect_parsed_float(-1234.567, "-1_23_4.567");
expect_parsed_ratio(-1920, 10, "-19_2.0"); expect_parsed_float(-192.0, "-19_2.0");
expect_parsed_ratio(12345, 100, "1_2_3.45"); expect_parsed_float(123.45, "1_2_3.45");
expect_parsed_ratio(4200, 100, "4_2.00"); expect_parsed_float(42.00, "4_2.00");
} }
#[test] #[test]
@ -910,7 +896,7 @@ mod test_parse {
Case( Case(
loc_box(Int(1)), loc_box(Int(1)),
vec![ vec![
( loc(Integer(2)), loc(Int(3)) ), ( loc(IntLiteral(2)), loc(Int(3)) ),
] ]
), ),
"".to_string() "".to_string()
@ -958,8 +944,8 @@ mod test_parse {
Case( Case(
loc_box(Int(0)), loc_box(Int(0)),
vec![ vec![
( loc(Integer(2)), loc(call_by_name("foo", vec![loc(Int(9))])) ), ( loc(IntLiteral(2)), loc(call_by_name("foo", vec![loc(Int(9))])) ),
( loc(Integer(1)), loc(call_by_name("bar", vec![loc(Int(8))])) ), ( loc(IntLiteral(1)), loc(call_by_name("bar", vec![loc(Int(8))])) ),
] ]
), ),
"".to_string() "".to_string()