Merge pull request #628 from rtfeldman/fuzz

Fuzz
This commit is contained in:
Richard Feldman 2020-11-01 19:07:15 -05:00 committed by GitHub
commit be77d887db
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 505 additions and 119 deletions

View file

@ -1443,6 +1443,8 @@ fn to_pending_def<'a>(
SpaceBefore(sub_def, _) | SpaceAfter(sub_def, _) | Nested(sub_def) => {
to_pending_def(env, var_store, sub_def, scope, pattern_type)
}
NotYetImplemented(s) => todo!("{}", s),
}
}

View file

@ -47,6 +47,8 @@ pub fn desugar_def<'a>(arena: &'a Bump, def: &'a Def<'a>) -> Def<'a> {
Nested(alias @ Alias { .. }) => Nested(alias),
ann @ Annotation(_, _) => Nested(ann),
Nested(ann @ Annotation(_, _)) => Nested(ann),
Nested(NotYetImplemented(s)) => todo!("{}", s),
NotYetImplemented(s) => todo!("{}", s),
}
}

View file

@ -20,6 +20,7 @@ impl<'a> Formattable<'a> for Def<'a> {
spaces.iter().any(|s| is_comment(s)) || sub_def.is_multiline()
}
Nested(def) => def.is_multiline(),
NotYetImplemented(s) => todo!("{}", s),
}
}
@ -66,6 +67,7 @@ impl<'a> Formattable<'a> for Def<'a> {
fmt_spaces(buf, spaces.iter(), indent);
}
Nested(def) => def.format(buf, indent),
NotYetImplemented(s) => todo!("{}", s),
}
}
}

View file

@ -101,6 +101,8 @@ fn generate_module_doc<'a>(
} => (acc, None),
Body(_, _) | Nested(_) => (acc, None),
NotYetImplemented(s) => todo!("{}", s),
}
}

4
compiler/parse/fuzz/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
target
corpus
artifacts

182
compiler/parse/fuzz/Cargo.lock generated Normal file
View file

@ -0,0 +1,182 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "arbitrary"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db55d72333851e17d572bec876e390cd3b11eb1ef53ae821dd9f3b653d2b4569"
[[package]]
name = "bitmaps"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2"
dependencies = [
"typenum",
]
[[package]]
name = "bumpalo"
version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820"
[[package]]
name = "cc"
version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed67cbde08356238e75fc4656be4749481eeffb09e19f320a25237d5221c985d"
[[package]]
name = "encode_unicode"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]]
name = "im"
version = "14.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "696059c87b83c5a258817ecd67c3af915e3ed141891fc35a1e79908801cf0ce7"
dependencies = [
"bitmaps",
"rand_core 0.5.1",
"rand_xoshiro",
"sized-chunks",
"typenum",
"version_check",
]
[[package]]
name = "im-rc"
version = "14.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "303f7e6256d546e01979071417432425f15c1891fb309a5f2d724ee908fabd6e"
dependencies = [
"bitmaps",
"rand_core 0.5.1",
"rand_xoshiro",
"sized-chunks",
"typenum",
"version_check",
]
[[package]]
name = "inlinable_string"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb6ee2a7da03bfc3b66ca47c92c2e392fcc053ea040a85561749b026f7aad09a"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libfuzzer-sys"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee8c42ab62f43795ed77a965ed07994c5584cdc94fd0ebf14b22ac1524077acc"
dependencies = [
"arbitrary",
"cc",
]
[[package]]
name = "rand_core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]]
name = "rand_core"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
[[package]]
name = "rand_xoshiro"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9fcdd2e881d02f1d9390ae47ad8e5696a9e4be7b547a1da2afbc61973217004"
dependencies = [
"rand_core 0.5.1",
]
[[package]]
name = "roc_collections"
version = "0.1.0"
dependencies = [
"bumpalo",
"im",
"im-rc",
"wyhash",
]
[[package]]
name = "roc_module"
version = "0.1.0"
dependencies = [
"bumpalo",
"inlinable_string",
"lazy_static",
"roc_collections",
"roc_region",
]
[[package]]
name = "roc_parse"
version = "0.1.0"
dependencies = [
"bumpalo",
"encode_unicode",
"inlinable_string",
"roc_collections",
"roc_module",
"roc_region",
]
[[package]]
name = "roc_parse-fuzz"
version = "0.0.0"
dependencies = [
"bumpalo",
"libfuzzer-sys",
"roc_parse",
]
[[package]]
name = "roc_region"
version = "0.1.0"
[[package]]
name = "sized-chunks"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d59044ea371ad781ff976f7b06480b9f0180e834eda94114f2afb4afc12b7718"
dependencies = [
"bitmaps",
"typenum",
]
[[package]]
name = "typenum"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
[[package]]
name = "version_check"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
[[package]]
name = "wyhash"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "782a50f48ac4336916227cd199c61c7b42f38d0ad705421b49eb12c74c53ae00"
dependencies = [
"rand_core 0.4.2",
]

View file

@ -0,0 +1,39 @@
[package]
name = "roc_parse-fuzz"
version = "0.0.0"
authors = ["Automatically generated"]
publish = false
edition = "2018"
[package.metadata]
cargo-fuzz = true
[dependencies]
libfuzzer-sys = "0.3"
bumpalo = { version = "3.2", features = ["collections"] }
[dependencies.roc_parse]
path = ".."
# Prevent this from interfering with workspaces
[workspace]
members = ["."]
[[bin]]
name = "fuzz_expr"
path = "fuzz_targets/fuzz_expr.rs"
test = false
doc = false
[[bin]]
name = "fuzz_defs"
path = "fuzz_targets/fuzz_defs.rs"
test = false
doc = false
[[bin]]
name = "fuzz_header"
path = "fuzz_targets/fuzz_header.rs"
test = false
doc = false

View file

@ -0,0 +1,11 @@
To setup fuzzing you will need to install cargo-fuzz and run with rust nightly:
```
$ cargo install cargo-fuzz
$ cargo +nightly fuzz run -j<cores> <target> -- -dict=dict.txt
```
The different targets can be found by running `cargo fuzz list`.
When a bug is found, it will be reported with commands to run it again and look for a minimized version.
If you are going to file a bug, please minimize the input before filing the bug.

View file

@ -0,0 +1,36 @@
"if"
"then"
"else"
"when"
"as"
"is"
"expect"
"app"
"platform"
"provides"
"requires"
"exposes"
"imports"
"effects"
"interface"
"|>"
"=="
"!="
"&&"
"||"
"+"
"*"
"-"
"//"
"/"
"<="
"<"
">="
">"
"^"
"%%"
"%"
"->"

View file

@ -0,0 +1,11 @@
#![no_main]
use bumpalo::Bump;
use libfuzzer_sys::fuzz_target;
use roc_parse::test_helpers::parse_defs_with;
fuzz_target!(|data: &[u8]| {
if let Ok(input) = std::str::from_utf8(data) {
let arena = Bump::new();
let _actual = parse_defs_with(&arena, input.trim());
}
});

View file

@ -0,0 +1,11 @@
#![no_main]
use bumpalo::Bump;
use libfuzzer_sys::fuzz_target;
use roc_parse::test_helpers::parse_expr_with;
fuzz_target!(|data: &[u8]| {
if let Ok(input) = std::str::from_utf8(data) {
let arena = Bump::new();
let _actual = parse_expr_with(&arena, input.trim());
}
});

View file

@ -0,0 +1,11 @@
#![no_main]
use bumpalo::Bump;
use libfuzzer_sys::fuzz_target;
use roc_parse::test_helpers::parse_header_with;
fuzz_target!(|data: &[u8]| {
if let Ok(input) = std::str::from_utf8(data) {
let arena = Bump::new();
let _actual = parse_header_with(&arena, input.trim());
}
});

View file

@ -277,6 +277,8 @@ pub enum Def<'a> {
/// This is used only to avoid cloning when reordering expressions (e.g. in desugar()).
/// It lets us take a (&Def) and create a plain (Def) from it.
Nested(&'a Def<'a>),
NotYetImplemented(&'static str),
}
#[derive(Debug, Clone, PartialEq)]

View file

@ -561,7 +561,7 @@ fn annotation_or_alias<'a>(
ann: loc_ann,
},
Apply(_, _) => {
panic!("TODO gracefully handle invalid Apply in type annotation");
Def::NotYetImplemented("TODO gracefully handle invalid Apply in type annotation")
}
SpaceAfter(value, spaces_before) => Def::SpaceAfter(
arena.alloc(annotation_or_alias(arena, value, region, loc_ann)),
@ -574,19 +574,19 @@ fn annotation_or_alias<'a>(
Nested(value) => annotation_or_alias(arena, value, region, loc_ann),
PrivateTag(_) => {
panic!("TODO gracefully handle trying to use a private tag as an annotation.");
Def::NotYetImplemented("TODO gracefully handle trying to use a private tag as an annotation.")
}
QualifiedIdentifier { .. } => {
panic!("TODO gracefully handle trying to annotate a qualified identifier, e.g. `Foo.bar : ...`");
Def::NotYetImplemented("TODO gracefully handle trying to annotate a qualified identifier, e.g. `Foo.bar : ...`")
}
NumLiteral(_) | NonBase10Literal { .. } | FloatLiteral(_) | StrLiteral(_) => {
panic!("TODO gracefully handle trying to annotate a litera");
Def::NotYetImplemented("TODO gracefully handle trying to annotate a litera")
}
Underscore => {
panic!("TODO gracefully handle trying to give a type annotation to an undrscore");
Def::NotYetImplemented("TODO gracefully handle trying to give a type annotation to an undrscore")
}
Malformed(_) => {
panic!("TODO translate a malformed pattern into a malformed annotation");
Def::NotYetImplemented("TODO translate a malformed pattern into a malformed annotation")
}
Identifier(ident) => {
// This is a regular Annotation
@ -633,7 +633,13 @@ fn parse_def_expr<'a>(
))
// `<` because '=' should be same indent (or greater) as the entire def-expr
} else if equals_sign_indent < def_start_col {
todo!("TODO the = in this declaration seems outdented. equals_sign_indent was {} and def_start_col was {}", equals_sign_indent, def_start_col);
Err((
Fail {
attempting: state.attempting,
reason: FailReason::NotYetImplemented(format!("TODO the = in this declaration seems outdented. equals_sign_indent was {} and def_start_col was {}", equals_sign_indent, def_start_col)),
},
state,
))
} else {
// Indented more beyond the original indent of the entire def-expr.
let indented_more = def_start_col + 1;
@ -720,7 +726,15 @@ fn parse_def_signature<'a>(
))
// `<` because ':' should be same indent or greater
} else if colon_indent < original_indent {
panic!("TODO the : in this declaration seems outdented");
Err((
Fail {
attempting: state.attempting,
reason: FailReason::NotYetImplemented(
"TODO the : in this declaration seems outdented".to_string(),
),
},
state,
))
} else {
// Indented more beyond the original indent.
let indented_more = original_indent + 1;
@ -1120,7 +1134,15 @@ mod when {
),
move |arena, state, (case_indent, loc_condition)| {
if case_indent < min_indent {
panic!("TODO case wasn't indented enough");
return Err((
Fail {
attempting: state.attempting,
reason: FailReason::NotYetImplemented(
"TODO case wasn't indented enough".to_string(),
),
},
state,
));
}
// Everything in the branches must be indented at least as much as the case itself.
@ -1178,9 +1200,15 @@ mod when {
if alternatives_indented_correctly(&loc_patterns, original_indent) {
Ok(((loc_patterns, loc_guard), state))
} else {
panic!(
"TODO additional branch didn't have same indentation as first branch"
);
Err((
Fail {
attempting: state.attempting,
reason: FailReason::NotYetImplemented(
"TODO additional branch didn't have same indentation as first branch".to_string(),
),
},
state,
))
}
},
),
@ -1490,10 +1518,16 @@ fn ident_etc<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
});
}
Err(malformed) => {
panic!(
"TODO early return malformed pattern {:?}",
malformed
);
return Err((
Fail {
attempting: state.attempting,
reason: FailReason::NotYetImplemented(format!(
"TODO early return malformed pattern {:?}",
malformed
)),
},
state,
));
}
}
}

View file

@ -24,4 +24,5 @@ pub mod number_literal;
pub mod pattern;
pub mod problems;
pub mod string_literal;
pub mod test_helpers;
pub mod type_annotation;

View file

@ -224,6 +224,7 @@ pub enum FailReason {
BadUtf8,
ReservedKeyword(Region),
ArgumentsBeforeEquals(Region),
NotYetImplemented(String),
}
#[derive(Debug, Clone, PartialEq, Eq)]

View file

@ -1,8 +1,8 @@
use crate::ast::{Attempting, EscapedChar, StrLiteral, StrSegment};
use crate::expr;
use crate::parser::{
allocated, ascii_char, ascii_hex_digits, loc, parse_utf8, unexpected, unexpected_eof,
ParseResult, Parser, State,
allocated, ascii_char, ascii_hex_digits, loc, parse_utf8, unexpected, unexpected_eof, Fail,
FailReason, ParseResult, Parser, State,
};
use bumpalo::collections::vec::Vec;
use bumpalo::Bump;
@ -279,7 +279,16 @@ where
// lines.push(line);
// Ok((StrLiteral::Block(lines.into_bump_slice()), state))
todo!("TODO parse this line in a block string: {:?}", line);
Err((
Fail {
attempting: state.attempting,
reason: FailReason::NotYetImplemented(format!(
"TODO parse this line in a block string: {:?}",
line
)),
},
state,
))
}
Err(reason) => state.fail(reason),
};

View file

@ -0,0 +1,45 @@
use crate::ast::{self, Attempting};
use crate::blankspace::space0_before;
use crate::expr::expr;
use crate::module::{header, module_defs};
use crate::parser::{loc, Fail, Parser, State};
use bumpalo::collections::Vec;
use bumpalo::Bump;
use roc_region::all::Located;
#[allow(dead_code)]
pub fn parse_expr_with<'a>(arena: &'a Bump, input: &'a str) -> Result<ast::Expr<'a>, Fail> {
parse_loc_with(arena, input).map(|loc_expr| loc_expr.value)
}
#[allow(dead_code)]
pub fn parse_header_with<'a>(arena: &'a Bump, input: &'a str) -> Result<ast::Module<'a>, Fail> {
let state = State::new(input.trim().as_bytes(), Attempting::Module);
let answer = header().parse(arena, state);
answer
.map(|(loc_expr, _)| loc_expr)
.map_err(|(fail, _)| fail)
}
#[allow(dead_code)]
pub fn parse_defs_with<'a>(
arena: &'a Bump,
input: &'a str,
) -> Result<Vec<'a, Located<ast::Def<'a>>>, Fail> {
let state = State::new(input.trim().as_bytes(), Attempting::Module);
let answer = module_defs().parse(arena, state);
answer
.map(|(loc_expr, _)| loc_expr)
.map_err(|(fail, _)| fail)
}
#[allow(dead_code)]
pub fn parse_loc_with<'a>(arena: &'a Bump, input: &'a str) -> Result<Located<ast::Expr<'a>>, Fail> {
let state = State::new(input.trim().as_bytes(), Attempting::Module);
let parser = space0_before(loc(expr(0)), 0);
let answer = parser.parse(&arena, state);
answer
.map(|(loc_expr, _)| loc_expr)
.map_err(|(fail, _)| fail)
}

View file

