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 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
13
src/expr.rs
13
src/expr.rs
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
38
src/parse.rs
38
src/parse.rs
|
@ -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
|
||||||
|
|
|
@ -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>,
|
||||||
|
@ -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(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue