Revert "Use immutable Vector in Expr"

This reverts commit 89eb88deace1eac2bebdf640ef00bdabf17fef6a.
This commit is contained in:
Richard Feldman 2019-05-29 17:25:04 -04:00
parent 69f5046568
commit b034e8a486
4 changed files with 83 additions and 64 deletions

View file

@ -6,7 +6,7 @@ use expr::Pattern::*;
use expr::Operator::*; use expr::Operator::*;
use std::rc::Rc; use std::rc::Rc;
use im_rc::hashmap::HashMap; use im_rc::hashmap::HashMap;
use im_rc::vector::Vector; use self::Evaluated::*;
pub fn eval(expr: Expr) -> Evaluated { pub fn eval(expr: Expr) -> Evaluated {
scoped_eval(expr, &HashMap::new()) scoped_eval(expr, &HashMap::new())
@ -18,8 +18,7 @@ pub fn from_evaluated(Evaluated(expr): Evaluated) -> Expr {
} }
/// Wrapper indicating the expression has been evaluated /// Wrapper indicating the expression has been evaluated
#[derive(Clone)] pub enum Evaluated { Evaluated(Expr) }
pub struct Evaluated(Expr);
type Scope = HashMap<String, Rc<Evaluated>>; type Scope = HashMap<String, Rc<Evaluated>>;
@ -35,7 +34,13 @@ pub fn scoped_eval(expr: Expr, vars: &Scope) -> Evaluated {
// Resolve variable names // Resolve variable names
Var(name) => match vars.get(&name) { 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)) None => problem(UnrecognizedVarName(name))
} }
@ -68,7 +73,13 @@ pub fn scoped_eval(expr: Expr, vars: &Scope) -> Evaluated {
Func(name, args) => { Func(name, args) => {
let func_expr = match vars.get(&name) { 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)) None => problem(UnrecognizedVarName(name))
}; };
@ -104,7 +115,7 @@ pub fn scoped_eval(expr: Expr, vars: &Scope) -> Evaluated {
} }
#[inline(always)] #[inline(always)]
fn eval_apply(expr: Evaluated, args: Vector<Expr>, vars: &Scope) -> Evaluated { fn eval_apply(expr: Evaluated, args: Vec<Expr>, vars: &Scope) -> Evaluated {
match expr { match expr {
Evaluated(Closure(arg_patterns, body)) => { Evaluated(Closure(arg_patterns, body)) => {
let evaluated_args = let evaluated_args =
@ -122,7 +133,7 @@ fn eval_apply(expr: Evaluated, args: Vector<Expr>, vars: &Scope) -> Evaluated {
} }
#[inline(always)] #[inline(always)]
fn eval_closure(args: Vector<Evaluated>, arg_patterns: Vector<Pattern>, vars: &Scope) fn eval_closure(args: Vec<Evaluated>, arg_patterns: Vec<Pattern>, vars: &Scope)
-> Result<Scope, expr::Problem> -> Result<Scope, expr::Problem>
{ {
if arg_patterns.len() == args.len() { if arg_patterns.len() == args.len() {
@ -213,11 +224,17 @@ fn eval_operator(Evaluated(left_expr): &Evaluated, op: Operator, Evaluated(right
} }
#[inline(always)] #[inline(always)]
fn eval_match (condition: Evaluated, branches: Vector<(Pattern, Box<Expr>)>, vars: &Scope) -> Evaluated { fn eval_match (condition: Evaluated, branches: Vec<(Pattern, Box<Expr>)>, vars: &Scope) -> Evaluated {
let Evaluated(ref evaluated_expr) = condition;
for (pattern, definition) in branches { for (pattern, definition) in branches {
let mut branch_vars = vars.clone(); 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); return scoped_eval(*definition, &branch_vars);
} }
} }

View file

@ -1,6 +1,5 @@
use std::fmt; use std::fmt;
use self::Expr::*; use self::Expr::*;
use im_rc::vector::Vector;
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Expr { pub enum Expr {
@ -15,17 +14,17 @@ pub enum Expr {
Let(Pattern, Box<Expr>, Box<Expr>), Let(Pattern, Box<Expr>, Box<Expr>),
// Functions // Functions
Func(String, Vector<Expr>), Func(String, Vec<Expr>),
Apply(Box<Expr>, Vector<Expr>), Apply(Box<Expr>, Vec<Expr>),
Operator(Box<Expr>, Operator, Box<Expr>), Operator(Box<Expr>, Operator, Box<Expr>),
Closure(Vector<Pattern>, Box<Expr>), Closure(Vec<Pattern>, Box<Expr>),
// Sum Types // Sum Types
ApplyVariant(String, Option<Vector<Expr>>), ApplyVariant(String, Option<Vec<Expr>>),
// Conditionals // Conditionals
If(Box<Expr>, Box<Expr>, Box<Expr>), If(Box<Expr>, Box<Expr>, Box<Expr>),
Match(Box<Expr>, Vector<(Pattern, Box<Expr>)>), Match(Box<Expr>, Vec<(Pattern, Box<Expr>)>),
// Error // Error
Error(Problem), Error(Problem),
@ -89,7 +88,7 @@ pub enum Problem {
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Pattern { pub enum Pattern {
Identifier(String), Identifier(String),
Variant(String, Option<Vector<Pattern>>), Variant(String, Option<Vec<Pattern>>),
Underscore Underscore
} }

View file

@ -1,8 +1,6 @@
use expr::Operator; use expr::Operator;
use expr::{Expr, Pattern}; use expr::{Expr, Pattern};
use im_rc::vector::Vector;
use std::char; use std::char;
use parse_state::{IndentablePosition}; use parse_state::{IndentablePosition};
@ -50,7 +48,7 @@ where I: Stream<Item = char, Position = IndentablePosition>,
fn whitespace<I>() -> impl Parser<Input = I, Output = ()> fn whitespace<I>() -> impl Parser<Input = I, Output = ()>
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> {
many::<Vector<_>, _>(choice((char(' '), char('\n')))).with(value(())) many::<Vec<_>, _>(choice((char(' '), char('\n')))).with(value(()))
} }
fn whitespace1<I>() -> impl Parser<Input = I, Output = ()> fn whitespace1<I>() -> impl Parser<Input = I, Output = ()>
@ -91,7 +89,7 @@ where I: Stream<Item = char, Position = IndentablePosition>,
.skip(skip_many(char('\n').skip(skip_many(char(' '))))) .skip(skip_many(char('\n').skip(skip_many(char(' ')))))
.skip( .skip(
choice(( choice((
many1::<Vector<_>, _>(char(' ')).then(move |chars| { many1::<Vec<_>, _>(char(' ')).then(move |chars| {
if chars.len() < min_indent as usize { if chars.len() < min_indent as usize {
unexpected("outdent").left() unexpected("outdent").left()
} else { } else {
@ -208,7 +206,7 @@ where I: Stream<Item = char, Position = IndentablePosition>,
string("match").skip(indented_whitespaces1(min_indent)) string("match").skip(indented_whitespaces1(min_indent))
.with(expr_body(min_indent)).skip(indented_whitespaces1(min_indent)) .with(expr_body(min_indent)).skip(indented_whitespaces1(min_indent))
.and( .and(
many::<Vector<_>, _>( many::<Vec<_>, _>(
string("when").skip(indented_whitespaces1(min_indent)) string("when").skip(indented_whitespaces1(min_indent))
.with(pattern(min_indent)).skip(indented_whitespaces1(min_indent)) .with(pattern(min_indent)).skip(indented_whitespaces1(min_indent))
.skip(string("then")).skip(indented_whitespaces1(min_indent)) .skip(string("then")).skip(indented_whitespaces1(min_indent))
@ -236,7 +234,7 @@ where I: Stream<Item = char, Position = IndentablePosition>,
// whitespace and one or more comma-separated expressions, // whitespace and one or more comma-separated expressions,
// meaning this is function application! // meaning this is function application!
optional(attempt(function_application(min_indent))) optional(attempt(function_application(min_indent)))
).map(|(expr, opt_args): (Expr, Option<Vector<Expr>>)| ).map(|(expr, opt_args): (Expr, Option<Vec<Expr>>)|
match opt_args { match opt_args {
None => expr, None => expr,
Some(args) => Expr::Apply(Box::new(expr), args) Some(args) => Expr::Apply(Box::new(expr), args)
@ -244,7 +242,7 @@ where I: Stream<Item = char, Position = IndentablePosition>,
) )
} }
pub fn function_application<I>(min_indent: i32) -> impl Parser<Input = I, Output = Vector<Expr>> pub fn function_application<I>(min_indent: i32) -> impl Parser<Input = I, Output = Vec<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>
{ {
@ -322,9 +320,9 @@ 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>
{ {
ident().and(optional(attempt(function_application(min_indent)))) ident().and(optional(attempt(function_application(min_indent))))
.map(|(name, opt_args): (String, Option<Vector<Expr>>)| .map(|(name, opt_args): (String, Option<Vec<Expr>>)|
// Use optional(sep_by1()) over sep_by() to avoid // 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 { match opt_args {
None => Expr::Var(name), None => Expr::Var(name),
Some(args) => Expr::Func(name, args) Some(args) => Expr::Func(name, args)
@ -369,9 +367,9 @@ where I: Stream<Item = char, Position = IndentablePosition>,
{ {
attempt(variant_name()) attempt(variant_name())
.and(optional(attempt(function_application(min_indent)))) .and(optional(attempt(function_application(min_indent))))
.map(|(name, opt_args): (String, Option<Vector<Expr>>)| .map(|(name, opt_args): (String, Option<Vec<Expr>>)|
// Use optional(sep_by1()) over sep_by() to avoid // 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) Expr::ApplyVariant(name, opt_args)
) )
} }
@ -386,9 +384,9 @@ where I: Stream<Item = char, Position = IndentablePosition>,
pattern(min_indent), pattern(min_indent),
char(',').skip(indented_whitespaces(min_indent)) char(',').skip(indented_whitespaces(min_indent))
)))) ))))
.map(|(name, opt_args): (String, Option<Vector<Pattern>>)| .map(|(name, opt_args): (String, Option<Vec<Pattern>>)|
// Use optional(sep_by1()) over sep_by() to avoid // 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) Pattern::Variant(name, opt_args)
) )
} }
@ -401,7 +399,7 @@ where I: Stream<Item = char, Position = IndentablePosition>,
// combination of letters or numbers afterwards. // combination of letters or numbers afterwards.
// No underscores, dashes, or apostrophes. // No underscores, dashes, or apostrophes.
look_ahead(satisfy(|ch: char| ch.is_uppercase())) look_ahead(satisfy(|ch: char| ch.is_uppercase()))
.with(many1::<Vector<_>, _>(alpha_num())) .with(many1::<Vec<_>, _>(alpha_num()))
.map(|chars| chars.into_iter().collect()) .map(|chars| chars.into_iter().collect())
} }
@ -412,8 +410,8 @@ where I: Stream<Item = char, Position = IndentablePosition>,
// Identifiers must begin with a lowercase letter, but can have any // Identifiers must begin with a lowercase letter, but can have any
// combination of letters or numbers afterwards. // combination of letters or numbers afterwards.
// No underscores, dashes, or apostrophes. // No underscores, dashes, or apostrophes.
many1::<Vector<_>, _>(alpha_num()) many1::<Vec<_>, _>(alpha_num())
.then(|chars: Vector<char>| { .then(|chars: Vec<char>| {
let valid_start_char = chars[0].is_lowercase(); let valid_start_char = chars[0].is_lowercase();
if valid_start_char { if valid_start_char {
@ -459,7 +457,7 @@ where
// e.g. \u{00A0} or \u{101010} // e.g. \u{00A0} or \u{101010}
// They must be no more than 10FFFF // They must be no more than 10FFFF
let hex_code_pt = let hex_code_pt =
count_min_max::<Vector<char>, HexDigit<I>>(1, 6, hex_digit()) count_min_max::<Vec<char>, HexDigit<I>>(1, 6, hex_digit())
.then(|hex_digits| { .then(|hex_digits| {
let hex_str:String = hex_digits.into_iter().collect(); let hex_str:String = hex_digits.into_iter().collect();
@ -572,11 +570,11 @@ where I: Stream<Item = char, Position = IndentablePosition>,
// We expect these to be digits, but read any alphanumeric characters // We expect these to be digits, but read any alphanumeric characters
// because it could turn out they're malformed identifiers which // because it could turn out they're malformed identifiers which
// happen to begin with a number. We'll check for that at the end. // happen to begin with a number. We'll check for that at the end.
let digits_after_decimal = many1::<Vector<_>, _>(alpha_num()); let digits_after_decimal = many1::<Vec<_>, _>(alpha_num());
// Digits before the decimal point can be space-separated // Digits before the decimal point can be space-separated
// e.g. one million can be written as 1 000 000 // e.g. one million can be written as 1 000 000
let digits_before_decimal = many1::<Vector<_>, _>( let digits_before_decimal = many1::<Vec<_>, _>(
alpha_num().skip(optional( alpha_num().skip(optional(
attempt( attempt(
char(' ').skip( char(' ').skip(
@ -597,7 +595,7 @@ where I: Stream<Item = char, Position = IndentablePosition>,
.and(look_ahead(digit())) .and(look_ahead(digit()))
.and(digits_before_decimal) .and(digits_before_decimal)
.and(optional(char('.').with(digits_after_decimal))) .and(optional(char('.').with(digits_after_decimal)))
.then(|(((opt_minus, _), int_digits), decimals): (((Option<char>, _), Vector<char>), Option<Vector<char>>)| { .then(|(((opt_minus, _), int_digits), decimals): (((Option<char>, _), Vec<char>), Option<Vec<char>>)| {
let is_positive = opt_minus.is_none(); let is_positive = opt_minus.is_none();
// TODO check length of digits and make sure not to overflow // TODO check length of digits and make sure not to overflow

View file

@ -1,8 +1,6 @@
#[macro_use] extern crate pretty_assertions; #[macro_use] extern crate pretty_assertions;
extern crate combine; extern crate combine;
#[macro_use] extern crate im_rc;
extern crate roc; extern crate roc;
#[cfg(test)] #[cfg(test)]
@ -18,7 +16,6 @@ mod parse_tests {
use combine::stream::{Stream}; use combine::stream::{Stream};
use combine::easy; use combine::easy;
use combine::stream::state::{State}; use combine::stream::state::{State};
use im_rc::vector::Vector;
fn standalone_expr<I>() -> impl Parser<Input = I, Output = Expr> fn standalone_expr<I>() -> impl Parser<Input = I, Output = Expr>
where I: Stream<Item = char, Position = IndentablePosition>, where I: Stream<Item = char, Position = IndentablePosition>,
@ -237,7 +234,7 @@ mod parse_tests {
#[test] #[test]
fn single_operator_with_var() { fn single_operator_with_var() {
assert_eq!( 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) // a declaration like (x = 1)
parse_standalone("x == 1"), parse_standalone("x == 1"),
Ok((Operator( 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] #[test]
fn basic_var() { fn basic_var() {
expect_parsed_var("x"); expect_parsed_var("x");
@ -351,7 +356,7 @@ mod parse_tests {
fn expect_parsed_apply<'a>(parse_str: &'a str, expr1: Expr, expr2: Expr) { fn expect_parsed_apply<'a>(parse_str: &'a str, expr1: Expr, expr2: Expr) {
assert_eq!( assert_eq!(
Ok((Apply(Box::new(expr1), vector![expr2]), "")), Ok((Apply(Box::new(expr1), vec![expr2]), "")),
parse_standalone(parse_str) parse_standalone(parse_str)
); );
} }
@ -373,14 +378,14 @@ mod parse_tests {
expect_parsed_apply( expect_parsed_apply(
"(x 5) y", "(x 5) y",
Func("x".to_string(), vector![Int(5)]), Func("x".to_string(), vec![Int(5)]),
Var("y".to_string()) Var("y".to_string())
); );
expect_parsed_apply( expect_parsed_apply(
"(x 5) (y 6)", "(x 5) (y 6)",
Func("x".to_string(), vector![Int(5)]), Func("x".to_string(), vec![Int(5)]),
Func("y".to_string(), vector![Int(6)]), Func("y".to_string(), vec![Int(6)]),
); );
expect_parsed_apply( expect_parsed_apply(
@ -402,7 +407,7 @@ mod parse_tests {
// FUNC // FUNC
fn expect_parsed_func<'a>(parse_str: &'a str, func_str: &'a str, args: Vector<Expr>) { fn expect_parsed_func<'a>(parse_str: &'a str, func_str: &'a str, args: Vec<Expr>) {
assert_eq!( assert_eq!(
Ok((Func(func_str.to_string(), args), "")), Ok((Func(func_str.to_string(), args), "")),
parse_standalone(parse_str) parse_standalone(parse_str)
@ -426,23 +431,23 @@ mod parse_tests {
#[test] #[test]
fn single_arg_func() { fn single_arg_func() {
expect_parsed_func("f 1", "f", vector![Int(1)]); expect_parsed_func("f 1", "f", vec![Int(1)]);
expect_parsed_func("foo bar", "foo", vector![Var("bar".to_string())]); expect_parsed_func("foo bar", "foo", vec![Var("bar".to_string())]);
expect_parsed_func("foo \"hi\"", "foo", vector![Str("hi".to_string())]); expect_parsed_func("foo \"hi\"", "foo", vec![Str("hi".to_string())]);
} }
#[test] #[test]
fn multi_arg_func() { fn multi_arg_func() {
expect_parsed_func("f 1, 23, 456", "f", vector![Int(1), Int(23), Int(456)]); expect_parsed_func("f 1, 23, 456", "f", vec![Int(1), Int(23), Int(456)]);
expect_parsed_func("foo bar, 'z'", "foo", vector![Var("bar".to_string()), Char('z')]); expect_parsed_func("foo bar, 'z'", "foo", vec![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("foo \"hi\", 1, blah", "foo", vec![Str("hi".to_string()), Int(1), Var("blah".to_string())]);
} }
#[test] #[test]
fn multiline_func() { fn multiline_func() {
expect_parsed_func("f\n 1", "f", vector![Int(1)]); expect_parsed_func("f\n 1", "f", vec![Int(1)]);
expect_parsed_func("foo bar,\n 'z'", "foo", vector![Var("bar".to_string()), Char('z')]); 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", vector![Str("hi".to_string()), Int(1), Var("blah".to_string())]); expect_parsed_func("foo \"hi\",\n 1,\n blah", "foo", vec![Str("hi".to_string()), Int(1), Var("blah".to_string())]);
} }
#[test] #[test]
@ -454,7 +459,7 @@ mod parse_tests {
Operator( Operator(
Box::new( Box::new(
Func("f".to_string(), Func("f".to_string(),
vector![Int(5)], vec![Int(5)],
) )
), ),
Plus, Plus,
@ -474,7 +479,7 @@ mod parse_tests {
Operator( Operator(
Box::new( Box::new(
Func("f".to_string(), Func("f".to_string(),
vector![Int(1), Int(2), Int(3)], vec![Int(1), Int(2), Int(3)],
) )
), ),
Plus, Plus,
@ -500,9 +505,9 @@ mod parse_tests {
expect_parsed_int(-2, "((-2))"); expect_parsed_int(-2, "((-2))");
expect_parsed_str("a", "(\"a\")"); expect_parsed_str("a", "(\"a\")");
expect_parsed_str("abc", "((\"abc\"))"); expect_parsed_str("abc", "((\"abc\"))");
expect_parsed_func("(f 1)", "f", vector![Int(1)]); expect_parsed_func("(f 1)", "f", vec![Int(1)]);
expect_parsed_func("(foo bar)", "foo", vector![Var("bar".to_string())]); expect_parsed_func("(foo bar)", "foo", vec![Var("bar".to_string())]);
expect_parsed_func("( foo \"hi\" )", "foo", vector![Str("hi".to_string())]); expect_parsed_func("( foo \"hi\" )", "foo", vec![Str("hi".to_string())]);
} }
#[test] #[test]
@ -567,18 +572,18 @@ mod parse_tests {
fn complex_expressions() { fn complex_expressions() {
expect_parsed_apply( expect_parsed_apply(
"(x 5) (y + (f 6))", "(x 5) (y + (f 6))",
Func("x".to_string(), vector![Int(5)]), Func("x".to_string(), vec![Int(5)]),
Operator( Operator(
Box::new(Var("y".to_string())), Box::new(Var("y".to_string())),
Plus, Plus,
Box::new(Func("f".to_string(), vector![Int(6)])), Box::new(Func("f".to_string(), vec![Int(6)])),
) )
); );
assert_eq!( assert_eq!(
parse_standalone("(x 5)"), parse_standalone("(x 5)"),
Ok(( 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"), parse_standalone("(x 5) + 123"),
Ok(( Ok((
Operator( Operator(
Box::new(Func("x".to_string(), vector![Int(5)])), Box::new(Func("x".to_string(), vec![Int(5)])),
Plus, Plus,
Box::new(Int(123)) Box::new(Int(123))
), ),
@ -651,7 +656,7 @@ mod parse_tests {
parse_standalone("(x 5) + (2 * y)"), parse_standalone("(x 5) + (2 * y)"),
Ok(( Ok((
Operator( Operator(
Box::new(Func("x".to_string(), vector![Int(5)])), Box::new(Func("x".to_string(), vec![Int(5)])),
Plus, Plus,
Box::new( Box::new(
Operator( Operator(