mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 23:31:12 +00:00
Revert "Use immutable Vector in Expr"
This reverts commit 89eb88deace1eac2bebdf640ef00bdabf17fef6a.
This commit is contained in:
parent
69f5046568
commit
b034e8a486
4 changed files with 83 additions and 64 deletions
35
src/eval.rs
35
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<String, Rc<Evaluated>>;
|
||||
|
||||
|
@ -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<Expr>, vars: &Scope) -> Evaluated {
|
||||
fn eval_apply(expr: Evaluated, args: Vec<Expr>, vars: &Scope) -> Evaluated {
|
||||
match expr {
|
||||
Evaluated(Closure(arg_patterns, body)) => {
|
||||
let evaluated_args =
|
||||
|
@ -122,7 +133,7 @@ fn eval_apply(expr: Evaluated, args: Vector<Expr>, vars: &Scope) -> Evaluated {
|
|||
}
|
||||
|
||||
#[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>
|
||||
{
|
||||
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<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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
13
src/expr.rs
13
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<Expr>, Box<Expr>),
|
||||
|
||||
// Functions
|
||||
Func(String, Vector<Expr>),
|
||||
Apply(Box<Expr>, Vector<Expr>),
|
||||
Func(String, Vec<Expr>),
|
||||
Apply(Box<Expr>, Vec<Expr>),
|
||||
Operator(Box<Expr>, Operator, Box<Expr>),
|
||||
Closure(Vector<Pattern>, Box<Expr>),
|
||||
Closure(Vec<Pattern>, Box<Expr>),
|
||||
|
||||
// Sum Types
|
||||
ApplyVariant(String, Option<Vector<Expr>>),
|
||||
ApplyVariant(String, Option<Vec<Expr>>),
|
||||
|
||||
// Conditionals
|
||||
If(Box<Expr>, Box<Expr>, Box<Expr>),
|
||||
Match(Box<Expr>, Vector<(Pattern, Box<Expr>)>),
|
||||
Match(Box<Expr>, Vec<(Pattern, Box<Expr>)>),
|
||||
|
||||
// Error
|
||||
Error(Problem),
|
||||
|
@ -89,7 +88,7 @@ pub enum Problem {
|
|||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Pattern {
|
||||
Identifier(String),
|
||||
Variant(String, Option<Vector<Pattern>>),
|
||||
Variant(String, Option<Vec<Pattern>>),
|
||||
Underscore
|
||||
}
|
||||
|
||||
|
|
38
src/parse.rs
38
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<Item = char, Position = IndentablePosition>,
|
|||
fn whitespace<I>() -> impl Parser<Input = I, Output = ()>
|
||||
where I: Stream<Item = char, Position = IndentablePosition>,
|
||||
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 = ()>
|
||||
|
@ -91,7 +89,7 @@ where I: Stream<Item = char, Position = IndentablePosition>,
|
|||
.skip(skip_many(char('\n').skip(skip_many(char(' ')))))
|
||||
.skip(
|
||||
choice((
|
||||
many1::<Vector<_>, _>(char(' ')).then(move |chars| {
|
||||
many1::<Vec<_>, _>(char(' ')).then(move |chars| {
|
||||
if chars.len() < min_indent as usize {
|
||||
unexpected("outdent").left()
|
||||
} else {
|
||||
|
@ -208,7 +206,7 @@ where I: Stream<Item = char, Position = IndentablePosition>,
|
|||
string("match").skip(indented_whitespaces1(min_indent))
|
||||
.with(expr_body(min_indent)).skip(indented_whitespaces1(min_indent))
|
||||
.and(
|
||||
many::<Vector<_>, _>(
|
||||
many::<Vec<_>, _>(
|
||||
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<Item = char, Position = IndentablePosition>,
|
|||
// 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<Vector<Expr>>)|
|
||||
).map(|(expr, opt_args): (Expr, Option<Vec<Expr>>)|
|
||||
match opt_args {
|
||||
None => expr,
|
||||
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>,
|
||||
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>
|
||||
{
|
||||
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
|
||||
// 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<Item = char, Position = IndentablePosition>,
|
|||
{
|
||||
attempt(variant_name())
|
||||
.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
|
||||
// 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<Item = char, Position = IndentablePosition>,
|
|||
pattern(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
|
||||
// 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<Item = char, Position = IndentablePosition>,
|
|||
// combination of letters or numbers afterwards.
|
||||
// No underscores, dashes, or apostrophes.
|
||||
look_ahead(satisfy(|ch: char| ch.is_uppercase()))
|
||||
.with(many1::<Vector<_>, _>(alpha_num()))
|
||||
.with(many1::<Vec<_>, _>(alpha_num()))
|
||||
.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
|
||||
// combination of letters or numbers afterwards.
|
||||
// No underscores, dashes, or apostrophes.
|
||||
many1::<Vector<_>, _>(alpha_num())
|
||||
.then(|chars: Vector<char>| {
|
||||
many1::<Vec<_>, _>(alpha_num())
|
||||
.then(|chars: Vec<char>| {
|
||||
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::<Vector<char>, HexDigit<I>>(1, 6, hex_digit())
|
||||
count_min_max::<Vec<char>, HexDigit<I>>(1, 6, hex_digit())
|
||||
.then(|hex_digits| {
|
||||
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
|
||||
// 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::<Vector<_>, _>(alpha_num());
|
||||
let digits_after_decimal = many1::<Vec<_>, _>(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::<Vector<_>, _>(
|
||||
let digits_before_decimal = many1::<Vec<_>, _>(
|
||||
alpha_num().skip(optional(
|
||||
attempt(
|
||||
char(' ').skip(
|
||||
|
@ -597,7 +595,7 @@ where I: Stream<Item = char, Position = IndentablePosition>,
|
|||
.and(look_ahead(digit()))
|
||||
.and(digits_before_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();
|
||||
|
||||
// TODO check length of digits and make sure not to overflow
|
||||
|
|
|
@ -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<I>() -> impl Parser<Input = I, Output = Expr>
|
||||
where I: Stream<Item = char, Position = IndentablePosition>,
|
||||
|
@ -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<Expr>) {
|
||||
fn expect_parsed_func<'a>(parse_str: &'a str, func_str: &'a str, args: Vec<Expr>) {
|
||||
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(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue