mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 00:24:34 +00:00
Frac+Approx --> Float
This commit is contained in:
parent
695d1eb467
commit
04595a9e71
11 changed files with 112 additions and 207 deletions
|
@ -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, ®ion, &loc_pattern.value)
|
ptype @ Assignment | ptype @ FunctionArg => unsupported_pattern(env, *ptype, ®ion, &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, ®ion, &loc_pattern.value)
|
ptype @ Assignment | ptype @ FunctionArg => unsupported_pattern(env, *ptype, ®ion, &loc_pattern.value)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
|
113
src/parse.rs
113
src/parse.rs
|
@ -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()
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)) =>
|
||||||
|
|
|
@ -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 *"
|
||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue