diff --git a/src/eval.rs b/src/eval.rs index bd17afe7a0..d9a4c84410 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -6,7 +6,7 @@ use expr::Pattern::*; use expr::Operator::*; use std::rc::Rc; use im_rc::hashmap::HashMap; -use im_rc::vector::Vector; +use self::Evaluated::*; pub fn eval(expr: Expr) -> Evaluated { scoped_eval(expr, &HashMap::new()) @@ -18,8 +18,7 @@ pub fn from_evaluated(Evaluated(expr): Evaluated) -> Expr { } /// Wrapper indicating the expression has been evaluated -#[derive(Clone)] -pub struct Evaluated(Expr); +pub enum Evaluated { Evaluated(Expr) } type Scope = HashMap>; @@ -35,7 +34,13 @@ pub fn scoped_eval(expr: Expr, vars: &Scope) -> Evaluated { // Resolve variable names Var(name) => match vars.get(&name) { - Some(resolved) => (**resolved).clone(), + Some(resolved) => { + let Evaluated(ref evaluated_expr) = **resolved; + + // TODO is there any way to avoid this clone? (Do we care, + // once this is a canonical expression with Rc instead of Box? + Evaluated(evaluated_expr.clone()) + }, None => problem(UnrecognizedVarName(name)) } @@ -68,7 +73,13 @@ pub fn scoped_eval(expr: Expr, vars: &Scope) -> Evaluated { Func(name, args) => { let func_expr = match vars.get(&name) { - Some(resolved) => (**resolved).clone(), + Some(resolved) => { + let Evaluated(ref evaluated_expr) = **resolved; + + // TODO is there any way to avoid this clone? (Do we care, + // once this is a canonical expression with Rc instead of Box? + Evaluated(evaluated_expr.clone()) + }, None => problem(UnrecognizedVarName(name)) }; @@ -104,7 +115,7 @@ pub fn scoped_eval(expr: Expr, vars: &Scope) -> Evaluated { } #[inline(always)] -fn eval_apply(expr: Evaluated, args: Vector, vars: &Scope) -> Evaluated { +fn eval_apply(expr: Evaluated, args: Vec, vars: &Scope) -> Evaluated { match expr { Evaluated(Closure(arg_patterns, body)) => { let evaluated_args = @@ -122,7 +133,7 @@ fn eval_apply(expr: Evaluated, args: Vector, vars: &Scope) -> Evaluated { } #[inline(always)] -fn eval_closure(args: Vector, arg_patterns: Vector, vars: &Scope) +fn eval_closure(args: Vec, arg_patterns: Vec, vars: &Scope) -> Result { if arg_patterns.len() == args.len() { @@ -213,11 +224,17 @@ fn eval_operator(Evaluated(left_expr): &Evaluated, op: Operator, Evaluated(right } #[inline(always)] -fn eval_match (condition: Evaluated, branches: Vector<(Pattern, Box)>, vars: &Scope) -> Evaluated { +fn eval_match (condition: Evaluated, branches: Vec<(Pattern, Box)>, vars: &Scope) -> Evaluated { + let Evaluated(ref evaluated_expr) = condition; + for (pattern, definition) in branches { let mut branch_vars = vars.clone(); - if pattern_match(condition.clone(), pattern, &mut branch_vars).is_ok() { + // TODO is there any way to avoid this clone? (Do we care, + // once this is a canonical expression with Rc instead of Box? + let cloned_expr = Evaluated(evaluated_expr.clone()); + + if pattern_match(cloned_expr, pattern, &mut branch_vars).is_ok() { return scoped_eval(*definition, &branch_vars); } } diff --git a/src/expr.rs b/src/expr.rs index 2a1b05a280..dc57c77761 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1,6 +1,5 @@ use std::fmt; use self::Expr::*; -use im_rc::vector::Vector; #[derive(Clone, Debug, PartialEq)] pub enum Expr { @@ -15,17 +14,17 @@ pub enum Expr { Let(Pattern, Box, Box), // Functions - Func(String, Vector), - Apply(Box, Vector), + Func(String, Vec), + Apply(Box, Vec), Operator(Box, Operator, Box), - Closure(Vector, Box), + Closure(Vec, Box), // Sum Types - ApplyVariant(String, Option>), + ApplyVariant(String, Option>), // Conditionals If(Box, Box, Box), - Match(Box, Vector<(Pattern, Box)>), + Match(Box, Vec<(Pattern, Box)>), // Error Error(Problem), @@ -89,7 +88,7 @@ pub enum Problem { #[derive(Clone, Debug, PartialEq)] pub enum Pattern { Identifier(String), - Variant(String, Option>), + Variant(String, Option>), Underscore } diff --git a/src/parse.rs b/src/parse.rs index f795ca076c..2b976d5bcf 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -1,8 +1,6 @@ use expr::Operator; use expr::{Expr, Pattern}; -use im_rc::vector::Vector; - use std::char; use parse_state::{IndentablePosition}; @@ -50,7 +48,7 @@ where I: Stream, fn whitespace() -> impl Parser where I: Stream, I::Error: ParseError { - many::, _>(choice((char(' '), char('\n')))).with(value(())) + many::, _>(choice((char(' '), char('\n')))).with(value(())) } fn whitespace1() -> impl Parser @@ -91,7 +89,7 @@ where I: Stream, .skip(skip_many(char('\n').skip(skip_many(char(' '))))) .skip( choice(( - many1::, _>(char(' ')).then(move |chars| { + many1::, _>(char(' ')).then(move |chars| { if chars.len() < min_indent as usize { unexpected("outdent").left() } else { @@ -208,7 +206,7 @@ where I: Stream, string("match").skip(indented_whitespaces1(min_indent)) .with(expr_body(min_indent)).skip(indented_whitespaces1(min_indent)) .and( - many::, _>( + many::, _>( string("when").skip(indented_whitespaces1(min_indent)) .with(pattern(min_indent)).skip(indented_whitespaces1(min_indent)) .skip(string("then")).skip(indented_whitespaces1(min_indent)) @@ -236,7 +234,7 @@ where I: Stream, // whitespace and one or more comma-separated expressions, // meaning this is function application! optional(attempt(function_application(min_indent))) - ).map(|(expr, opt_args): (Expr, Option>)| + ).map(|(expr, opt_args): (Expr, Option>)| match opt_args { None => expr, Some(args) => Expr::Apply(Box::new(expr), args) @@ -244,7 +242,7 @@ where I: Stream, ) } -pub fn function_application(min_indent: i32) -> impl Parser> +pub fn function_application(min_indent: i32) -> impl Parser> where I: Stream, I::Error: ParseError { @@ -322,9 +320,9 @@ where I: Stream, I::Error: ParseError { ident().and(optional(attempt(function_application(min_indent)))) - .map(|(name, opt_args): (String, Option>)| + .map(|(name, opt_args): (String, Option>)| // Use optional(sep_by1()) over sep_by() to avoid - // allocating a Vector in the common case where this is a var + // allocating a Vec in the common case where this is a var match opt_args { None => Expr::Var(name), Some(args) => Expr::Func(name, args) @@ -369,9 +367,9 @@ where I: Stream, { attempt(variant_name()) .and(optional(attempt(function_application(min_indent)))) - .map(|(name, opt_args): (String, Option>)| + .map(|(name, opt_args): (String, Option>)| // Use optional(sep_by1()) over sep_by() to avoid - // allocating a Vector in case the variant is empty + // allocating a Vec in case the variant is empty Expr::ApplyVariant(name, opt_args) ) } @@ -386,9 +384,9 @@ where I: Stream, pattern(min_indent), char(',').skip(indented_whitespaces(min_indent)) )))) - .map(|(name, opt_args): (String, Option>)| + .map(|(name, opt_args): (String, Option>)| // Use optional(sep_by1()) over sep_by() to avoid - // allocating a Vector in case the variant is empty + // allocating a Vec in case the variant is empty Pattern::Variant(name, opt_args) ) } @@ -401,7 +399,7 @@ where I: Stream, // combination of letters or numbers afterwards. // No underscores, dashes, or apostrophes. look_ahead(satisfy(|ch: char| ch.is_uppercase())) - .with(many1::, _>(alpha_num())) + .with(many1::, _>(alpha_num())) .map(|chars| chars.into_iter().collect()) } @@ -412,8 +410,8 @@ where I: Stream, // Identifiers must begin with a lowercase letter, but can have any // combination of letters or numbers afterwards. // No underscores, dashes, or apostrophes. - many1::, _>(alpha_num()) - .then(|chars: Vector| { + many1::, _>(alpha_num()) + .then(|chars: Vec| { let valid_start_char = chars[0].is_lowercase(); if valid_start_char { @@ -459,7 +457,7 @@ where // e.g. \u{00A0} or \u{101010} // They must be no more than 10FFFF let hex_code_pt = - count_min_max::, HexDigit>(1, 6, hex_digit()) + count_min_max::, HexDigit>(1, 6, hex_digit()) .then(|hex_digits| { let hex_str:String = hex_digits.into_iter().collect(); @@ -572,11 +570,11 @@ where I: Stream, // We expect these to be digits, but read any alphanumeric characters // because it could turn out they're malformed identifiers which // happen to begin with a number. We'll check for that at the end. - let digits_after_decimal = many1::, _>(alpha_num()); + let digits_after_decimal = many1::, _>(alpha_num()); // Digits before the decimal point can be space-separated // e.g. one million can be written as 1 000 000 - let digits_before_decimal = many1::, _>( + let digits_before_decimal = many1::, _>( alpha_num().skip(optional( attempt( char(' ').skip( @@ -597,7 +595,7 @@ where I: Stream, .and(look_ahead(digit())) .and(digits_before_decimal) .and(optional(char('.').with(digits_after_decimal))) - .then(|(((opt_minus, _), int_digits), decimals): (((Option, _), Vector), Option>)| { + .then(|(((opt_minus, _), int_digits), decimals): (((Option, _), Vec), Option>)| { let is_positive = opt_minus.is_none(); // TODO check length of digits and make sure not to overflow diff --git a/tests/test_parse.rs b/tests/test_parse.rs index 97f8901a36..ba39b24e5a 100644 --- a/tests/test_parse.rs +++ b/tests/test_parse.rs @@ -1,8 +1,6 @@ #[macro_use] extern crate pretty_assertions; extern crate combine; -#[macro_use] extern crate im_rc; - extern crate roc; #[cfg(test)] @@ -18,7 +16,6 @@ mod parse_tests { use combine::stream::{Stream}; use combine::easy; use combine::stream::state::{State}; - use im_rc::vector::Vector; fn standalone_expr() -> impl Parser where I: Stream, @@ -237,7 +234,7 @@ mod parse_tests { #[test] fn single_operator_with_var() { assert_eq!( - // It's important that this isn't mistaken for + // It's important that this isn't mistaken for // a declaration like (x = 1) parse_standalone("x == 1"), Ok((Operator( @@ -332,6 +329,14 @@ mod parse_tests { ); } + fn expect_parsed_capitalizedvar_error<'a>(actual_str: &'a str) { + assert!( + parse_standalone(actual_str).is_err(), + "Expected parsing error" + ); + } + + #[test] fn basic_var() { expect_parsed_var("x"); @@ -351,7 +356,7 @@ mod parse_tests { fn expect_parsed_apply<'a>(parse_str: &'a str, expr1: Expr, expr2: Expr) { assert_eq!( - Ok((Apply(Box::new(expr1), vector![expr2]), "")), + Ok((Apply(Box::new(expr1), vec![expr2]), "")), parse_standalone(parse_str) ); } @@ -373,14 +378,14 @@ mod parse_tests { expect_parsed_apply( "(x 5) y", - Func("x".to_string(), vector![Int(5)]), + Func("x".to_string(), vec![Int(5)]), Var("y".to_string()) ); expect_parsed_apply( "(x 5) (y 6)", - Func("x".to_string(), vector![Int(5)]), - Func("y".to_string(), vector![Int(6)]), + Func("x".to_string(), vec![Int(5)]), + Func("y".to_string(), vec![Int(6)]), ); expect_parsed_apply( @@ -402,7 +407,7 @@ mod parse_tests { // FUNC - fn expect_parsed_func<'a>(parse_str: &'a str, func_str: &'a str, args: Vector) { + fn expect_parsed_func<'a>(parse_str: &'a str, func_str: &'a str, args: Vec) { assert_eq!( Ok((Func(func_str.to_string(), args), "")), parse_standalone(parse_str) @@ -426,23 +431,23 @@ mod parse_tests { #[test] fn single_arg_func() { - expect_parsed_func("f 1", "f", vector![Int(1)]); - expect_parsed_func("foo bar", "foo", vector![Var("bar".to_string())]); - expect_parsed_func("foo \"hi\"", "foo", vector![Str("hi".to_string())]); + expect_parsed_func("f 1", "f", vec![Int(1)]); + expect_parsed_func("foo bar", "foo", vec![Var("bar".to_string())]); + expect_parsed_func("foo \"hi\"", "foo", vec![Str("hi".to_string())]); } #[test] fn multi_arg_func() { - expect_parsed_func("f 1, 23, 456", "f", vector![Int(1), Int(23), Int(456)]); - expect_parsed_func("foo bar, 'z'", "foo", vector![Var("bar".to_string()), Char('z')]); - expect_parsed_func("foo \"hi\", 1, blah", "foo", vector![Str("hi".to_string()), Int(1), Var("blah".to_string())]); + expect_parsed_func("f 1, 23, 456", "f", vec![Int(1), Int(23), Int(456)]); + expect_parsed_func("foo bar, 'z'", "foo", vec![Var("bar".to_string()), Char('z')]); + expect_parsed_func("foo \"hi\", 1, blah", "foo", vec![Str("hi".to_string()), Int(1), Var("blah".to_string())]); } #[test] fn multiline_func() { - expect_parsed_func("f\n 1", "f", vector![Int(1)]); - expect_parsed_func("foo bar,\n 'z'", "foo", vector![Var("bar".to_string()), Char('z')]); - expect_parsed_func("foo \"hi\",\n 1,\n blah", "foo", vector![Str("hi".to_string()), Int(1), Var("blah".to_string())]); + expect_parsed_func("f\n 1", "f", vec![Int(1)]); + expect_parsed_func("foo bar,\n 'z'", "foo", vec![Var("bar".to_string()), Char('z')]); + expect_parsed_func("foo \"hi\",\n 1,\n blah", "foo", vec![Str("hi".to_string()), Int(1), Var("blah".to_string())]); } #[test] @@ -454,7 +459,7 @@ mod parse_tests { Operator( Box::new( Func("f".to_string(), - vector![Int(5)], + vec![Int(5)], ) ), Plus, @@ -474,7 +479,7 @@ mod parse_tests { Operator( Box::new( Func("f".to_string(), - vector![Int(1), Int(2), Int(3)], + vec![Int(1), Int(2), Int(3)], ) ), Plus, @@ -500,9 +505,9 @@ mod parse_tests { expect_parsed_int(-2, "((-2))"); expect_parsed_str("a", "(\"a\")"); expect_parsed_str("abc", "((\"abc\"))"); - expect_parsed_func("(f 1)", "f", vector![Int(1)]); - expect_parsed_func("(foo bar)", "foo", vector![Var("bar".to_string())]); - expect_parsed_func("( foo \"hi\" )", "foo", vector![Str("hi".to_string())]); + expect_parsed_func("(f 1)", "f", vec![Int(1)]); + expect_parsed_func("(foo bar)", "foo", vec![Var("bar".to_string())]); + expect_parsed_func("( foo \"hi\" )", "foo", vec![Str("hi".to_string())]); } #[test] @@ -567,18 +572,18 @@ mod parse_tests { fn complex_expressions() { expect_parsed_apply( "(x 5) (y + (f 6))", - Func("x".to_string(), vector![Int(5)]), + Func("x".to_string(), vec![Int(5)]), Operator( Box::new(Var("y".to_string())), Plus, - Box::new(Func("f".to_string(), vector![Int(6)])), + Box::new(Func("f".to_string(), vec![Int(6)])), ) ); assert_eq!( parse_standalone("(x 5)"), Ok(( - Func("x".to_string(), vector![Int(5)]), + Func("x".to_string(), vec![Int(5)]), "") ) ); @@ -639,7 +644,7 @@ mod parse_tests { parse_standalone("(x 5) + 123"), Ok(( Operator( - Box::new(Func("x".to_string(), vector![Int(5)])), + Box::new(Func("x".to_string(), vec![Int(5)])), Plus, Box::new(Int(123)) ), @@ -651,7 +656,7 @@ mod parse_tests { parse_standalone("(x 5) + (2 * y)"), Ok(( Operator( - Box::new(Func("x".to_string(), vector![Int(5)])), + Box::new(Func("x".to_string(), vec![Int(5)])), Plus, Box::new( Operator(