@ -4,8 +4,8 @@ use crate::expr::{global_tag, private_tag};
use crate::ident::join_module_parts;
use crate::keyword;
use crate::parser::{
allocated, ascii_char, ascii_string, not, optional, peek_utf8_char, unexpected, Either,
ParseResult, Parser, State,
allocated, ascii_char, ascii_string, not, optional, peek_utf8_char, unexpected, Either, Fail,
FailReason, ParseResult, Parser, State,
};
use bumpalo::collections::string::String;
use bumpalo::collections::vec::Vec;
@ -239,7 +239,13 @@ fn expression<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>
Ok((first, state))
} else {
// e.g. `Int,Int` without an arrow and return type
panic!("Invalid function signature")
Err((
Fail {
attempting: state.attempting,
reason: FailReason::NotYetImplemented("TODO: Decide the correct error to return for 'Invalid function signature'".to_string()),
},
state,
))
}
}
}

View file

@ -1,23 +0,0 @@
extern crate bumpalo;
use self::bumpalo::Bump;
use roc_parse::ast::{self, Attempting};
use roc_parse::blankspace::space0_before;
use roc_parse::parser::{loc, Fail, Parser, State};
use roc_region::all::Located;
#[allow(dead_code)]
pub fn parse_with<'a>(arena: &'a Bump, input: &'a str) -> Result<ast::Expr<'a>, Fail> {
parse_loc_with(arena, input).map(|loc_expr| loc_expr.value)
}
#[allow(dead_code)]
pub fn parse_loc_with<'a>(arena: &'a Bump, input: &'a str) -> Result<Located<ast::Expr<'a>>, Fail> {
let state = State::new(input.trim().as_bytes(), Attempting::Module);
let parser = space0_before(loc(roc_parse::expr::expr(0)), 0);
let answer = parser.parse(&arena, state);
answer
.map(|(loc_expr, _)| loc_expr)
.map_err(|(fail, _)| fail)
}

View file

@ -11,11 +11,8 @@ extern crate quickcheck_macros;
extern crate roc_module;
extern crate roc_parse;
mod helpers;
#[cfg(test)]
mod test_parse {
use crate::helpers::parse_with;
use bumpalo::collections::vec::Vec;
use bumpalo::{self, Bump};
use roc_module::operator::BinOp::*;
@ -33,19 +30,20 @@ mod test_parse {
use roc_parse::header::ModuleName;
use roc_parse::module::{interface_header, module_defs};
use roc_parse::parser::{Fail, FailReason, Parser, State};
use roc_parse::test_helpers::parse_expr_with;
use roc_region::all::{Located, Region};
use std::{f64, i64};
fn assert_parses_to<'a>(input: &'a str, expected_expr: Expr<'a>) {
let arena = Bump::new();
let actual = parse_with(&arena, input.trim());
let actual = parse_expr_with(&arena, input.trim());
assert_eq!(Ok(expected_expr), actual);
}
fn assert_parsing_fails<'a>(input: &'a str, reason: FailReason, attempting: Attempting) {
let arena = Bump::new();
let actual = parse_with(&arena, input);
let actual = parse_expr_with(&arena, input);
let expected_fail = Fail { reason, attempting };
assert_eq!(Err(expected_fail), actual);
@ -53,7 +51,7 @@ mod test_parse {
fn assert_segments<E: Fn(&Bump) -> Vec<'_, ast::StrSegment<'_>>>(input: &str, to_expected: E) {
let arena = Bump::new();
let actual = parse_with(&arena, arena.alloc(input));
let actual = parse_expr_with(&arena, arena.alloc(input));
let expected_slice = to_expected(&arena);
let expected_expr = Expr::Str(Line(&expected_slice));
@ -77,7 +75,7 @@ mod test_parse {
("\\t", EscapedChar::Tab),
("\\\"", EscapedChar::Quote),
] {
let actual = parse_with(&arena, arena.alloc(to_input(string)));
let actual = parse_expr_with(&arena, arena.alloc(to_input(string)));
let expected_slice = to_expected(*escaped, &arena);
let expected_expr = Expr::Str(Line(&expected_slice));
@ -423,7 +421,7 @@ mod test_parse {
fields: &[],
update: None,
};
let actual = parse_with(&arena, "{}");
let actual = parse_expr_with(&arena, "{}");
assert_eq!(Ok(expected), actual);
}
@ -455,7 +453,7 @@ mod test_parse {
fields,
};
let actual = parse_with(&arena, "{ Foo.Bar.baz & x: 5, y: 0 }");
let actual = parse_expr_with(&arena, "{ Foo.Bar.baz & x: 5, y: 0 }");
assert_eq!(Ok(expected), actual);
}
@ -470,7 +468,7 @@ mod test_parse {
Located::new(0, 0, 2, 3, Num("2")),
));
let expected = BinOp(tuple);
let actual = parse_with(&arena, "1+2");
let actual = parse_expr_with(&arena, "1+2");
assert_eq!(Ok(expected), actual);
}
@ -484,7 +482,7 @@ mod test_parse {
Located::new(0, 0, 2, 3, Num("2")),
));
let expected = BinOp(tuple);
let actual = parse_with(&arena, "1-2");
let actual = parse_expr_with(&arena, "1-2");
assert_eq!(Ok(expected), actual);
}
@ -498,7 +496,7 @@ mod test_parse {
Located::new(0, 0, 7, 8, Num("2")),
));
let expected = BinOp(tuple);
let actual = parse_with(&arena, "1 + 2");
let actual = parse_expr_with(&arena, "1 + 2");
assert_eq!(Ok(expected), actual);
}
@ -512,7 +510,7 @@ mod test_parse {
Located::new(0, 0, 7, 8, Num("2")),
));
let expected = BinOp(tuple);
let actual = parse_with(&arena, "1 - 2");
let actual = parse_expr_with(&arena, "1 - 2");
assert_eq!(Ok(expected), actual);
}
@ -535,7 +533,7 @@ mod test_parse {
Located::new(0, 0, 4, 5, Num("2")),
));
let expected = BinOp(tuple);
let actual = parse_with(&arena, "x + 2");
let actual = parse_expr_with(&arena, "x + 2");
assert_eq!(Ok(expected), actual);
}
@ -557,7 +555,7 @@ mod test_parse {
Located::new(0, 0, 4, 5, Num("2")),
));
let expected = BinOp(tuple);
let actual = parse_with(&arena, "x - 2");
let actual = parse_expr_with(&arena, "x - 2");
assert_eq!(Ok(expected), actual);
}
@ -572,7 +570,7 @@ mod test_parse {
Located::new(1, 1, 2, 3, Num("4")),
));
let expected = BinOp(tuple);
let actual = parse_with(&arena, "3 \n+ 4");
let actual = parse_expr_with(&arena, "3 \n+ 4");
assert_eq!(Ok(expected), actual);
}
@ -587,7 +585,7 @@ mod test_parse {
Located::new(1, 1, 2, 3, Num("4")),
));
let expected = BinOp(tuple);
let actual = parse_with(&arena, "3 \n- 4");
let actual = parse_expr_with(&arena, "3 \n- 4");
assert_eq!(Ok(expected), actual);
}
@ -602,7 +600,7 @@ mod test_parse {
Located::new(1, 1, 2, 3, spaced_int),
));
let expected = BinOp(tuple);
let actual = parse_with(&arena, "3 *\n 4");
let actual = parse_expr_with(&arena, "3 *\n 4");
assert_eq!(Ok(expected), actual);
}
@ -617,7 +615,7 @@ mod test_parse {
Located::new(1, 1, 2, 3, spaced_int),
));
let expected = BinOp(tuple);
let actual = parse_with(&arena, "3 -\n 4");
let actual = parse_expr_with(&arena, "3 -\n 4");
assert_eq!(Ok(expected), actual);
}
@ -632,7 +630,7 @@ mod test_parse {
Located::new(1, 1, 2, 3, Num("4")),
));
let expected = BinOp(tuple);
let actual = parse_with(&arena, "3 # 2 × 2\n+ 4");
let actual = parse_expr_with(&arena, "3 # 2 × 2\n+ 4");
assert_eq!(Ok(expected), actual);
}
@ -647,7 +645,7 @@ mod test_parse {
Located::new(1, 1, 2, 3, Num("4")),
));
let expected = BinOp(tuple);
let actual = parse_with(&arena, "3 # test!\n+ 4");
let actual = parse_expr_with(&arena, "3 # test!\n+ 4");
assert_eq!(Ok(expected), actual);
}
@ -662,7 +660,7 @@ mod test_parse {
Located::new(1, 1, 1, 3, spaced_int),
));
let expected = BinOp(tuple);
let actual = parse_with(&arena, "12 * # test!\n 92");
let actual = parse_expr_with(&arena, "12 * # test!\n 92");
assert_eq!(Ok(expected), actual);
}
@ -678,7 +676,7 @@ mod test_parse {
Located::new(3, 3, 2, 3, spaced_int2),
));
let expected = BinOp(tuple);
let actual = parse_with(&arena, "3 \n+ \n\n 4");
let actual = parse_expr_with(&arena, "3 \n+ \n\n 4");
assert_eq!(Ok(expected), actual);
}
@ -702,7 +700,7 @@ mod test_parse {
Located::new(0, 0, 3, 4, var2),
));
let expected = BinOp(tuple);
let actual = parse_with(&arena, "x- y");
let actual = parse_expr_with(&arena, "x- y");
assert_eq!(Ok(expected), actual);
}
@ -716,7 +714,7 @@ mod test_parse {
Located::new(0, 0, 4, 5, Num("5")),
));
let expected = BinOp(tuple);
let actual = parse_with(&arena, "-12-5");
let actual = parse_expr_with(&arena, "-12-5");
assert_eq!(Ok(expected), actual);
}
@ -730,7 +728,7 @@ mod test_parse {
Located::new(0, 0, 3, 5, Num("11")),
));
let expected = BinOp(tuple);
let actual = parse_with(&arena, "10*11");
let actual = parse_expr_with(&arena, "10*11");
assert_eq!(Ok(expected), actual);
}
@ -749,7 +747,7 @@ mod test_parse {
Located::new(0, 0, 3, 9, BinOp(inner)),
));
let expected = BinOp(outer);
let actual = parse_with(&arena, "31*42+534");
let actual = parse_expr_with(&arena, "31*42+534");
assert_eq!(Ok(expected), actual);
}
@ -771,7 +769,7 @@ mod test_parse {
Located::new(0, 0, 3, 4, var2),
));
let expected = BinOp(tuple);
let actual = parse_with(&arena, "x==y");
let actual = parse_expr_with(&arena, "x==y");
assert_eq!(Ok(expected), actual);
}
@ -793,7 +791,7 @@ mod test_parse {
Located::new(0, 0, 5, 6, var2),
));
let expected = BinOp(tuple);
let actual = parse_with(&arena, "x == y");
let actual = parse_expr_with(&arena, "x == y");
assert_eq!(Ok(expected), actual);
}
@ -807,7 +805,7 @@ mod test_parse {
module_name: "",
ident: "whee",
};
let actual = parse_with(&arena, "whee");
let actual = parse_expr_with(&arena, "whee");
assert_eq!(Ok(expected), actual);
}
@ -819,7 +817,7 @@ mod test_parse {
module_name: "",
ident: "whee",
}));
let actual = parse_with(&arena, "(whee)");
let actual = parse_expr_with(&arena, "(whee)");
assert_eq!(Ok(expected), actual);
}
@ -831,7 +829,7 @@ mod test_parse {
module_name: "One.Two",
ident: "whee",
};
let actual = parse_with(&arena, "One.Two.whee");
let actual = parse_expr_with(&arena, "One.Two.whee");
assert_eq!(Ok(expected), actual);
}
@ -842,7 +840,7 @@ mod test_parse {
fn basic_global_tag() {
let arena = Bump::new();
let expected = Expr::GlobalTag("Whee");
let actual = parse_with(&arena, "Whee");
let actual = parse_expr_with(&arena, "Whee");
assert_eq!(Ok(expected), actual);
}
@ -851,7 +849,7 @@ mod test_parse {
fn basic_private_tag() {
let arena = Bump::new();
let expected = Expr::PrivateTag("@Whee");
let actual = parse_with(&arena, "@Whee");
let actual = parse_expr_with(&arena, "@Whee");
assert_eq!(Ok(expected), actual);
}
@ -867,7 +865,7 @@ mod test_parse {
args,
CalledVia::Space,
);
let actual = parse_with(&arena, "@Whee 12 34");
let actual = parse_expr_with(&arena, "@Whee 12 34");
assert_eq!(Ok(expected), actual);
}
@ -883,7 +881,7 @@ mod test_parse {
args,
CalledVia::Space,
);
let actual = parse_with(&arena, "Whee 12 34");
let actual = parse_expr_with(&arena, "Whee 12 34");
assert_eq!(Ok(expected), actual);
}
@ -901,7 +899,7 @@ mod test_parse {
args,
CalledVia::Space,
);
let actual = parse_with(&arena, "Whee (12) (34)");
let actual = parse_expr_with(&arena, "Whee (12) (34)");
assert_eq!(Ok(expected), actual);
}
@ -910,7 +908,7 @@ mod test_parse {
fn qualified_global_tag() {
let arena = Bump::new();
let expected = Expr::MalformedIdent("One.Two.Whee");
let actual = parse_with(&arena, "One.Two.Whee");
let actual = parse_expr_with(&arena, "One.Two.Whee");
assert_eq!(Ok(expected), actual);
}
@ -920,7 +918,7 @@ mod test_parse {
// fn qualified_private_tag() {
// let arena = Bump::new();
// let expected = Expr::MalformedIdent("One.Two.@Whee");
// let actual = parse_with(&arena, "One.Two.@Whee");
// let actual = parse_expr_with(&arena, "One.Two.@Whee");
// assert_eq!(Ok(expected), actual);
// }
@ -931,7 +929,7 @@ mod test_parse {
let pattern = Located::new(0, 0, 1, 6, Pattern::GlobalTag("Thing"));
let patterns = &[pattern];
let expected = Closure(patterns, arena.alloc(Located::new(0, 0, 10, 12, Num("42"))));
let actual = parse_with(&arena, "\\Thing -> 42");
let actual = parse_expr_with(&arena, "\\Thing -> 42");
assert_eq!(Ok(expected), actual);
}
@ -940,7 +938,7 @@ mod test_parse {
fn private_qualified_tag() {
let arena = Bump::new();
let expected = Expr::MalformedIdent("@One.Two.Whee");
let actual = parse_with(&arena, "@One.Two.Whee");
let actual = parse_expr_with(&arena, "@One.Two.Whee");
assert_eq!(Ok(expected), actual);
}
@ -952,7 +950,7 @@ mod test_parse {
let arena = Bump::new();
let elems = &[];
let expected = List(elems);
let actual = parse_with(&arena, "[]");
let actual = parse_expr_with(&arena, "[]");
assert_eq!(Ok(expected), actual);
}
@ -963,7 +961,7 @@ mod test_parse {
let arena = Bump::new();
let elems = &[];
let expected = List(elems);
let actual = parse_with(&arena, "[ ]");
let actual = parse_expr_with(&arena, "[ ]");
assert_eq!(Ok(expected), actual);
}
@ -973,7 +971,7 @@ mod test_parse {
let arena = Bump::new();
let elems = &[&*arena.alloc(Located::new(0, 0, 1, 2, Num("1")))];
let expected = List(elems);
let actual = parse_with(&arena, "[1]");
let actual = parse_expr_with(&arena, "[1]");
assert_eq!(Ok(expected), actual);
}
@ -983,7 +981,7 @@ mod test_parse {
let arena = Bump::new();
let elems = &[&*arena.alloc(Located::new(0, 0, 2, 3, Num("1")))];
let expected = List(elems);
let actual = parse_with(&arena, "[ 1 ]");
let actual = parse_expr_with(&arena, "[ 1 ]");
assert_eq!(Ok(expected), actual);
}
@ -998,7 +996,7 @@ mod test_parse {
ident: "rec",
};
let expected = Access(arena.alloc(var), "field");
let actual = parse_with(&arena, "rec.field");
let actual = parse_expr_with(&arena, "rec.field");
assert_eq!(Ok(expected), actual);
}
@ -1011,7 +1009,7 @@ mod test_parse {
ident: "rec",
}));
let expected = Access(arena.alloc(paren_var), "field");
let actual = parse_with(&arena, "(rec).field");
let actual = parse_expr_with(&arena, "(rec).field");
assert_eq!(Ok(expected), actual);
}
@ -1024,7 +1022,7 @@ mod test_parse {
ident: "rec",
}));
let expected = Access(arena.alloc(paren_var), "field");
let actual = parse_with(&arena, "(One.Two.rec).field");
let actual = parse_expr_with(&arena, "(One.Two.rec).field");
assert_eq!(Ok(expected), actual);
}
@ -1040,7 +1038,7 @@ mod test_parse {
arena.alloc(Access(arena.alloc(Access(arena.alloc(var), "abc")), "def")),
"ghi",
);
let actual = parse_with(&arena, "rec.abc.def.ghi");
let actual = parse_expr_with(&arena, "rec.abc.def.ghi");
assert_eq!(Ok(expected), actual);
}
@ -1056,7 +1054,7 @@ mod test_parse {
arena.alloc(Access(arena.alloc(Access(arena.alloc(var), "abc")), "def")),
"ghi",
);
let actual = parse_with(&arena, "One.Two.rec.abc.def.ghi");
let actual = parse_expr_with(&arena, "One.Two.rec.abc.def.ghi");
assert_eq!(Ok(expected), actual);
}
@ -1077,7 +1075,7 @@ mod test_parse {
args,
CalledVia::Space,
);
let actual = parse_with(&arena, "whee 1");
let actual = parse_expr_with(&arena, "whee 1");
assert_eq!(Ok(expected), actual);
}
@ -1102,7 +1100,7 @@ mod test_parse {
args,
CalledVia::Space,
);
let actual = parse_with(&arena, "whee 12 34");
let actual = parse_expr_with(&arena, "whee 12 34");
assert_eq!(Ok(expected), actual);
}
@ -1155,7 +1153,7 @@ mod test_parse {
args,
CalledVia::Space,
);
let actual = parse_with(&arena, "a b c d");
let actual = parse_expr_with(&arena, "a b c d");
assert_eq!(Ok(expected), actual);
}
@ -1174,7 +1172,7 @@ mod test_parse {
args,
CalledVia::Space,
);
let actual = parse_with(&arena, "(whee) 1");
let actual = parse_expr_with(&arena, "(whee) 1");
assert_eq!(Ok(expected), actual);
}
@ -1191,7 +1189,7 @@ mod test_parse {
};
let loc_arg1_expr = Located::new(0, 0, 1, 4, arg1_expr);
let expected = UnaryOp(arena.alloc(loc_arg1_expr), loc_op);
let actual = parse_with(&arena, "-foo");
let actual = parse_expr_with(&arena, "-foo");
assert_eq!(Ok(expected), actual);
}
@ -1206,7 +1204,7 @@ mod test_parse {
};
let loc_arg1_expr = Located::new(0, 0, 1, 5, arg1_expr);
let expected = UnaryOp(arena.alloc(loc_arg1_expr), loc_op);
let actual = parse_with(&arena, "!blah");
let actual = parse_expr_with(&arena, "!blah");
assert_eq!(Ok(expected), actual);
}
@ -1242,7 +1240,7 @@ mod test_parse {
CalledVia::Space,
);
let expected = UnaryOp(arena.alloc(Located::new(0, 0, 1, 13, apply_expr)), loc_op);
let actual = parse_with(&arena, "-whee 12 foo");
let actual = parse_expr_with(&arena, "-whee 12 foo");
assert_eq!(Ok(expected), actual);
}
@ -1278,7 +1276,7 @@ mod test_parse {
CalledVia::Space,
);
let expected = UnaryOp(arena.alloc(Located::new(0, 0, 1, 13, apply_expr)), loc_op);
let actual = parse_with(&arena, "!whee 12 foo");
let actual = parse_expr_with(&arena, "!whee 12 foo");
assert_eq!(Ok(expected), actual);
}
@ -1314,7 +1312,7 @@ mod test_parse {
CalledVia::Space,
)));
let expected = UnaryOp(arena.alloc(Located::new(0, 0, 1, 15, apply_expr)), loc_op);
let actual = parse_with(&arena, "-(whee 12 foo)");
let actual = parse_expr_with(&arena, "-(whee 12 foo)");
assert_eq!(Ok(expected), actual);
}
@ -1350,7 +1348,7 @@ mod test_parse {
CalledVia::Space,
)));
let expected = UnaryOp(arena.alloc(Located::new(0, 0, 1, 15, apply_expr)), loc_op);
let actual = parse_with(&arena, "!(whee 12 foo)");
let actual = parse_expr_with(&arena, "!(whee 12 foo)");
assert_eq!(Ok(expected), actual);
}
@ -1377,7 +1375,7 @@ mod test_parse {
args,
CalledVia::Space,
);
let actual = parse_with(&arena, "whee 12 -foo");
let actual = parse_expr_with(&arena, "whee 12 -foo");
assert_eq!(Ok(expected), actual);
}
@ -1394,7 +1392,7 @@ mod test_parse {
let access = Access(arena.alloc(var), "field");
let loc_access = Located::new(0, 0, 1, 11, access);
let expected = UnaryOp(arena.alloc(loc_access), loc_op);
let actual = parse_with(&arena, "-rec1.field");
let actual = parse_expr_with(&arena, "-rec1.field");
assert_eq!(Ok(expected), actual);
}
@ -1407,7 +1405,7 @@ mod test_parse {
let pattern = Located::new(0, 0, 1, 2, Identifier("a"));
let patterns = &[pattern];
let expected = Closure(patterns, arena.alloc(Located::new(0, 0, 6, 8, Num("42"))));
let actual = parse_with(&arena, "\\a -> 42");
let actual = parse_expr_with(&arena, "\\a -> 42");
assert_eq!(Ok(expected), actual);
}
@ -1418,7 +1416,7 @@ mod test_parse {
let pattern = Located::new(0, 0, 1, 2, Underscore);
let patterns = &[pattern];
let expected = Closure(patterns, arena.alloc(Located::new(0, 0, 6, 8, Num("42"))));
let actual = parse_with(&arena, "\\_ -> 42");
let actual = parse_expr_with(&arena, "\\_ -> 42");
assert_eq!(Ok(expected), actual);
}
@ -1429,7 +1427,7 @@ mod test_parse {
// underscore in an argument name, it would parse as three arguments
// (and would ignore the underscore as if it had been blank space).
let arena = Bump::new();
let actual = parse_with(&arena, "\\the_answer -> 42");
let actual = parse_expr_with(&arena, "\\the_answer -> 42");
assert_eq!(Ok(MalformedClosure), actual);
}
@ -1441,7 +1439,7 @@ mod test_parse {
let arg2 = Located::new(0, 0, 4, 5, Identifier("b"));
let patterns = &[arg1, arg2];
let expected = Closure(patterns, arena.alloc(Located::new(0, 0, 9, 11, Num("42"))));
let actual = parse_with(&arena, "\\a, b -> 42");
let actual = parse_expr_with(&arena, "\\a, b -> 42");
assert_eq!(Ok(expected), actual);
}
@ -1457,7 +1455,7 @@ mod test_parse {
arena.alloc(patterns),
arena.alloc(Located::new(0, 0, 12, 14, Num("42"))),
);
let actual = parse_with(&arena, "\\a, b, c -> 42");
let actual = parse_expr_with(&arena, "\\a, b, c -> 42");
assert_eq!(Ok(expected), actual);
}
@ -1472,7 +1470,7 @@ mod test_parse {
arena.alloc(patterns),
arena.alloc(Located::new(0, 0, 9, 11, Num("42"))),
);
let actual = parse_with(&arena, "\\_, _ -> 42");
let actual = parse_expr_with(&arena, "\\_, _ -> 42");
assert_eq!(Ok(expected), actual);
}
@ -2040,7 +2038,7 @@ mod test_parse {
};
let loc_cond = Located::new(0, 0, 5, 6, var);
let expected = Expr::When(arena.alloc(loc_cond), branches);
let actual = parse_with(
let actual = parse_expr_with(
&arena,
indoc!(
r#"
@ -2084,7 +2082,7 @@ mod test_parse {
};
let loc_cond = Located::new(0, 0, 5, 6, var);
let expected = Expr::When(arena.alloc(loc_cond), branches);
let actual = parse_with(
let actual = parse_expr_with(
&arena,
indoc!(
r#"
@ -2133,7 +2131,7 @@ mod test_parse {
};
let loc_cond = Located::new(0, 0, 5, 6, var);
let expected = Expr::When(arena.alloc(loc_cond), branches);
let actual = parse_with(
let actual = parse_expr_with(
&arena,
indoc!(
r#"
@ -2183,7 +2181,7 @@ mod test_parse {
};
let loc_cond = Located::new(0, 0, 5, 6, var);
let expected = Expr::When(arena.alloc(loc_cond), branches);
let actual = parse_with(
let actual = parse_expr_with(
&arena,
indoc!(
r#"
@ -2490,7 +2488,7 @@ mod test_parse {
};
let loc_cond = Located::new(0, 0, 5, 6, var);
let expected = Expr::When(arena.alloc(loc_cond), branches);
let actual = parse_with(
let actual = parse_expr_with(
&arena,
indoc!(
r#"
@ -2535,7 +2533,7 @@ mod test_parse {
};
let loc_cond = Located::new(0, 0, 5, 6, var);
let expected = Expr::When(arena.alloc(loc_cond), branches);
let actual = parse_with(
let actual = parse_expr_with(
&arena,
indoc!(
r#"