mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-01 07:41:12 +00:00
Merge branch 'trunk' into fix/docs-tests
This commit is contained in:
commit
29f9364696
39 changed files with 1072 additions and 477 deletions
7
.github/workflows/ci.yml
vendored
7
.github/workflows/ci.yml
vendored
|
@ -56,6 +56,13 @@ jobs:
|
||||||
with:
|
with:
|
||||||
command: test
|
command: test
|
||||||
|
|
||||||
|
- uses: actions-rs/cargo@v1
|
||||||
|
name: cargo test -- --ignored
|
||||||
|
continue-on-error: true
|
||||||
|
with:
|
||||||
|
command: test
|
||||||
|
args: -- --ignored
|
||||||
|
|
||||||
- uses: actions-rs/cargo@v1
|
- uses: actions-rs/cargo@v1
|
||||||
name: cargo test --release
|
name: cargo test --release
|
||||||
with:
|
with:
|
||||||
|
|
|
@ -1,21 +1,37 @@
|
||||||
# Building the Roc compiler from source
|
# Building the Roc compiler from source
|
||||||
|
|
||||||
|
|
||||||
## Installing LLVM, valgrind, libunwind, and libc++-dev
|
## Installing LLVM, Zig, valgrind, libunwind, and libc++-dev
|
||||||
|
|
||||||
To build the compiler, you need these installed:
|
To build the compiler, you need these installed:
|
||||||
|
|
||||||
* `libunwind` (macOS should already have this one installed)
|
* `libunwind` (macOS should already have this one installed)
|
||||||
* `libc++-dev`
|
* `libc++-dev`
|
||||||
* a particular version of LLVM
|
* a particular version of Zig (see below)
|
||||||
|
* a particular version of LLVM (see below)
|
||||||
|
|
||||||
To run the test suite (via `cargo test`), you additionally need to install:
|
To run the test suite (via `cargo test`), you additionally need to install:
|
||||||
|
|
||||||
* [`valgrind`](https://www.valgrind.org/) (needs special treatment to [install on macOS](https://stackoverflow.com/a/61359781)]
|
* [`valgrind`](https://www.valgrind.org/) (needs special treatment to [install on macOS](https://stackoverflow.com/a/61359781)
|
||||||
|
Alternatively, you can use `cargo test --no-fail-fast` or `cargo test -p specific_tests` to skip over the valgrind failures & tests.
|
||||||
|
|
||||||
Some systems may already have `libc++-dev` on them, but if not, you may need to install it. (On Ubuntu, this can be done with `sudo apt-get install libc++-dev`.) macOS systems
|
### libunwind & libc++-dev
|
||||||
should already have `libunwind`, but other systems will need to install it
|
|
||||||
(e.g. with `sudo apt-get install libunwind-dev`).
|
MacOS systems should already have `libunwind`, but other systems will need to install it (On Ubuntu, this can be donw with `sudo apt-get install libunwind-dev`).
|
||||||
|
Some systems may already have `libc++-dev` on them, but if not, you may need to install it. (On Ubuntu, this can be done with `sudo apt-get install libc++-dev`.)
|
||||||
|
|
||||||
|
### Zig
|
||||||
|
We use a specific version of Zig, a build off the the commit `0088efc4b`. The latest tagged version of Zig, 0.6.0, doesn't include the feature to emit LLVM ir, which is a core feature of how we use Zig. To download this specific version, you can use the following links:
|
||||||
|
* [linux](https://ziglang.org/builds/zig-linux-x86_64-0.6.0+0088efc4b.tar.xz)
|
||||||
|
* [macOS](https://ziglang.org/builds/zig-macos-x86_64-0.6.0+0088efc4b.tar.xz)
|
||||||
|
|
||||||
|
Alternatively, any recent master branch build should work. To install the latest master branch build you can use:
|
||||||
|
* `brew install zig --HEAD` (on macos)
|
||||||
|
* `snap install zig --classic --edge` (on ubunutu)
|
||||||
|
|
||||||
|
Once 0.7.0 is released, we'll switch back to installing the tagged releases and this process will get easier.
|
||||||
|
|
||||||
|
### LLVM
|
||||||
|
|
||||||
To see which version of LLVM you need, take a look at `Cargo.toml`, in particular the `branch` section of the `inkwell` dependency. It should have something like `llvmX-Y` where X and Y are the major and minor revisions of LLVM you need.
|
To see which version of LLVM you need, take a look at `Cargo.toml`, in particular the `branch` section of the `inkwell` dependency. It should have something like `llvmX-Y` where X and Y are the major and minor revisions of LLVM you need.
|
||||||
|
|
||||||
|
|
23
Cargo.lock
generated
23
Cargo.lock
generated
|
@ -2320,6 +2320,7 @@ dependencies = [
|
||||||
"roc_uniq",
|
"roc_uniq",
|
||||||
"serde",
|
"serde",
|
||||||
"serde-xml-rs",
|
"serde-xml-rs",
|
||||||
|
"serial_test",
|
||||||
"strip-ansi-escapes",
|
"strip-ansi-escapes",
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
|
@ -2806,6 +2807,28 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serial_test"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b15f74add9a9d4a3eb2bf739c9a427d266d3895b53d992c3a7c234fec2ff1f1"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"parking_lot 0.10.2",
|
||||||
|
"serial_test_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serial_test_derive"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "65f59259be9fc1bf677d06cc1456e97756004a1a5a577480f71430bd7c17ba33"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 1.0.21",
|
||||||
|
"quote 1.0.7",
|
||||||
|
"syn 1.0.40",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha-1"
|
name = "sha-1"
|
||||||
version = "0.8.2"
|
version = "0.8.2"
|
||||||
|
|
|
@ -60,3 +60,8 @@ wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
|
||||||
add-apt-repository "${REPO_NAME}"
|
add-apt-repository "${REPO_NAME}"
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install -y clang-$LLVM_VERSION lldb-$LLVM_VERSION lld-$LLVM_VERSION clangd-$LLVM_VERSION libc++abi-dev libunwind-dev valgrind
|
apt-get install -y clang-$LLVM_VERSION lldb-$LLVM_VERSION lld-$LLVM_VERSION clangd-$LLVM_VERSION libc++abi-dev libunwind-dev valgrind
|
||||||
|
|
||||||
|
# install zig - can't use apt-get since we require at least a specific commit later then the most recent tag (0.6.0)
|
||||||
|
wget -c https://ziglang.org/builds/zig-linux-x86_64-0.6.0+0088efc4b.tar.xz --no-check-certificate
|
||||||
|
tar -xf zig-linux-x86_64-0.6.0+0088efc4b.tar.xz
|
||||||
|
ln -s "$PWD/zig-linux-x86_64-0.6.0+0088efc4b/zig" /usr/local/bin/zig
|
||||||
|
|
|
@ -89,4 +89,5 @@ quickcheck_macros = "0.8"
|
||||||
strip-ansi-escapes = "0.1"
|
strip-ansi-escapes = "0.1"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde-xml-rs = "0.4"
|
serde-xml-rs = "0.4"
|
||||||
|
serial_test = "0.5"
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
|
|
|
@ -79,9 +79,7 @@ fn jit_to_ast_help<'a>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Layout::Builtin(Builtin::EmptyList) => {
|
Layout::Builtin(Builtin::EmptyList) => {
|
||||||
run_jit_function!(lib, main_fn_name, &'static str, |_| {
|
run_jit_function!(lib, main_fn_name, &'static str, |_| { Expr::List(&[]) })
|
||||||
Expr::List(Vec::new_in(env.arena))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
Layout::Builtin(Builtin::List(_, elem_layout)) => run_jit_function!(
|
Layout::Builtin(Builtin::List(_, elem_layout)) => run_jit_function!(
|
||||||
lib,
|
lib,
|
||||||
|
@ -191,7 +189,7 @@ fn ptr_to_ast<'a>(
|
||||||
|
|
||||||
num_to_ast(env, f64_to_ast(env.arena, num), content)
|
num_to_ast(env, f64_to_ast(env.arena, num), content)
|
||||||
}
|
}
|
||||||
Layout::Builtin(Builtin::EmptyList) => Expr::List(Vec::new_in(env.arena)),
|
Layout::Builtin(Builtin::EmptyList) => Expr::List(&[]),
|
||||||
Layout::Builtin(Builtin::List(_, elem_layout)) => {
|
Layout::Builtin(Builtin::List(_, elem_layout)) => {
|
||||||
// Turn the (ptr, len) wrapper struct into actual ptr and len values.
|
// Turn the (ptr, len) wrapper struct into actual ptr and len values.
|
||||||
let len = unsafe { *(ptr.offset(env.ptr_bytes as isize) as *const usize) };
|
let len = unsafe { *(ptr.offset(env.ptr_bytes as isize) as *const usize) };
|
||||||
|
@ -263,6 +261,8 @@ fn list_to_ast<'a>(
|
||||||
output.push(loc_expr);
|
output.push(loc_expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let output = output.into_bump_slice();
|
||||||
|
|
||||||
Expr::List(output)
|
Expr::List(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,6 +314,8 @@ fn struct_to_ast<'a>(
|
||||||
field_ptr = unsafe { field_ptr.offset(field_layout.stack_size(env.ptr_bytes) as isize) };
|
field_ptr = unsafe { field_ptr.offset(field_layout.stack_size(env.ptr_bytes) as isize) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let output = output.into_bump_slice();
|
||||||
|
|
||||||
Expr::Record {
|
Expr::Record {
|
||||||
update: None,
|
update: None,
|
||||||
fields: output,
|
fields: output,
|
||||||
|
@ -362,7 +364,7 @@ fn num_to_ast<'a>(env: &Env<'a, '_>, num_expr: Expr<'a>, content: &Content) -> E
|
||||||
|
|
||||||
Expr::Record {
|
Expr::Record {
|
||||||
update: None,
|
update: None,
|
||||||
fields: bumpalo::vec![in arena; loc_assigned_field],
|
fields: arena.alloc([loc_assigned_field]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FlatType::TagUnion(tags, _) => {
|
FlatType::TagUnion(tags, _) => {
|
||||||
|
@ -404,7 +406,7 @@ fn num_to_ast<'a>(env: &Env<'a, '_>, num_expr: Expr<'a>, content: &Content) -> E
|
||||||
region: Region::zero(),
|
region: Region::zero(),
|
||||||
});
|
});
|
||||||
|
|
||||||
bumpalo::vec![in arena; loc_payload]
|
arena.alloc([loc_payload])
|
||||||
};
|
};
|
||||||
|
|
||||||
Expr::Apply(loc_tag_expr, payload, CalledVia::Space)
|
Expr::Apply(loc_tag_expr, payload, CalledVia::Space)
|
||||||
|
|
|
@ -12,123 +12,174 @@ mod helpers;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod cli_run {
|
mod cli_run {
|
||||||
use crate::helpers::{
|
use crate::helpers::{
|
||||||
example_file, extract_valgrind_errors, run_cmd, run_roc, run_with_valgrind, Out,
|
example_file, extract_valgrind_errors, run_cmd, run_roc, run_with_valgrind,
|
||||||
};
|
};
|
||||||
|
use serial_test::serial;
|
||||||
|
|
||||||
#[test]
|
fn check_output(
|
||||||
fn run_hello_world() {
|
folder: &str,
|
||||||
fn check_hello_world_output(out: Out) {
|
file: &str,
|
||||||
if !out.stderr.is_empty() {
|
flags: &[&str],
|
||||||
panic!(out.stderr);
|
expected_ending: &str,
|
||||||
}
|
use_valgrind: bool,
|
||||||
assert!(out.status.success());
|
) {
|
||||||
|
let compile_out = run_roc(
|
||||||
|
&[
|
||||||
|
&["build", example_file(folder, file).to_str().unwrap()],
|
||||||
|
flags,
|
||||||
|
]
|
||||||
|
.concat(),
|
||||||
|
);
|
||||||
|
if !compile_out.stderr.is_empty() {
|
||||||
|
panic!(compile_out.stderr);
|
||||||
|
}
|
||||||
|
assert!(compile_out.status.success());
|
||||||
|
|
||||||
|
let out = if use_valgrind {
|
||||||
let (valgrind_out, raw_xml) =
|
let (valgrind_out, raw_xml) =
|
||||||
run_with_valgrind(&[example_file("hello-world", "app").to_str().unwrap()]);
|
run_with_valgrind(&[example_file(folder, "app").to_str().unwrap()]);
|
||||||
|
|
||||||
let ending = "Hello, World!!!!!!!!!!!!!\n";
|
|
||||||
if !&valgrind_out.stdout.ends_with(ending) {
|
|
||||||
panic!(
|
|
||||||
"expected output to end with {:?} but instead got {:?}",
|
|
||||||
ending, &valgrind_out.stdout
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let memory_errors = extract_valgrind_errors(&raw_xml);
|
let memory_errors = extract_valgrind_errors(&raw_xml);
|
||||||
if !memory_errors.is_empty() {
|
if !memory_errors.is_empty() {
|
||||||
panic!("{:?}", memory_errors);
|
panic!("{:?}", memory_errors);
|
||||||
}
|
}
|
||||||
assert!(valgrind_out.status.success());
|
valgrind_out
|
||||||
|
} else {
|
||||||
|
run_cmd(example_file(folder, "app").to_str().unwrap(), &[])
|
||||||
|
};
|
||||||
|
if !&out.stdout.ends_with(expected_ending) {
|
||||||
|
panic!(
|
||||||
|
"expected output to end with {:?} but instead got {:#?}",
|
||||||
|
expected_ending, out
|
||||||
|
);
|
||||||
}
|
}
|
||||||
check_hello_world_output(run_roc(&[
|
assert!(out.status.success());
|
||||||
"build",
|
|
||||||
example_file("hello-world", "Hello.roc").to_str().unwrap(),
|
|
||||||
]));
|
|
||||||
check_hello_world_output(run_roc(&[
|
|
||||||
"build",
|
|
||||||
"--optimize",
|
|
||||||
example_file("hello-world", "Hello.roc").to_str().unwrap(),
|
|
||||||
]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[serial(hello_world)]
|
||||||
|
fn run_hello_world() {
|
||||||
|
check_output(
|
||||||
|
"hello-world",
|
||||||
|
"Hello.roc",
|
||||||
|
&[],
|
||||||
|
"Hello, World!!!!!!!!!!!!!\n",
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial(hello_world)]
|
||||||
|
fn run_hello_world_optimized() {
|
||||||
|
check_output(
|
||||||
|
"hello-world",
|
||||||
|
"Hello.roc",
|
||||||
|
&[],
|
||||||
|
"Hello, World!!!!!!!!!!!!!\n",
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial(quicksort)]
|
||||||
fn run_quicksort() {
|
fn run_quicksort() {
|
||||||
fn check_quicksort_output(out: Out) {
|
check_output(
|
||||||
if !out.stderr.is_empty() {
|
"quicksort",
|
||||||
panic!(out.stderr);
|
"Quicksort.roc",
|
||||||
}
|
&[],
|
||||||
assert!(out.status.success());
|
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
||||||
|
false,
|
||||||
// let (valgrind_out, raw_xml) =
|
);
|
||||||
// run_with_valgrind(&[example_file("quicksort", "app").to_str().unwrap()]);
|
|
||||||
let valgrind_out = run_cmd(example_file("quicksort", "app").to_str().unwrap(), &[]);
|
|
||||||
let ending = "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n";
|
|
||||||
if !&valgrind_out.stdout.ends_with(ending) {
|
|
||||||
panic!(
|
|
||||||
"expected output to end with {:?} but instead got {:?}",
|
|
||||||
ending, &valgrind_out.stdout
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// let memory_errors = extract_valgrind_errors(&raw_xml);
|
|
||||||
// if !memory_errors.is_empty() {
|
|
||||||
// panic!("{:?}", memory_errors);
|
|
||||||
// }
|
|
||||||
assert!(valgrind_out.status.success());
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Uncomment this once we are correctly freeing the RocList even when in dev build.
|
|
||||||
/*
|
|
||||||
check_quicksort_output(run_roc(&[
|
|
||||||
"build",
|
|
||||||
example_file("quicksort", "Quicksort.roc").to_str().unwrap(),
|
|
||||||
]));
|
|
||||||
*/
|
|
||||||
check_quicksort_output(run_roc(&[
|
|
||||||
"build",
|
|
||||||
"--optimize",
|
|
||||||
example_file("quicksort", "Quicksort.roc").to_str().unwrap(),
|
|
||||||
]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[serial(quicksort)]
|
||||||
|
fn run_quicksort_optimized() {
|
||||||
|
check_output(
|
||||||
|
"quicksort",
|
||||||
|
"Quicksort.roc",
|
||||||
|
&["--optimize"],
|
||||||
|
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial(quicksort)]
|
||||||
|
// TODO: Stop ignoring this test once we are correctly freeing the RocList even when in dev build.
|
||||||
|
#[ignore]
|
||||||
|
fn run_quicksort_valgrind() {
|
||||||
|
check_output(
|
||||||
|
"quicksort",
|
||||||
|
"Quicksort.roc",
|
||||||
|
&[],
|
||||||
|
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial(quicksort)]
|
||||||
|
// TODO: Stop ignoring this test once valgrind supports AVX512.
|
||||||
|
#[ignore]
|
||||||
|
fn run_quicksort_optimized_valgrind() {
|
||||||
|
check_output(
|
||||||
|
"quicksort",
|
||||||
|
"Quicksort.roc",
|
||||||
|
&["--optimize"],
|
||||||
|
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial(multi_module)]
|
||||||
fn run_multi_module() {
|
fn run_multi_module() {
|
||||||
fn check_muti_module_output(out: Out) {
|
check_output(
|
||||||
if !out.stderr.is_empty() {
|
"multi-module",
|
||||||
panic!(out.stderr);
|
"Quicksort.roc",
|
||||||
}
|
&[],
|
||||||
assert!(out.status.success());
|
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// let (valgrind_out, raw_xml) =
|
#[test]
|
||||||
// run_with_valgrind(&[example_file("multi-module", "app").to_str().unwrap()]);
|
#[serial(multi_module)]
|
||||||
let valgrind_out = run_cmd(example_file("multi-module", "app").to_str().unwrap(), &[]);
|
fn run_multi_module_optimized() {
|
||||||
let ending = "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n";
|
check_output(
|
||||||
if !&valgrind_out.stdout.ends_with(ending) {
|
"multi-module",
|
||||||
panic!(
|
"Quicksort.roc",
|
||||||
"expected output to end with {:?} but instead got {:?}",
|
&["--optimize"],
|
||||||
ending, &valgrind_out.stdout
|
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
||||||
);
|
false,
|
||||||
}
|
);
|
||||||
// let memory_errors = extract_valgrind_errors(&raw_xml);
|
}
|
||||||
// if !memory_errors.is_empty() {
|
|
||||||
// panic!("{:?}", memory_errors);
|
|
||||||
// }
|
|
||||||
assert!(valgrind_out.status.success());
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Uncomment this once we are correctly freeing the RocList even when in dev build.
|
#[test]
|
||||||
/*
|
#[serial(multi_module)]
|
||||||
check_muti_module_output(run_roc(&[
|
// TODO: Stop ignoring this test once we are correctly freeing the RocList even when in dev build.
|
||||||
"run",
|
#[ignore]
|
||||||
example_file("multi-module", "Quicksort.roc")
|
fn run_multi_module_valgrind() {
|
||||||
.to_str()
|
check_output(
|
||||||
.unwrap(),
|
"multi-module",
|
||||||
]));
|
"Quicksort.roc",
|
||||||
*/
|
&[],
|
||||||
check_muti_module_output(run_roc(&[
|
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
||||||
"run",
|
true,
|
||||||
example_file("multi-module", "Quicksort.roc")
|
);
|
||||||
.to_str()
|
}
|
||||||
.unwrap(),
|
|
||||||
"--optimize",
|
#[test]
|
||||||
]));
|
#[serial(multi_module)]
|
||||||
|
// TODO: Stop ignoring this test once valgrind supports AVX512.
|
||||||
|
#[ignore]
|
||||||
|
fn run_multi_module_optimized_valgrind() {
|
||||||
|
check_output(
|
||||||
|
"multi-module",
|
||||||
|
"Quicksort.roc",
|
||||||
|
&["--optimize"],
|
||||||
|
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
||||||
|
true,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ use std::path::PathBuf;
|
||||||
use std::process::{Command, ExitStatus, Stdio};
|
use std::process::{Command, ExitStatus, Stdio};
|
||||||
use tempfile::NamedTempFile;
|
use tempfile::NamedTempFile;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Out {
|
pub struct Out {
|
||||||
pub stdout: String,
|
pub stdout: String,
|
||||||
pub stderr: String,
|
pub stderr: String,
|
||||||
|
@ -131,6 +132,9 @@ enum ValgrindField {
|
||||||
Args(ValgrindDummyStruct),
|
Args(ValgrindDummyStruct),
|
||||||
Error(ValgrindError),
|
Error(ValgrindError),
|
||||||
Status(ValgrindDummyStruct),
|
Status(ValgrindDummyStruct),
|
||||||
|
Stack(ValgrindDummyStruct),
|
||||||
|
#[serde(rename = "fatal_signal")]
|
||||||
|
FatalSignal(ValgrindDummyStruct),
|
||||||
ErrorCounts(ValgrindDummyStruct),
|
ErrorCounts(ValgrindDummyStruct),
|
||||||
SuppCounts(ValgrindDummyStruct),
|
SuppCounts(ValgrindDummyStruct),
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ pub fn target_machine(
|
||||||
Target::from_name(arch).unwrap().create_target_machine(
|
Target::from_name(arch).unwrap().create_target_machine(
|
||||||
&TargetTriple::create(target_triple_str(target)),
|
&TargetTriple::create(target_triple_str(target)),
|
||||||
arch,
|
arch,
|
||||||
"+avx2", // TODO this string was used uncritically from an example, and should be reexamined
|
"", // TODO: this probably should be TargetMachine::get_host_cpu_features() to enable all features.
|
||||||
opt,
|
opt,
|
||||||
reloc,
|
reloc,
|
||||||
model,
|
model,
|
||||||
|
|
3
compiler/builtins/bitcode/.gitignore
vendored
3
compiler/builtins/bitcode/.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
lib.ll
|
zig-cache
|
||||||
|
src/zig-cache
|
||||||
|
|
|
@ -5,24 +5,19 @@ When their implementations are simple enough (e.g. addition), they
|
||||||
can be implemented directly in Inkwell.
|
can be implemented directly in Inkwell.
|
||||||
|
|
||||||
When their implementations are complex enough, it's nicer to
|
When their implementations are complex enough, it's nicer to
|
||||||
implement them in a higher-level language like C (or eventually Zig),
|
implement them in a higher-level language like Zig, then compile
|
||||||
compile the result to LLVM bitcode, and import that bitcode into the compiler.
|
the result to LLVM bitcode, and import that bitcode into the compiler.
|
||||||
|
|
||||||
Compiling the bitcode happens automatically in a Rust build script at `compiler/gen/build.rs`.
|
Compiling the bitcode happens automatically in a Rust build script at `compiler/builtins/build.rs`.
|
||||||
You can find the compiled bitcode in `target/debug/build/roc_gen-[some random characters]/out/builtins.bc`.
|
Then `builtins/src/bitcode/rs` staticlly imports the compiled bitcode for use in the compiler.
|
||||||
|
|
||||||
> If you want to take a look at the human-readable LLVM IR, cd into `compiler/builtins/bitcode` and
|
You can find the compiled bitcode in `target/debug/build/roc_builtins-[some random characters]/out/builtins.bc`.
|
||||||
> run the following command. It should create `compiler/builtins/bitcode/lib.ll`
|
There will be two directories like `roc_builtins-[some random characters]`, look for the one that has an
|
||||||
>
|
`out` directory as a child.
|
||||||
> ```bash
|
|
||||||
> clang -S -emit-llvm src/lib.c
|
|
||||||
> ```
|
|
||||||
|
|
||||||
The bitcode is a bunch of bytes that aren't particularly human-readable.
|
> The bitcode is a bunch of bytes that aren't particularly human-readable.
|
||||||
Since Roc is designed to be distributed as a single binary, these bytes
|
> If you want to take a look at the human-readable LLVM IR, look at
|
||||||
need to be included in the raw source somewhere.
|
> `target/debug/build/roc_builtins-[some random characters]/out/builtins.ll`
|
||||||
|
|
||||||
The `llvm/src/build.rs` file statically imports these raw bytes.
|
|
||||||
|
|
||||||
## Calling bitcode functions
|
## Calling bitcode functions
|
||||||
|
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
#include <math.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
// float -> f32
|
|
||||||
// double -> f64
|
|
||||||
// int -> i16
|
|
||||||
// long int -> i32
|
|
||||||
// long long -> i64
|
|
||||||
|
|
||||||
bool is_finite_(double num) { return isfinite(num); }
|
|
||||||
|
|
||||||
double atan_(double num) { return atan(num); }
|
|
||||||
|
|
||||||
long long pow_int_(long long base, long long exp) {
|
|
||||||
int acc = 1;
|
|
||||||
|
|
||||||
while (exp > 1) {
|
|
||||||
if ((exp & 1) == 1) {
|
|
||||||
acc *= base;
|
|
||||||
}
|
|
||||||
exp /= 2;
|
|
||||||
base *= base;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deal with the final bit of the exponent separately, since
|
|
||||||
// squaring the base afterwards is not necessary and may cause a
|
|
||||||
// needless overflow.
|
|
||||||
if (exp == 1) {
|
|
||||||
acc *= base;
|
|
||||||
}
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
}
|
|
374
compiler/builtins/bitcode/src/main.zig
Normal file
374
compiler/builtins/bitcode/src/main.zig
Normal file
|
@ -0,0 +1,374 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const math = std.math;
|
||||||
|
const expect = std.testing.expect;
|
||||||
|
|
||||||
|
const roc_builtins_namespace = "roc_builtins";
|
||||||
|
const math_namespace = roc_builtins_namespace ++ ".math";
|
||||||
|
const str_namespace = roc_builtins_namespace ++ ".str";
|
||||||
|
|
||||||
|
comptime { @export(atan, .{ .name = math_namespace ++ ".atan", .linkage = .Strong }); }
|
||||||
|
fn atan(num: f64) callconv(.C) f64 {
|
||||||
|
return math.atan(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
comptime { @export(isFinite, .{ .name = math_namespace ++ ".is_finite", .linkage = .Strong }); }
|
||||||
|
fn isFinite(num: f64) callconv(.C) bool {
|
||||||
|
return math.isFinite(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
comptime { @export(powInt, .{ .name = math_namespace ++ ".pow_int", .linkage = .Strong }); }
|
||||||
|
fn powInt(base: i64, exp: i64) callconv(.C) i64 {
|
||||||
|
return math.pow(i64, base, exp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Str.split
|
||||||
|
|
||||||
|
const RocStr = struct {
|
||||||
|
str_bytes_ptrs: [*]u8,
|
||||||
|
str_len: usize,
|
||||||
|
|
||||||
|
pub fn init(bytes: [*]u8, len: usize) RocStr {
|
||||||
|
return RocStr {
|
||||||
|
.str_bytes_ptrs = bytes,
|
||||||
|
.str_len = len
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eq(self: RocStr, other: RocStr) bool {
|
||||||
|
if (self.str_len != other.str_len) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var areEq: bool = true;
|
||||||
|
var index: usize = 0;
|
||||||
|
while (index < self.str_len and areEq) {
|
||||||
|
areEq = areEq and self.str_bytes_ptrs[index] == other.str_bytes_ptrs[index];
|
||||||
|
index = index + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return areEq;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "RocStr.eq: equal" {
|
||||||
|
const str1_len = 3;
|
||||||
|
var str1: [str1_len]u8 = "abc".*;
|
||||||
|
const str1_ptr: [*]u8 = &str1;
|
||||||
|
var roc_str1 = RocStr.init(str1_ptr, str1_len);
|
||||||
|
|
||||||
|
const str2_len = 3;
|
||||||
|
var str2: [str2_len]u8 = "abc".*;
|
||||||
|
const str2_ptr: [*]u8 = &str2;
|
||||||
|
var roc_str2 = RocStr.init(str2_ptr, str2_len);
|
||||||
|
|
||||||
|
expect(RocStr.eq(roc_str1, roc_str2));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "RocStr.eq: not equal different length" {
|
||||||
|
const str1_len = 4;
|
||||||
|
var str1: [str1_len]u8 = "abcd".*;
|
||||||
|
const str1_ptr: [*]u8 = &str1;
|
||||||
|
var roc_str1 = RocStr.init(str1_ptr, str1_len);
|
||||||
|
|
||||||
|
const str2_len = 3;
|
||||||
|
var str2: [str2_len]u8 = "abc".*;
|
||||||
|
const str2_ptr: [*]u8 = &str2;
|
||||||
|
var roc_str2 = RocStr.init(str2_ptr, str2_len);
|
||||||
|
|
||||||
|
expect(!RocStr.eq(roc_str1, roc_str2));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "RocStr.eq: not equal same length" {
|
||||||
|
const str1_len = 3;
|
||||||
|
var str1: [str1_len]u8 = "acb".*;
|
||||||
|
const str1_ptr: [*]u8 = &str1;
|
||||||
|
var roc_str1 = RocStr.init(str1_ptr, str1_len);
|
||||||
|
|
||||||
|
const str2_len = 3;
|
||||||
|
var str2: [str2_len]u8 = "abc".*;
|
||||||
|
const str2_ptr: [*]u8 = &str2;
|
||||||
|
var roc_str2 = RocStr.init(str2_ptr, str2_len);
|
||||||
|
|
||||||
|
expect(!RocStr.eq(roc_str1, roc_str2));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
comptime { @export(strSplitInPlace, .{ .name = str_namespace ++ ".str_split_in_place", .linkage = .Strong }); }
|
||||||
|
fn strSplitInPlace(
|
||||||
|
array: [*]RocStr,
|
||||||
|
array_len: usize,
|
||||||
|
str_bytes_ptrs: [*]u8,
|
||||||
|
str_len: usize,
|
||||||
|
delimiter_bytes: [*]u8,
|
||||||
|
delimiter_len: usize
|
||||||
|
) callconv(.C) void {
|
||||||
|
var ret_array_index : usize = 0;
|
||||||
|
|
||||||
|
var sliceStart_index : usize = 0;
|
||||||
|
|
||||||
|
var str_index : usize = 0;
|
||||||
|
|
||||||
|
if (str_len > delimiter_len) {
|
||||||
|
const end_index : usize = str_len - delimiter_len;
|
||||||
|
while (str_index <= end_index) {
|
||||||
|
var delimiter_index : usize = 0;
|
||||||
|
var matches_delimiter = true;
|
||||||
|
|
||||||
|
while (delimiter_index < delimiter_len) {
|
||||||
|
var delimiterChar = delimiter_bytes[delimiter_index];
|
||||||
|
var strChar = str_bytes_ptrs[str_index + delimiter_index];
|
||||||
|
|
||||||
|
if (delimiterChar != strChar) {
|
||||||
|
matches_delimiter = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
delimiter_index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matches_delimiter) {
|
||||||
|
array[ret_array_index] = RocStr.init(str_bytes_ptrs + sliceStart_index, str_index - sliceStart_index);
|
||||||
|
sliceStart_index = str_index + delimiter_len;
|
||||||
|
ret_array_index += 1;
|
||||||
|
str_index += delimiter_len;
|
||||||
|
} else {
|
||||||
|
str_index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
array[ret_array_index] = RocStr.init(str_bytes_ptrs + sliceStart_index, str_len - sliceStart_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "strSplitInPlace: no delimiter" {
|
||||||
|
// Str.split "abc" "!" == [ "abc" ]
|
||||||
|
|
||||||
|
var str: [3]u8 = "abc".*;
|
||||||
|
const str_ptr: [*]u8 = &str;
|
||||||
|
|
||||||
|
var delimiter: [1]u8 = "!".*;
|
||||||
|
const delimiter_ptr: [*]u8 = &delimiter;
|
||||||
|
|
||||||
|
var array: [1]RocStr = undefined;
|
||||||
|
const array_ptr: [*]RocStr = &array;
|
||||||
|
|
||||||
|
strSplitInPlace(
|
||||||
|
array_ptr,
|
||||||
|
1,
|
||||||
|
str_ptr,
|
||||||
|
3,
|
||||||
|
delimiter_ptr,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
var expected = [1]RocStr{
|
||||||
|
RocStr.init(str_ptr, 3),
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(array.len == expected.len);
|
||||||
|
expect(RocStr.eq(array[0], expected[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "strSplitInPlace: delimiter on sides" {
|
||||||
|
// Str.split "tttghittt" "ttt" == [ "", "ghi", "" ]
|
||||||
|
|
||||||
|
const str_len: usize = 9;
|
||||||
|
var str: [str_len]u8 = "tttghittt".*;
|
||||||
|
const str_ptr: [*]u8 = &str;
|
||||||
|
|
||||||
|
const delimiter_len = 3;
|
||||||
|
var delimiter: [delimiter_len]u8 = "ttt".*;
|
||||||
|
const delimiter_ptr: [*]u8 = &delimiter;
|
||||||
|
|
||||||
|
const array_len : usize = 3;
|
||||||
|
var array: [array_len]RocStr = [_]RocStr{
|
||||||
|
undefined ,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
};
|
||||||
|
const array_ptr: [*]RocStr = &array;
|
||||||
|
|
||||||
|
strSplitInPlace(
|
||||||
|
array_ptr,
|
||||||
|
array_len,
|
||||||
|
str_ptr,
|
||||||
|
str_len,
|
||||||
|
delimiter_ptr,
|
||||||
|
delimiter_len
|
||||||
|
);
|
||||||
|
|
||||||
|
const expected_str_len: usize = 3;
|
||||||
|
var expected_str: [expected_str_len]u8 = "ghi".*;
|
||||||
|
const expected_str_ptr: [*]u8 = &expected_str;
|
||||||
|
var expectedRocStr = RocStr.init(expected_str_ptr, expected_str_len);
|
||||||
|
|
||||||
|
expect(array.len == 3);
|
||||||
|
expect(array[0].str_len == 0);
|
||||||
|
expect(RocStr.eq(array[1], expectedRocStr));
|
||||||
|
expect(array[2].str_len == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "strSplitInPlace: three pieces" {
|
||||||
|
// Str.split "a!b!c" "!" == [ "a", "b", "c" ]
|
||||||
|
|
||||||
|
const str_len: usize = 5;
|
||||||
|
var str: [str_len]u8 = "a!b!c".*;
|
||||||
|
const str_ptr: [*]u8 = &str;
|
||||||
|
|
||||||
|
const delimiter_len = 1;
|
||||||
|
var delimiter: [delimiter_len]u8 = "!".*;
|
||||||
|
const delimiter_ptr: [*]u8 = &delimiter;
|
||||||
|
|
||||||
|
const array_len : usize = 3;
|
||||||
|
var array: [array_len]RocStr = undefined;
|
||||||
|
const array_ptr: [*]RocStr = &array;
|
||||||
|
|
||||||
|
strSplitInPlace(
|
||||||
|
array_ptr,
|
||||||
|
array_len,
|
||||||
|
str_ptr,
|
||||||
|
str_len,
|
||||||
|
delimiter_ptr,
|
||||||
|
delimiter_len
|
||||||
|
);
|
||||||
|
|
||||||
|
var a: [1]u8 = "a".*;
|
||||||
|
const a_ptr: [*]u8 = &a;
|
||||||
|
|
||||||
|
var b: [1]u8 = "b".*;
|
||||||
|
const b_ptr: [*]u8 = &b;
|
||||||
|
|
||||||
|
var c: [1]u8 = "c".*;
|
||||||
|
const c_ptr: [*]u8 = &c;
|
||||||
|
|
||||||
|
var expected_array = [array_len]RocStr{
|
||||||
|
RocStr{
|
||||||
|
.str_bytes_ptrs = a_ptr,
|
||||||
|
.str_len = 1,
|
||||||
|
},
|
||||||
|
RocStr{
|
||||||
|
.str_bytes_ptrs = b_ptr,
|
||||||
|
.str_len = 1,
|
||||||
|
},
|
||||||
|
RocStr{
|
||||||
|
.str_bytes_ptrs = c_ptr,
|
||||||
|
.str_len = 1,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(expected_array.len == array.len);
|
||||||
|
expect(RocStr.eq(array[0], expected_array[0]));
|
||||||
|
expect(RocStr.eq(array[1], expected_array[1]));
|
||||||
|
expect(RocStr.eq(array[2], expected_array[2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is used for `Str.split : Str, Str -> Array Str
|
||||||
|
// It is used to count how many segments the input `_str`
|
||||||
|
// needs to be broken into, so that we can allocate a array
|
||||||
|
// of that size. It always returns at least 1.
|
||||||
|
comptime { @export(countSegments, .{ .name = str_namespace ++ ".count_segements", .linkage = .Strong }); }
|
||||||
|
fn countSegments(
|
||||||
|
str_bytes_ptrs: [*]u8,
|
||||||
|
str_len: usize,
|
||||||
|
delimiter_bytes: [*]u8,
|
||||||
|
delimiter_len: usize
|
||||||
|
) callconv(.C) i64 {
|
||||||
|
var count: i64 = 1;
|
||||||
|
|
||||||
|
if (str_len > delimiter_len) {
|
||||||
|
var str_index: usize = 0;
|
||||||
|
const end_cond: usize = str_len - delimiter_len;
|
||||||
|
|
||||||
|
while (str_index < end_cond) {
|
||||||
|
var delimiter_index: usize = 0;
|
||||||
|
|
||||||
|
var matches_delimiter = true;
|
||||||
|
|
||||||
|
while (delimiter_index < delimiter_len) {
|
||||||
|
const delimiterChar = delimiter_bytes[delimiter_index];
|
||||||
|
const strChar = str_bytes_ptrs[str_index + delimiter_index];
|
||||||
|
|
||||||
|
if (delimiterChar != strChar) {
|
||||||
|
matches_delimiter = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
delimiter_index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matches_delimiter) {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
str_index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "countSegments: long delimiter" {
|
||||||
|
// Str.split "str" "delimiter" == [ "str" ]
|
||||||
|
// 1 segment
|
||||||
|
|
||||||
|
const str_len: usize = 3;
|
||||||
|
var str: [str_len]u8 = "str".*;
|
||||||
|
const str_ptr: [*]u8 = &str;
|
||||||
|
|
||||||
|
const delimiter_len = 9;
|
||||||
|
var delimiter: [delimiter_len]u8 = "delimiter".*;
|
||||||
|
const delimiter_ptr: [*]u8 = &delimiter;
|
||||||
|
|
||||||
|
const segments_count = countSegments(
|
||||||
|
str_ptr,
|
||||||
|
str_len,
|
||||||
|
delimiter_ptr,
|
||||||
|
delimiter_len
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(segments_count == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "countSegments: delimiter at start" {
|
||||||
|
// Str.split "hello there" "hello" == [ "", " there" ]
|
||||||
|
// 2 segments
|
||||||
|
|
||||||
|
const str_len: usize = 11;
|
||||||
|
var str: [str_len]u8 = "hello there".*;
|
||||||
|
const str_ptr: [*]u8 = &str;
|
||||||
|
|
||||||
|
const delimiter_len = 5;
|
||||||
|
var delimiter: [delimiter_len]u8 = "hello".*;
|
||||||
|
const delimiter_ptr: [*]u8 = &delimiter;
|
||||||
|
|
||||||
|
const segments_count = countSegments(
|
||||||
|
str_ptr,
|
||||||
|
str_len,
|
||||||
|
delimiter_ptr,
|
||||||
|
delimiter_len
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(segments_count == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "countSegments: delimiter interspered" {
|
||||||
|
// Str.split "a!b!c" "!" == [ "a", "b", "c" ]
|
||||||
|
// 3 segments
|
||||||
|
|
||||||
|
const str_len: usize = 5;
|
||||||
|
var str: [str_len]u8 = "a!b!c".*;
|
||||||
|
const str_ptr: [*]u8 = &str;
|
||||||
|
|
||||||
|
const delimiter_len = 1;
|
||||||
|
var delimiter: [delimiter_len]u8 = "!".*;
|
||||||
|
const delimiter_ptr: [*]u8 = &delimiter;
|
||||||
|
|
||||||
|
const segments_count = countSegments(
|
||||||
|
str_ptr,
|
||||||
|
str_len,
|
||||||
|
delimiter_ptr,
|
||||||
|
delimiter_len
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(segments_count == 3);
|
||||||
|
}
|
70
compiler/builtins/build.rs
Normal file
70
compiler/builtins/build.rs
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
use std::convert::AsRef;
|
||||||
|
use std::env;
|
||||||
|
use std::ffi::OsStr;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::process::Command;
|
||||||
|
use std::str;
|
||||||
|
|
||||||
|
fn run_command<S, I>(command: &str, args: I)
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = S>,
|
||||||
|
S: AsRef<OsStr>,
|
||||||
|
{
|
||||||
|
let output_result = Command::new(OsStr::new(&command)).args(args).output();
|
||||||
|
match output_result {
|
||||||
|
Ok(output) => match output.status.success() {
|
||||||
|
true => (),
|
||||||
|
false => {
|
||||||
|
let error_str = match str::from_utf8(&output.stderr) {
|
||||||
|
Ok(stderr) => stderr.to_string(),
|
||||||
|
Err(_) => format!("Failed to run \"{}\"", command),
|
||||||
|
};
|
||||||
|
panic!("{} failed: {}", command, error_str);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(reason) => panic!("{} failed: {}", command, reason),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||||
|
|
||||||
|
// "." is relative to where "build.rs" is
|
||||||
|
let src_path = Path::new(".").join("bitcode").join("src").join("main.zig");
|
||||||
|
let src_path_str = src_path.to_str().expect("Invalid src path");
|
||||||
|
println!("Building main.zig from: {}", src_path_str);
|
||||||
|
|
||||||
|
let zig_cache_dir = Path::new(&out_dir).join("zig-cache");
|
||||||
|
let zig_cache_dir_str = zig_cache_dir.to_str().expect("Invalid zig cache dir");
|
||||||
|
println!("Setting zig cache to: {}", zig_cache_dir_str);
|
||||||
|
|
||||||
|
let dest_ll_path = Path::new(&out_dir).join("builtins.ll");
|
||||||
|
let dest_ll = dest_ll_path.to_str().expect("Invalid dest ir path");
|
||||||
|
let emit_ir_arg = "-femit-llvm-ir=".to_owned() + dest_ll;
|
||||||
|
println!("Compiling zig llvm-ir to: {}", dest_ll);
|
||||||
|
|
||||||
|
run_command(
|
||||||
|
"zig",
|
||||||
|
&[
|
||||||
|
"build-obj",
|
||||||
|
src_path_str,
|
||||||
|
&emit_ir_arg,
|
||||||
|
"-fno-emit-bin",
|
||||||
|
"--strip",
|
||||||
|
"-O",
|
||||||
|
"ReleaseFast",
|
||||||
|
"--cache-dir",
|
||||||
|
zig_cache_dir_str,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
let dest_bc_path = Path::new(&out_dir).join("builtins.bc");
|
||||||
|
let dest_bc = dest_bc_path.to_str().expect("Invalid dest bc path");
|
||||||
|
println!("Compiling bitcode to: {}", dest_bc);
|
||||||
|
|
||||||
|
run_command("llvm-as-10", &[dest_ll, "-o", dest_bc]);
|
||||||
|
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
println!("cargo:rerun-if-changed={}", src_path_str);
|
||||||
|
println!("cargo:rustc-env=BUILTINS_BC={}", dest_bc);
|
||||||
|
}
|
25
compiler/builtins/src/bitcode.rs
Normal file
25
compiler/builtins/src/bitcode.rs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::prelude::Read;
|
||||||
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
pub fn get_bytes() -> Vec<u8> {
|
||||||
|
// In the build script for the builtins module, we compile the builtins bitcode and set
|
||||||
|
// BUILTINS_BC to the path to the compiled output.
|
||||||
|
let path: &'static str = env!(
|
||||||
|
"BUILTINS_BC",
|
||||||
|
"Env var BUILTINS_BC not found. Is there a problem with the build script?"
|
||||||
|
);
|
||||||
|
let mut builtins_bitcode = File::open(path).expect("Unable to find builtins bitcode source");
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
builtins_bitcode
|
||||||
|
.read_to_end(&mut buffer)
|
||||||
|
.expect("Unable to read builtins bitcode");
|
||||||
|
buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MATH_ATAN: &str = "roc_builtins.math.atan";
|
||||||
|
pub const MATH_IS_FINITE: &str = "roc_builtins.math.is_finite";
|
||||||
|
pub const MATH_POW_INT: &str = "roc_builtins.math.pow_int";
|
||||||
|
|
||||||
|
pub const STR_COUNT_SEGEMENTS: &str = "roc_builtins.str.count_segements";
|
||||||
|
pub const STR_STR_SPLIT_IN_PLACE: &str = "roc_builtins.str.str_split_in_place";
|
|
@ -10,5 +10,6 @@
|
||||||
// and encouraging shortcuts here creates bad incentives. I would rather temporarily
|
// and encouraging shortcuts here creates bad incentives. I would rather temporarily
|
||||||
// re-enable this when working on performance optimizations than have it block PRs.
|
// re-enable this when working on performance optimizations than have it block PRs.
|
||||||
#![allow(clippy::large_enum_variant)]
|
#![allow(clippy::large_enum_variant)]
|
||||||
|
pub mod bitcode;
|
||||||
pub mod std;
|
pub mod std;
|
||||||
pub mod unique;
|
pub mod unique;
|
||||||
|
|
|
@ -110,7 +110,7 @@ pub fn canonicalize_defs<'a>(
|
||||||
mut output: Output,
|
mut output: Output,
|
||||||
var_store: &mut VarStore,
|
var_store: &mut VarStore,
|
||||||
original_scope: &Scope,
|
original_scope: &Scope,
|
||||||
loc_defs: &'a bumpalo::collections::Vec<'a, &'a Located<ast::Def<'a>>>,
|
loc_defs: &'a [&'a Located<ast::Def<'a>>],
|
||||||
pattern_type: PatternType,
|
pattern_type: PatternType,
|
||||||
) -> (CanDefs, Scope, Output, MutMap<Symbol, Region>) {
|
) -> (CanDefs, Scope, Output, MutMap<Symbol, Region>) {
|
||||||
// Canonicalizing defs while detecting shadowing involves a multi-step process:
|
// Canonicalizing defs while detecting shadowing involves a multi-step process:
|
||||||
|
@ -1243,7 +1243,7 @@ pub fn can_defs_with_return<'a>(
|
||||||
env: &mut Env<'a>,
|
env: &mut Env<'a>,
|
||||||
var_store: &mut VarStore,
|
var_store: &mut VarStore,
|
||||||
scope: Scope,
|
scope: Scope,
|
||||||
loc_defs: &'a bumpalo::collections::Vec<'a, &'a Located<ast::Def<'a>>>,
|
loc_defs: &'a [&'a Located<ast::Def<'a>>],
|
||||||
loc_ret: &'a Located<ast::Expr<'a>>,
|
loc_ret: &'a Located<ast::Expr<'a>>,
|
||||||
) -> (Expr, Output) {
|
) -> (Expr, Output) {
|
||||||
let (unsorted, mut scope, defs_output, symbols_introduced) = canonicalize_defs(
|
let (unsorted, mut scope, defs_output, symbols_introduced) = canonicalize_defs(
|
||||||
|
|
|
@ -309,7 +309,7 @@ pub fn canonicalize_expr<'a>(
|
||||||
let mut args = Vec::new();
|
let mut args = Vec::new();
|
||||||
let mut outputs = Vec::new();
|
let mut outputs = Vec::new();
|
||||||
|
|
||||||
for loc_arg in loc_args {
|
for loc_arg in loc_args.iter() {
|
||||||
let (arg_expr, arg_out) =
|
let (arg_expr, arg_out) =
|
||||||
canonicalize_expr(env, var_store, scope, loc_arg.region, &loc_arg.value);
|
canonicalize_expr(env, var_store, scope, loc_arg.region, &loc_arg.value);
|
||||||
|
|
||||||
|
@ -450,7 +450,7 @@ pub fn canonicalize_expr<'a>(
|
||||||
|
|
||||||
let mut bound_by_argument_patterns = MutSet::default();
|
let mut bound_by_argument_patterns = MutSet::default();
|
||||||
|
|
||||||
for loc_pattern in loc_arg_patterns.into_iter() {
|
for loc_pattern in loc_arg_patterns.iter() {
|
||||||
let (new_output, can_arg) = canonicalize_pattern(
|
let (new_output, can_arg) = canonicalize_pattern(
|
||||||
env,
|
env,
|
||||||
var_store,
|
var_store,
|
||||||
|
@ -562,7 +562,7 @@ pub fn canonicalize_expr<'a>(
|
||||||
|
|
||||||
let mut can_branches = Vec::with_capacity(branches.len());
|
let mut can_branches = Vec::with_capacity(branches.len());
|
||||||
|
|
||||||
for branch in branches {
|
for branch in branches.iter() {
|
||||||
let (can_when_branch, branch_references) =
|
let (can_when_branch, branch_references) =
|
||||||
canonicalize_when_branch(env, var_store, scope, region, *branch, &mut output);
|
canonicalize_when_branch(env, var_store, scope, region, *branch, &mut output);
|
||||||
|
|
||||||
|
@ -788,7 +788,7 @@ fn canonicalize_when_branch<'a>(
|
||||||
let mut scope = original_scope.clone();
|
let mut scope = original_scope.clone();
|
||||||
|
|
||||||
// TODO report symbols not bound in all patterns
|
// TODO report symbols not bound in all patterns
|
||||||
for loc_pattern in &branch.patterns {
|
for loc_pattern in branch.patterns.iter() {
|
||||||
let (new_output, can_pattern) = canonicalize_pattern(
|
let (new_output, can_pattern) = canonicalize_pattern(
|
||||||
env,
|
env,
|
||||||
var_store,
|
var_store,
|
||||||
|
|
|
@ -43,7 +43,7 @@ pub struct ModuleOutput {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn canonicalize_module_defs<'a>(
|
pub fn canonicalize_module_defs<'a>(
|
||||||
arena: &Bump,
|
arena: &Bump,
|
||||||
loc_defs: bumpalo::collections::Vec<'a, Located<ast::Def<'a>>>,
|
loc_defs: &'a [Located<ast::Def<'a>>],
|
||||||
home: ModuleId,
|
home: ModuleId,
|
||||||
module_ids: &ModuleIds,
|
module_ids: &ModuleIds,
|
||||||
exposed_ident_ids: IdentIds,
|
exposed_ident_ids: IdentIds,
|
||||||
|
@ -66,9 +66,9 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
let mut desugared =
|
let mut desugared =
|
||||||
bumpalo::collections::Vec::with_capacity_in(loc_defs.len() + num_deps, arena);
|
bumpalo::collections::Vec::with_capacity_in(loc_defs.len() + num_deps, arena);
|
||||||
|
|
||||||
for loc_def in loc_defs {
|
for loc_def in loc_defs.iter() {
|
||||||
desugared.push(&*arena.alloc(Located {
|
desugared.push(&*arena.alloc(Located {
|
||||||
value: desugar_def(arena, arena.alloc(loc_def.value)),
|
value: desugar_def(arena, &loc_def.value),
|
||||||
region: loc_def.region,
|
region: loc_def.region,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,9 +90,10 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located<Expr<'a>>) -> &'a
|
||||||
List(elems) | Nested(List(elems)) => {
|
List(elems) | Nested(List(elems)) => {
|
||||||
let mut new_elems = Vec::with_capacity_in(elems.len(), arena);
|
let mut new_elems = Vec::with_capacity_in(elems.len(), arena);
|
||||||
|
|
||||||
for elem in elems {
|
for elem in elems.iter() {
|
||||||
new_elems.push(desugar_expr(arena, elem));
|
new_elems.push(desugar_expr(arena, elem));
|
||||||
}
|
}
|
||||||
|
let new_elems = new_elems.into_bump_slice();
|
||||||
let value: Expr<'a> = List(new_elems);
|
let value: Expr<'a> = List(new_elems);
|
||||||
|
|
||||||
arena.alloc(Located {
|
arena.alloc(Located {
|
||||||
|
@ -103,7 +104,7 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located<Expr<'a>>) -> &'a
|
||||||
Record { fields, update } | Nested(Record { fields, update }) => {
|
Record { fields, update } | Nested(Record { fields, update }) => {
|
||||||
let mut new_fields = Vec::with_capacity_in(fields.len(), arena);
|
let mut new_fields = Vec::with_capacity_in(fields.len(), arena);
|
||||||
|
|
||||||
for field in fields {
|
for field in fields.iter() {
|
||||||
let value = desugar_field(arena, &field.value);
|
let value = desugar_field(arena, &field.value);
|
||||||
|
|
||||||
new_fields.push(Located {
|
new_fields.push(Located {
|
||||||
|
@ -112,6 +113,8 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located<Expr<'a>>) -> &'a
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let new_fields = new_fields.into_bump_slice();
|
||||||
|
|
||||||
arena.alloc(Located {
|
arena.alloc(Located {
|
||||||
region: loc_expr.region,
|
region: loc_expr.region,
|
||||||
value: Record {
|
value: Record {
|
||||||
|
@ -130,7 +133,7 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located<Expr<'a>>) -> &'a
|
||||||
Defs(defs, loc_ret) | Nested(Defs(defs, loc_ret)) => {
|
Defs(defs, loc_ret) | Nested(Defs(defs, loc_ret)) => {
|
||||||
let mut desugared_defs = Vec::with_capacity_in(defs.len(), arena);
|
let mut desugared_defs = Vec::with_capacity_in(defs.len(), arena);
|
||||||
|
|
||||||
for loc_def in defs.into_iter() {
|
for loc_def in defs.iter() {
|
||||||
let loc_def = Located {
|
let loc_def = Located {
|
||||||
value: desugar_def(arena, &loc_def.value),
|
value: desugar_def(arena, &loc_def.value),
|
||||||
region: loc_def.region,
|
region: loc_def.region,
|
||||||
|
@ -139,6 +142,8 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located<Expr<'a>>) -> &'a
|
||||||
desugared_defs.push(&*arena.alloc(loc_def));
|
desugared_defs.push(&*arena.alloc(loc_def));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let desugared_defs = desugared_defs.into_bump_slice();
|
||||||
|
|
||||||
arena.alloc(Located {
|
arena.alloc(Located {
|
||||||
value: Defs(desugared_defs, desugar_expr(arena, loc_ret)),
|
value: Defs(desugared_defs, desugar_expr(arena, loc_ret)),
|
||||||
region: loc_expr.region,
|
region: loc_expr.region,
|
||||||
|
@ -147,10 +152,12 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located<Expr<'a>>) -> &'a
|
||||||
Apply(loc_fn, loc_args, called_via) | Nested(Apply(loc_fn, loc_args, called_via)) => {
|
Apply(loc_fn, loc_args, called_via) | Nested(Apply(loc_fn, loc_args, called_via)) => {
|
||||||
let mut desugared_args = Vec::with_capacity_in(loc_args.len(), arena);
|
let mut desugared_args = Vec::with_capacity_in(loc_args.len(), arena);
|
||||||
|
|
||||||
for loc_arg in loc_args {
|
for loc_arg in loc_args.iter() {
|
||||||
desugared_args.push(desugar_expr(arena, loc_arg));
|
desugared_args.push(desugar_expr(arena, loc_arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let desugared_args = desugared_args.into_bump_slice();
|
||||||
|
|
||||||
arena.alloc(Located {
|
arena.alloc(Located {
|
||||||
value: Apply(desugar_expr(arena, loc_fn), desugared_args, *called_via),
|
value: Apply(desugar_expr(arena, loc_fn), desugared_args, *called_via),
|
||||||
region: loc_expr.region,
|
region: loc_expr.region,
|
||||||
|
@ -160,11 +167,11 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located<Expr<'a>>) -> &'a
|
||||||
let loc_desugared_cond = &*arena.alloc(desugar_expr(arena, &loc_cond_expr));
|
let loc_desugared_cond = &*arena.alloc(desugar_expr(arena, &loc_cond_expr));
|
||||||
let mut desugared_branches = Vec::with_capacity_in(branches.len(), arena);
|
let mut desugared_branches = Vec::with_capacity_in(branches.len(), arena);
|
||||||
|
|
||||||
for branch in branches.into_iter() {
|
for branch in branches.iter() {
|
||||||
let desugared = desugar_expr(arena, &branch.value);
|
let desugared = desugar_expr(arena, &branch.value);
|
||||||
|
|
||||||
let mut alternatives = Vec::with_capacity_in(branch.patterns.len(), arena);
|
let mut alternatives = Vec::with_capacity_in(branch.patterns.len(), arena);
|
||||||
for loc_pattern in &branch.patterns {
|
for loc_pattern in branch.patterns.iter() {
|
||||||
alternatives.push(Located {
|
alternatives.push(Located {
|
||||||
region: loc_pattern.region,
|
region: loc_pattern.region,
|
||||||
value: Pattern::Nested(&loc_pattern.value),
|
value: Pattern::Nested(&loc_pattern.value),
|
||||||
|
@ -177,6 +184,8 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located<Expr<'a>>) -> &'a
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let alternatives = alternatives.into_bump_slice();
|
||||||
|
|
||||||
desugared_branches.push(&*arena.alloc(WhenBranch {
|
desugared_branches.push(&*arena.alloc(WhenBranch {
|
||||||
patterns: alternatives,
|
patterns: alternatives,
|
||||||
value: Located {
|
value: Located {
|
||||||
|
@ -187,6 +196,8 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located<Expr<'a>>) -> &'a
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let desugared_branches = desugared_branches.into_bump_slice();
|
||||||
|
|
||||||
arena.alloc(Located {
|
arena.alloc(Located {
|
||||||
value: When(loc_desugared_cond, desugared_branches),
|
value: When(loc_desugared_cond, desugared_branches),
|
||||||
region: loc_expr.region,
|
region: loc_expr.region,
|
||||||
|
@ -213,6 +224,8 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located<Expr<'a>>) -> &'a
|
||||||
let loc_fn_var = arena.alloc(Located { region, value });
|
let loc_fn_var = arena.alloc(Located { region, value });
|
||||||
let desugared_args = bumpalo::vec![in arena; desugar_expr(arena, loc_arg)];
|
let desugared_args = bumpalo::vec![in arena; desugar_expr(arena, loc_arg)];
|
||||||
|
|
||||||
|
let desugared_args = desugared_args.into_bump_slice();
|
||||||
|
|
||||||
arena.alloc(Located {
|
arena.alloc(Located {
|
||||||
value: Apply(loc_fn_var, desugared_args, CalledVia::UnaryOp(op)),
|
value: Apply(loc_fn_var, desugared_args, CalledVia::UnaryOp(op)),
|
||||||
region: loc_expr.region,
|
region: loc_expr.region,
|
||||||
|
@ -463,10 +476,12 @@ fn desugar_bin_op<'a>(arena: &'a Bump, loc_expr: &'a Located<Expr<'_>>) -> &'a L
|
||||||
|
|
||||||
args.push(left);
|
args.push(left);
|
||||||
|
|
||||||
for arg in arguments {
|
for arg in arguments.iter() {
|
||||||
args.push(arg);
|
args.push(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let args = args.into_bump_slice();
|
||||||
|
|
||||||
Apply(function, args, CalledVia::BinOp(Pizza))
|
Apply(function, args, CalledVia::BinOp(Pizza))
|
||||||
}
|
}
|
||||||
expr => {
|
expr => {
|
||||||
|
@ -480,6 +495,8 @@ fn desugar_bin_op<'a>(arena: &'a Bump, loc_expr: &'a Located<Expr<'_>>) -> &'a L
|
||||||
region: right.region,
|
region: right.region,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let args = args.into_bump_slice();
|
||||||
|
|
||||||
Apply(function, args, CalledVia::BinOp(Pizza))
|
Apply(function, args, CalledVia::BinOp(Pizza))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -498,6 +515,8 @@ fn desugar_bin_op<'a>(arena: &'a Bump, loc_expr: &'a Located<Expr<'_>>) -> &'a L
|
||||||
region: loc_op.region,
|
region: loc_op.region,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let args = args.into_bump_slice();
|
||||||
|
|
||||||
Apply(loc_expr, args, CalledVia::BinOp(binop))
|
Apply(loc_expr, args, CalledVia::BinOp(binop))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::pattern::fmt_pattern;
|
||||||
use crate::spaces::{
|
use crate::spaces::{
|
||||||
add_spaces, fmt_comments_only, fmt_condition_spaces, fmt_spaces, newline, INDENT,
|
add_spaces, fmt_comments_only, fmt_condition_spaces, fmt_spaces, newline, INDENT,
|
||||||
};
|
};
|
||||||
use bumpalo::collections::{String, Vec};
|
use bumpalo::collections::String;
|
||||||
use roc_module::operator::{self, BinOp};
|
use roc_module::operator::{self, BinOp};
|
||||||
use roc_parse::ast::StrSegment;
|
use roc_parse::ast::StrSegment;
|
||||||
use roc_parse::ast::{AssignedField, Base, CommentOrNewline, Expr, Pattern, WhenBranch};
|
use roc_parse::ast::{AssignedField, Base, CommentOrNewline, Expr, Pattern, WhenBranch};
|
||||||
|
@ -194,12 +194,12 @@ impl<'a> Formattable<'a> for Expr<'a> {
|
||||||
if multiline_args {
|
if multiline_args {
|
||||||
let arg_indent = indent + INDENT;
|
let arg_indent = indent + INDENT;
|
||||||
|
|
||||||
for loc_arg in loc_args {
|
for loc_arg in loc_args.iter() {
|
||||||
newline(buf, arg_indent);
|
newline(buf, arg_indent);
|
||||||
loc_arg.format_with_options(buf, Parens::InApply, Newlines::No, arg_indent);
|
loc_arg.format_with_options(buf, Parens::InApply, Newlines::No, arg_indent);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for loc_arg in loc_args {
|
for loc_arg in loc_args.iter() {
|
||||||
buf.push(' ');
|
buf.push(' ');
|
||||||
loc_arg.format_with_options(buf, Parens::InApply, Newlines::Yes, indent);
|
loc_arg.format_with_options(buf, Parens::InApply, Newlines::Yes, indent);
|
||||||
}
|
}
|
||||||
|
@ -707,7 +707,7 @@ fn fmt_if<'a>(
|
||||||
|
|
||||||
pub fn fmt_closure<'a>(
|
pub fn fmt_closure<'a>(
|
||||||
buf: &mut String<'a>,
|
buf: &mut String<'a>,
|
||||||
loc_patterns: &'a Vec<'a, Located<Pattern<'a>>>,
|
loc_patterns: &'a [Located<Pattern<'a>>],
|
||||||
loc_ret: &'a Located<Expr<'a>>,
|
loc_ret: &'a Located<Expr<'a>>,
|
||||||
indent: u16,
|
indent: u16,
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
use std::env;
|
|
||||||
use std::fs;
|
|
||||||
use std::path::Path;
|
|
||||||
use std::process::Command;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let src_path = fs::canonicalize("./../builtins/bitcode/src/lib.c")
|
|
||||||
.expect("Failed to resolve bitcode source");
|
|
||||||
let src = src_path.to_str().expect("Invalid src path");
|
|
||||||
|
|
||||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
|
||||||
let dest_path = Path::new(&out_dir).join("builtins.bc");
|
|
||||||
let dest = dest_path.to_str().expect("Invalid dest path");
|
|
||||||
|
|
||||||
Command::new("clang")
|
|
||||||
.args(&["-emit-llvm", "-o", dest, "-c", src])
|
|
||||||
.status()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
println!("cargo:rerun-if-changed=build.rs");
|
|
||||||
println!("cargo:rerun-if-changed={}", src);
|
|
||||||
println!("cargo:rustc-env=BUILTINS_BC={}", dest);
|
|
||||||
}
|
|
|
@ -29,13 +29,12 @@ use inkwell::values::{
|
||||||
};
|
};
|
||||||
use inkwell::OptimizationLevel;
|
use inkwell::OptimizationLevel;
|
||||||
use inkwell::{AddressSpace, IntPredicate};
|
use inkwell::{AddressSpace, IntPredicate};
|
||||||
|
use roc_builtins::bitcode;
|
||||||
use roc_collections::all::{ImMap, MutSet};
|
use roc_collections::all::{ImMap, MutSet};
|
||||||
use roc_module::low_level::LowLevel;
|
use roc_module::low_level::LowLevel;
|
||||||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||||
use roc_mono::ir::{JoinPointId, Wrapped};
|
use roc_mono::ir::{JoinPointId, Wrapped};
|
||||||
use roc_mono::layout::{Builtin, Layout, MemoryMode};
|
use roc_mono::layout::{Builtin, Layout, MemoryMode};
|
||||||
use std::fs::File;
|
|
||||||
use std::io::prelude::Read;
|
|
||||||
use target_lexicon::CallingConvention;
|
use target_lexicon::CallingConvention;
|
||||||
|
|
||||||
/// This is for Inkwell's FunctionValue::verify - we want to know the verification
|
/// This is for Inkwell's FunctionValue::verify - we want to know the verification
|
||||||
|
@ -183,19 +182,9 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn module_from_builtins<'ctx>(ctx: &'ctx Context, module_name: &str) -> Module<'ctx> {
|
pub fn module_from_builtins<'ctx>(ctx: &'ctx Context, module_name: &str) -> Module<'ctx> {
|
||||||
// In the build script for the gen module, we compile the builtins bitcode and set
|
let bitcode_bytes = bitcode::get_bytes();
|
||||||
// BUILTINS_BC to the path to the compiled output.
|
|
||||||
let path: &'static str = env!(
|
|
||||||
"BUILTINS_BC",
|
|
||||||
"Env var BUILTINS_BC not found. Is there a problem with the build script?"
|
|
||||||
);
|
|
||||||
let mut builtins_bitcode = File::open(path).expect("Unable to find builtins bitcode source");
|
|
||||||
let mut buffer = std::vec::Vec::new();
|
|
||||||
builtins_bitcode
|
|
||||||
.read_to_end(&mut buffer)
|
|
||||||
.expect("Unable to read builtins bitcode");
|
|
||||||
|
|
||||||
let memory_buffer = MemoryBuffer::create_from_memory_range(&buffer, module_name);
|
let memory_buffer = MemoryBuffer::create_from_memory_range(&bitcode_bytes, module_name);
|
||||||
|
|
||||||
let module = Module::parse_bitcode_from_buffer(&memory_buffer, ctx)
|
let module = Module::parse_bitcode_from_buffer(&memory_buffer, ctx)
|
||||||
.unwrap_or_else(|err| panic!("Unable to import builtins bitcode. LLVM error: {:?}", err));
|
.unwrap_or_else(|err| panic!("Unable to import builtins bitcode. LLVM error: {:?}", err));
|
||||||
|
@ -2541,7 +2530,12 @@ fn build_int_binop<'a, 'ctx, 'env>(
|
||||||
NumLte => bd.build_int_compare(SLE, lhs, rhs, "int_lte").into(),
|
NumLte => bd.build_int_compare(SLE, lhs, rhs, "int_lte").into(),
|
||||||
NumRemUnchecked => bd.build_int_signed_rem(lhs, rhs, "rem_int").into(),
|
NumRemUnchecked => bd.build_int_signed_rem(lhs, rhs, "rem_int").into(),
|
||||||
NumDivUnchecked => bd.build_int_signed_div(lhs, rhs, "div_int").into(),
|
NumDivUnchecked => bd.build_int_signed_div(lhs, rhs, "div_int").into(),
|
||||||
NumPowInt => call_bitcode_fn(NumPowInt, env, &[lhs.into(), rhs.into()], "pow_int_"),
|
NumPowInt => call_bitcode_fn(
|
||||||
|
NumPowInt,
|
||||||
|
env,
|
||||||
|
&[lhs.into(), rhs.into()],
|
||||||
|
&bitcode::MATH_POW_INT,
|
||||||
|
),
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!("Unrecognized int binary operation: {:?}", op);
|
unreachable!("Unrecognized int binary operation: {:?}", op);
|
||||||
}
|
}
|
||||||
|
@ -2589,7 +2583,8 @@ fn build_float_binop<'a, 'ctx, 'env>(
|
||||||
let result = bd.build_float_add(lhs, rhs, "add_float");
|
let result = bd.build_float_add(lhs, rhs, "add_float");
|
||||||
|
|
||||||
let is_finite =
|
let is_finite =
|
||||||
call_bitcode_fn(NumIsFinite, env, &[result.into()], "is_finite_").into_int_value();
|
call_bitcode_fn(NumIsFinite, env, &[result.into()], &bitcode::MATH_IS_FINITE)
|
||||||
|
.into_int_value();
|
||||||
|
|
||||||
let then_block = context.append_basic_block(parent, "then_block");
|
let then_block = context.append_basic_block(parent, "then_block");
|
||||||
let throw_block = context.append_basic_block(parent, "throw_block");
|
let throw_block = context.append_basic_block(parent, "throw_block");
|
||||||
|
@ -2610,7 +2605,8 @@ fn build_float_binop<'a, 'ctx, 'env>(
|
||||||
let result = bd.build_float_add(lhs, rhs, "add_float");
|
let result = bd.build_float_add(lhs, rhs, "add_float");
|
||||||
|
|
||||||
let is_finite =
|
let is_finite =
|
||||||
call_bitcode_fn(NumIsFinite, env, &[result.into()], "is_finite_").into_int_value();
|
call_bitcode_fn(NumIsFinite, env, &[result.into()], &bitcode::MATH_IS_FINITE)
|
||||||
|
.into_int_value();
|
||||||
let is_infinite = bd.build_not(is_finite, "negate");
|
let is_infinite = bd.build_not(is_finite, "negate");
|
||||||
|
|
||||||
let struct_type = context.struct_type(
|
let struct_type = context.struct_type(
|
||||||
|
@ -2739,8 +2735,8 @@ fn build_float_unary_op<'a, 'ctx, 'env>(
|
||||||
env.context.i64_type(),
|
env.context.i64_type(),
|
||||||
"num_floor",
|
"num_floor",
|
||||||
),
|
),
|
||||||
NumIsFinite => call_bitcode_fn(NumIsFinite, env, &[arg.into()], "is_finite_"),
|
NumIsFinite => call_bitcode_fn(NumIsFinite, env, &[arg.into()], &bitcode::MATH_IS_FINITE),
|
||||||
NumAtan => call_bitcode_fn(NumAtan, env, &[arg.into()], "atan_"),
|
NumAtan => call_bitcode_fn(NumAtan, env, &[arg.into()], &bitcode::MATH_ATAN),
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!("Unrecognized int unary operation: {:?}", op);
|
unreachable!("Unrecognized int unary operation: {:?}", op);
|
||||||
}
|
}
|
||||||
|
|
|
@ -788,8 +788,7 @@ pub fn list_walk_right<'a, 'ctx, 'env>(
|
||||||
let new_current = call_site_value
|
let new_current = call_site_value
|
||||||
.try_as_basic_value()
|
.try_as_basic_value()
|
||||||
.left()
|
.left()
|
||||||
.unwrap_or_else(|| panic!("LLVM error: Invalid call by pointer."))
|
.unwrap_or_else(|| panic!("LLVM error: Invalid call by pointer."));
|
||||||
.into_int_value();
|
|
||||||
|
|
||||||
builder.build_store(accum_alloca, new_current);
|
builder.build_store(accum_alloca, new_current);
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,8 +14,7 @@ mod helpers;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod gen_list {
|
mod gen_list {
|
||||||
use crate::helpers::with_larger_debug_stack;
|
use crate::helpers::with_larger_debug_stack;
|
||||||
//use roc_std::roclist;
|
use roc_std::{RocList, RocStr};
|
||||||
use roc_std::RocList;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn roc_list_construction() {
|
fn roc_list_construction() {
|
||||||
|
@ -264,6 +263,47 @@ mod gen_list {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn list_walk_right_with_str() {
|
||||||
|
assert_evals_to!(
|
||||||
|
r#"List.walkRight [ "x", "y", "z" ] Str.concat "<""#,
|
||||||
|
RocStr::from("zyx<"),
|
||||||
|
RocStr
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_evals_to!(
|
||||||
|
r#"List.walkRight [ "Third", "Second", "First" ] Str.concat "Fourth""#,
|
||||||
|
RocStr::from("FirstSecondThirdFourth"),
|
||||||
|
RocStr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn list_walk_right_with_record() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Bit : [ Zero, One ]
|
||||||
|
|
||||||
|
byte = [ Zero, One, Zero, One, Zero, Zero, One, Zero ]
|
||||||
|
|
||||||
|
initialCounts = { zeroes: 0, ones: 0 }
|
||||||
|
|
||||||
|
acc = \b, r ->
|
||||||
|
when b is
|
||||||
|
Zero -> { r & zeroes: r.zeroes + 1 }
|
||||||
|
One -> { r & ones: r.ones + 1 }
|
||||||
|
|
||||||
|
finalCounts = List.walkRight byte acc initialCounts
|
||||||
|
|
||||||
|
finalCounts.ones * 10 + finalCounts.zeroes
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
35,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn list_keep_if_empty_list_of_int() {
|
fn list_keep_if_empty_list_of_int() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
|
|
|
@ -686,15 +686,7 @@ mod gen_num {
|
||||||
assert_evals_to!("Num.powInt 2 3", 8, i64);
|
assert_evals_to!("Num.powInt 2 3", 8, i64);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For some reason, libm's atan has slightly different results on macos vs non-macos
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
fn atan_macos() {
|
|
||||||
assert_evals_to!("Num.atan 10", 1.4711276743037345, f64);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
|
||||||
fn atan() {
|
fn atan() {
|
||||||
assert_evals_to!("Num.atan 10", 1.4711276743037347, f64);
|
assert_evals_to!("Num.atan 10", 1.4711276743037347, f64);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ pub struct DocEntry {
|
||||||
pub fn generate_module_docs<'a>(
|
pub fn generate_module_docs<'a>(
|
||||||
module_name: ModuleName,
|
module_name: ModuleName,
|
||||||
exposed_ident_ids: &'a IdentIds,
|
exposed_ident_ids: &'a IdentIds,
|
||||||
parsed_defs: &'a bumpalo::collections::Vec<'a, Located<Def<'a>>>,
|
parsed_defs: &'a [Located<Def<'a>>],
|
||||||
) -> ModuleDocumentation {
|
) -> ModuleDocumentation {
|
||||||
let (entries, _) =
|
let (entries, _) =
|
||||||
parsed_defs
|
parsed_defs
|
||||||
|
|
|
@ -2031,7 +2031,7 @@ fn parse_and_constrain<'a>(
|
||||||
let mut var_store = VarStore::default();
|
let mut var_store = VarStore::default();
|
||||||
let canonicalized = canonicalize_module_defs(
|
let canonicalized = canonicalize_module_defs(
|
||||||
&arena,
|
&arena,
|
||||||
parsed_defs,
|
&parsed_defs,
|
||||||
module_id,
|
module_id,
|
||||||
module_ids,
|
module_ids,
|
||||||
header.exposed_ident_ids,
|
header.exposed_ident_ids,
|
||||||
|
|
|
@ -78,8 +78,8 @@ mod test_mono {
|
||||||
println!("Ignoring {} canonicalization problems", can_problems.len());
|
println!("Ignoring {} canonicalization problems", can_problems.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(type_problems.is_empty());
|
assert_eq!(type_problems, Vec::new());
|
||||||
assert!(mono_problems.is_empty());
|
assert_eq!(mono_problems, Vec::new());
|
||||||
|
|
||||||
debug_assert_eq!(exposed_to_host.len(), 1);
|
debug_assert_eq!(exposed_to_host.len(), 1);
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ pub struct InterfaceHeader<'a> {
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct WhenBranch<'a> {
|
pub struct WhenBranch<'a> {
|
||||||
pub patterns: Vec<'a, Loc<Pattern<'a>>>,
|
pub patterns: &'a [Loc<Pattern<'a>>],
|
||||||
pub value: Loc<Expr<'a>>,
|
pub value: Loc<Expr<'a>>,
|
||||||
pub guard: Option<Loc<Expr<'a>>>,
|
pub guard: Option<Loc<Expr<'a>>>,
|
||||||
}
|
}
|
||||||
|
@ -188,10 +188,10 @@ pub enum Expr<'a> {
|
||||||
AccessorFunction(&'a str),
|
AccessorFunction(&'a str),
|
||||||
|
|
||||||
// Collection Literals
|
// Collection Literals
|
||||||
List(Vec<'a, &'a Loc<Expr<'a>>>),
|
List(&'a [&'a Loc<Expr<'a>>]),
|
||||||
Record {
|
Record {
|
||||||
update: Option<&'a Loc<Expr<'a>>>,
|
update: Option<&'a Loc<Expr<'a>>>,
|
||||||
fields: Vec<'a, Loc<AssignedField<'a, Expr<'a>>>>,
|
fields: &'a [Loc<AssignedField<'a, Expr<'a>>>],
|
||||||
},
|
},
|
||||||
|
|
||||||
// Lookups
|
// Lookups
|
||||||
|
@ -205,14 +205,14 @@ pub enum Expr<'a> {
|
||||||
PrivateTag(&'a str),
|
PrivateTag(&'a str),
|
||||||
|
|
||||||
// Pattern Matching
|
// Pattern Matching
|
||||||
Closure(&'a Vec<'a, Loc<Pattern<'a>>>, &'a Loc<Expr<'a>>),
|
Closure(&'a [Loc<Pattern<'a>>], &'a Loc<Expr<'a>>),
|
||||||
/// Multiple defs in a row
|
/// Multiple defs in a row
|
||||||
Defs(Vec<'a, &'a Loc<Def<'a>>>, &'a Loc<Expr<'a>>),
|
Defs(&'a [&'a Loc<Def<'a>>], &'a Loc<Expr<'a>>),
|
||||||
|
|
||||||
// Application
|
// Application
|
||||||
/// To apply by name, do Apply(Var(...), ...)
|
/// To apply by name, do Apply(Var(...), ...)
|
||||||
/// To apply a tag by name, do Apply(Tag(...), ...)
|
/// To apply a tag by name, do Apply(Tag(...), ...)
|
||||||
Apply(&'a Loc<Expr<'a>>, Vec<'a, &'a Loc<Expr<'a>>>, CalledVia),
|
Apply(&'a Loc<Expr<'a>>, &'a [&'a Loc<Expr<'a>>], CalledVia),
|
||||||
BinOp(&'a (Loc<Expr<'a>>, Loc<BinOp>, Loc<Expr<'a>>)),
|
BinOp(&'a (Loc<Expr<'a>>, Loc<BinOp>, Loc<Expr<'a>>)),
|
||||||
UnaryOp(&'a Loc<Expr<'a>>, Loc<UnaryOp>),
|
UnaryOp(&'a Loc<Expr<'a>>, Loc<UnaryOp>),
|
||||||
|
|
||||||
|
@ -226,7 +226,7 @@ pub enum Expr<'a> {
|
||||||
/// Vec, because there may be many patterns, and the guard
|
/// Vec, because there may be many patterns, and the guard
|
||||||
/// is Option<Expr> because each branch may be preceded by
|
/// is Option<Expr> because each branch may be preceded by
|
||||||
/// a guard (".. if ..").
|
/// a guard (".. if ..").
|
||||||
Vec<'a, &'a WhenBranch<'a>>,
|
&'a [&'a WhenBranch<'a>],
|
||||||
),
|
),
|
||||||
|
|
||||||
// Blank Space (e.g. comments, spaces, newlines) before or after an expression.
|
// Blank Space (e.g. comments, spaces, newlines) before or after an expression.
|
||||||
|
|
|
@ -82,7 +82,7 @@ macro_rules! loc_parenthetical_expr {
|
||||||
region: loc_expr_with_extras.region,
|
region: loc_expr_with_extras.region,
|
||||||
value: Expr::Apply(
|
value: Expr::Apply(
|
||||||
arena.alloc(loc_expr),
|
arena.alloc(loc_expr),
|
||||||
allocated_args,
|
allocated_args.into_bump_slice(),
|
||||||
CalledVia::Space,
|
CalledVia::Space,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
@ -250,7 +250,7 @@ fn expr_to_pattern<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<'a>,
|
||||||
|
|
||||||
let mut arg_patterns = Vec::with_capacity_in(loc_args.len(), arena);
|
let mut arg_patterns = Vec::with_capacity_in(loc_args.len(), arena);
|
||||||
|
|
||||||
for loc_arg in loc_args {
|
for loc_arg in loc_args.iter() {
|
||||||
let region = loc_arg.region;
|
let region = loc_arg.region;
|
||||||
let value = expr_to_pattern(arena, &loc_arg.value)?;
|
let value = expr_to_pattern(arena, &loc_arg.value)?;
|
||||||
|
|
||||||
|
@ -279,7 +279,7 @@ fn expr_to_pattern<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<'a>,
|
||||||
} => {
|
} => {
|
||||||
let mut loc_patterns = Vec::with_capacity_in(fields.len(), arena);
|
let mut loc_patterns = Vec::with_capacity_in(fields.len(), arena);
|
||||||
|
|
||||||
for loc_assigned_field in fields {
|
for loc_assigned_field in fields.iter() {
|
||||||
let region = loc_assigned_field.region;
|
let region = loc_assigned_field.region;
|
||||||
let value = assigned_expr_field_to_pattern(arena, &loc_assigned_field.value)?;
|
let value = assigned_expr_field_to_pattern(arena, &loc_assigned_field.value)?;
|
||||||
|
|
||||||
|
@ -691,7 +691,10 @@ fn parse_def_expr<'a>(
|
||||||
// for formatting reasons, we must insert the first def first!
|
// for formatting reasons, we must insert the first def first!
|
||||||
defs.insert(0, arena.alloc(loc_first_def));
|
defs.insert(0, arena.alloc(loc_first_def));
|
||||||
|
|
||||||
Ok((Expr::Defs(defs, arena.alloc(loc_ret)), state))
|
Ok((
|
||||||
|
Expr::Defs(defs.into_bump_slice(), arena.alloc(loc_ret)),
|
||||||
|
state,
|
||||||
|
))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.parse(arena, state)
|
.parse(arena, state)
|
||||||
|
@ -766,6 +769,8 @@ fn parse_def_signature<'a>(
|
||||||
// corresponding definition (the one with the body).
|
// corresponding definition (the one with the body).
|
||||||
defs.insert(0, arena.alloc(loc_first_def));
|
defs.insert(0, arena.alloc(loc_first_def));
|
||||||
|
|
||||||
|
let defs = defs.into_bump_slice();
|
||||||
|
|
||||||
Ok((Expr::Defs(defs, arena.alloc(loc_ret)), state))
|
Ok((Expr::Defs(defs, arena.alloc(loc_ret)), state))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -848,7 +853,12 @@ fn closure<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
|
||||||
),
|
),
|
||||||
|arena: &'a Bump, opt_contents| match opt_contents {
|
|arena: &'a Bump, opt_contents| match opt_contents {
|
||||||
None => Expr::MalformedClosure,
|
None => Expr::MalformedClosure,
|
||||||
Some((params, loc_body)) => Expr::Closure(arena.alloc(params), arena.alloc(loc_body)),
|
Some((params, loc_body)) => {
|
||||||
|
let params: Vec<'a, Located<Pattern<'a>>> = params;
|
||||||
|
let params: &'a [Located<Pattern<'a>>] = params.into_bump_slice();
|
||||||
|
|
||||||
|
Expr::Closure(params, arena.alloc(loc_body))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1119,7 +1129,10 @@ mod when {
|
||||||
let (branches, state) =
|
let (branches, state) =
|
||||||
attempt!(Attempting::WhenBranch, branches(min_indent)).parse(arena, state)?;
|
attempt!(Attempting::WhenBranch, branches(min_indent)).parse(arena, state)?;
|
||||||
|
|
||||||
Ok((Expr::When(arena.alloc(loc_condition), branches), state))
|
Ok((
|
||||||
|
Expr::When(arena.alloc(loc_condition), branches.into_bump_slice()),
|
||||||
|
state,
|
||||||
|
))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1152,7 +1165,7 @@ mod when {
|
||||||
|
|
||||||
// Record this as the first branch, then optionally parse additional branches.
|
// Record this as the first branch, then optionally parse additional branches.
|
||||||
branches.push(arena.alloc(WhenBranch {
|
branches.push(arena.alloc(WhenBranch {
|
||||||
patterns: loc_first_patterns,
|
patterns: loc_first_patterns.into_bump_slice(),
|
||||||
value: loc_first_expr,
|
value: loc_first_expr,
|
||||||
guard: loc_first_guard,
|
guard: loc_first_guard,
|
||||||
}));
|
}));
|
||||||
|
@ -1173,10 +1186,13 @@ mod when {
|
||||||
),
|
),
|
||||||
branch_result(indented_more)
|
branch_result(indented_more)
|
||||||
),
|
),
|
||||||
|((patterns, guard), expr)| WhenBranch {
|
|((patterns, guard), expr)| {
|
||||||
patterns,
|
let patterns: Vec<'a, _> = patterns;
|
||||||
value: expr,
|
WhenBranch {
|
||||||
guard
|
patterns: patterns.into_bump_slice(),
|
||||||
|
value: expr,
|
||||||
|
guard,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1444,7 +1460,11 @@ fn ident_etc<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
Expr::Apply(arena.alloc(loc_expr), allocated_args, CalledVia::Space),
|
Expr::Apply(
|
||||||
|
arena.alloc(loc_expr),
|
||||||
|
allocated_args.into_bump_slice(),
|
||||||
|
CalledVia::Space,
|
||||||
|
),
|
||||||
state,
|
state,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -1638,7 +1658,7 @@ pub fn list_literal<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
|
||||||
allocated.push(&*arena.alloc(parsed_elem));
|
allocated.push(&*arena.alloc(parsed_elem));
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::List(allocated)
|
Expr::List(allocated.into_bump_slice())
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1663,7 +1683,7 @@ pub fn record_literal<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
|
||||||
// This is a record literal, not a destructure.
|
// This is a record literal, not a destructure.
|
||||||
let mut value = Expr::Record {
|
let mut value = Expr::Record {
|
||||||
update: opt_update.map(|loc_expr| &*arena.alloc(loc_expr)),
|
update: opt_update.map(|loc_expr| &*arena.alloc(loc_expr)),
|
||||||
fields: loc_assigned_fields.value,
|
fields: loc_assigned_fields.value.into_bump_slice(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// there can be field access, e.g. `{ x : 4 }.x`
|
// there can be field access, e.g. `{ x : 4 }.x`
|
||||||
|
|
|
@ -54,8 +54,8 @@ mod test_parse {
|
||||||
fn assert_segments<E: Fn(&Bump) -> Vec<'_, ast::StrSegment<'_>>>(input: &str, to_expected: E) {
|
fn assert_segments<E: Fn(&Bump) -> Vec<'_, ast::StrSegment<'_>>>(input: &str, to_expected: E) {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let actual = parse_with(&arena, arena.alloc(input));
|
let actual = parse_with(&arena, arena.alloc(input));
|
||||||
let expected_slice = to_expected(&arena).into_bump_slice();
|
let expected_slice = to_expected(&arena);
|
||||||
let expected_expr = Expr::Str(Line(expected_slice));
|
let expected_expr = Expr::Str(Line(&expected_slice));
|
||||||
|
|
||||||
assert_eq!(Ok(expected_expr), actual);
|
assert_eq!(Ok(expected_expr), actual);
|
||||||
}
|
}
|
||||||
|
@ -78,8 +78,8 @@ mod test_parse {
|
||||||
("\\\"", EscapedChar::Quote),
|
("\\\"", EscapedChar::Quote),
|
||||||
] {
|
] {
|
||||||
let actual = parse_with(&arena, arena.alloc(to_input(string)));
|
let actual = parse_with(&arena, arena.alloc(to_input(string)));
|
||||||
let expected_slice = to_expected(*escaped, &arena).into_bump_slice();
|
let expected_slice = to_expected(*escaped, &arena);
|
||||||
let expected_expr = Expr::Str(Line(expected_slice));
|
let expected_expr = Expr::Str(Line(&expected_slice));
|
||||||
|
|
||||||
assert_eq!(Ok(expected_expr), actual);
|
assert_eq!(Ok(expected_expr), actual);
|
||||||
}
|
}
|
||||||
|
@ -420,7 +420,7 @@ mod test_parse {
|
||||||
fn empty_record() {
|
fn empty_record() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let expected = Record {
|
let expected = Record {
|
||||||
fields: Vec::new_in(&arena),
|
fields: &[],
|
||||||
update: None,
|
update: None,
|
||||||
};
|
};
|
||||||
let actual = parse_with(&arena, "{}");
|
let actual = parse_with(&arena, "{}");
|
||||||
|
@ -441,9 +441,9 @@ mod test_parse {
|
||||||
&[],
|
&[],
|
||||||
arena.alloc(Located::new(0, 0, 25, 26, Num("0"))),
|
arena.alloc(Located::new(0, 0, 25, 26, Num("0"))),
|
||||||
);
|
);
|
||||||
let fields = bumpalo::vec![in &arena;
|
let fields = &[
|
||||||
Located::new(0, 0, 16, 20, label1),
|
Located::new(0, 0, 16, 20, label1),
|
||||||
Located::new(0, 0, 22, 26, label2)
|
Located::new(0, 0, 22, 26, label2),
|
||||||
];
|
];
|
||||||
let var = Var {
|
let var = Var {
|
||||||
module_name: "Foo.Bar",
|
module_name: "Foo.Bar",
|
||||||
|
@ -565,10 +565,7 @@ mod test_parse {
|
||||||
#[test]
|
#[test]
|
||||||
fn newline_before_add() {
|
fn newline_before_add() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let spaced_int = Expr::SpaceAfter(
|
let spaced_int = Expr::SpaceAfter(arena.alloc(Num("3")), &[Newline]);
|
||||||
arena.alloc(Num("3")),
|
|
||||||
bumpalo::vec![in &arena; Newline].into_bump_slice(),
|
|
||||||
);
|
|
||||||
let tuple = arena.alloc((
|
let tuple = arena.alloc((
|
||||||
Located::new(0, 0, 0, 1, spaced_int),
|
Located::new(0, 0, 0, 1, spaced_int),
|
||||||
Located::new(1, 1, 0, 1, Plus),
|
Located::new(1, 1, 0, 1, Plus),
|
||||||
|
@ -583,10 +580,7 @@ mod test_parse {
|
||||||
#[test]
|
#[test]
|
||||||
fn newline_before_sub() {
|
fn newline_before_sub() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let spaced_int = Expr::SpaceAfter(
|
let spaced_int = Expr::SpaceAfter(arena.alloc(Num("3")), &[Newline]);
|
||||||
arena.alloc(Num("3")),
|
|
||||||
bumpalo::vec![in &arena; Newline].into_bump_slice(),
|
|
||||||
);
|
|
||||||
let tuple = arena.alloc((
|
let tuple = arena.alloc((
|
||||||
Located::new(0, 0, 0, 1, spaced_int),
|
Located::new(0, 0, 0, 1, spaced_int),
|
||||||
Located::new(1, 1, 0, 1, Minus),
|
Located::new(1, 1, 0, 1, Minus),
|
||||||
|
@ -601,9 +595,7 @@ mod test_parse {
|
||||||
#[test]
|
#[test]
|
||||||
fn newline_after_mul() {
|
fn newline_after_mul() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let spaced_int = arena
|
let spaced_int = arena.alloc(Num("4")).before(&[Newline]);
|
||||||
.alloc(Num("4"))
|
|
||||||
.before(bumpalo::vec![in &arena; Newline].into_bump_slice());
|
|
||||||
let tuple = arena.alloc((
|
let tuple = arena.alloc((
|
||||||
Located::new(0, 0, 0, 1, Num("3")),
|
Located::new(0, 0, 0, 1, Num("3")),
|
||||||
Located::new(0, 0, 3, 4, Star),
|
Located::new(0, 0, 3, 4, Star),
|
||||||
|
@ -618,9 +610,7 @@ mod test_parse {
|
||||||
#[test]
|
#[test]
|
||||||
fn newline_after_sub() {
|
fn newline_after_sub() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let spaced_int = arena
|
let spaced_int = arena.alloc(Num("4")).before(&[Newline]);
|
||||||
.alloc(Num("4"))
|
|
||||||
.before(bumpalo::vec![in &arena; Newline].into_bump_slice());
|
|
||||||
let tuple = arena.alloc((
|
let tuple = arena.alloc((
|
||||||
Located::new(0, 0, 0, 1, Num("3")),
|
Located::new(0, 0, 0, 1, Num("3")),
|
||||||
Located::new(0, 0, 3, 4, Minus),
|
Located::new(0, 0, 3, 4, Minus),
|
||||||
|
@ -635,9 +625,7 @@ mod test_parse {
|
||||||
#[test]
|
#[test]
|
||||||
fn comment_with_non_ascii() {
|
fn comment_with_non_ascii() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let spaced_int = arena
|
let spaced_int = arena.alloc(Num("3")).after(&[LineComment(" 2 × 2")]);
|
||||||
.alloc(Num("3"))
|
|
||||||
.after(bumpalo::vec![in &arena; LineComment(" 2 × 2")].into_bump_slice());
|
|
||||||
let tuple = arena.alloc((
|
let tuple = arena.alloc((
|
||||||
Located::new(0, 0, 0, 1, spaced_int),
|
Located::new(0, 0, 0, 1, spaced_int),
|
||||||
Located::new(1, 1, 0, 1, Plus),
|
Located::new(1, 1, 0, 1, Plus),
|
||||||
|
@ -652,9 +640,7 @@ mod test_parse {
|
||||||
#[test]
|
#[test]
|
||||||
fn comment_before_op() {
|
fn comment_before_op() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let spaced_int = arena
|
let spaced_int = arena.alloc(Num("3")).after(&[LineComment(" test!")]);
|
||||||
.alloc(Num("3"))
|
|
||||||
.after(bumpalo::vec![in &arena; LineComment(" test!")].into_bump_slice());
|
|
||||||
let tuple = arena.alloc((
|
let tuple = arena.alloc((
|
||||||
Located::new(0, 0, 0, 1, spaced_int),
|
Located::new(0, 0, 0, 1, spaced_int),
|
||||||
Located::new(1, 1, 0, 1, Plus),
|
Located::new(1, 1, 0, 1, Plus),
|
||||||
|
@ -669,9 +655,7 @@ mod test_parse {
|
||||||
#[test]
|
#[test]
|
||||||
fn comment_after_op() {
|
fn comment_after_op() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let spaced_int = arena
|
let spaced_int = arena.alloc(Num("92")).before(&[LineComment(" test!")]);
|
||||||
.alloc(Num("92"))
|
|
||||||
.before(bumpalo::vec![in &arena; LineComment(" test!")].into_bump_slice());
|
|
||||||
let tuple = arena.alloc((
|
let tuple = arena.alloc((
|
||||||
Located::new(0, 0, 0, 2, Num("12")),
|
Located::new(0, 0, 0, 2, Num("12")),
|
||||||
Located::new(0, 0, 4, 5, Star),
|
Located::new(0, 0, 4, 5, Star),
|
||||||
|
@ -686,12 +670,8 @@ mod test_parse {
|
||||||
#[test]
|
#[test]
|
||||||
fn ops_with_newlines() {
|
fn ops_with_newlines() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let spaced_int1 = arena
|
let spaced_int1 = arena.alloc(Num("3")).after(&[Newline]);
|
||||||
.alloc(Num("3"))
|
let spaced_int2 = arena.alloc(Num("4")).before(&[Newline, Newline]);
|
||||||
.after(bumpalo::vec![in &arena; Newline].into_bump_slice());
|
|
||||||
let spaced_int2 = arena
|
|
||||||
.alloc(Num("4"))
|
|
||||||
.before(bumpalo::vec![in &arena; Newline, Newline].into_bump_slice());
|
|
||||||
let tuple = arena.alloc((
|
let tuple = arena.alloc((
|
||||||
Located::new(0, 0, 0, 1, spaced_int1),
|
Located::new(0, 0, 0, 1, spaced_int1),
|
||||||
Located::new(1, 1, 0, 1, Plus),
|
Located::new(1, 1, 0, 1, Plus),
|
||||||
|
@ -881,7 +861,7 @@ mod test_parse {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let arg1 = arena.alloc(Located::new(0, 0, 6, 8, Num("12")));
|
let arg1 = arena.alloc(Located::new(0, 0, 6, 8, Num("12")));
|
||||||
let arg2 = arena.alloc(Located::new(0, 0, 9, 11, Num("34")));
|
let arg2 = arena.alloc(Located::new(0, 0, 9, 11, Num("34")));
|
||||||
let args = bumpalo::vec![in &arena; &*arg1, &*arg2];
|
let args = &[&*arg1, &*arg2];
|
||||||
let expected = Expr::Apply(
|
let expected = Expr::Apply(
|
||||||
arena.alloc(Located::new(0, 0, 0, 5, Expr::PrivateTag("@Whee"))),
|
arena.alloc(Located::new(0, 0, 0, 5, Expr::PrivateTag("@Whee"))),
|
||||||
args,
|
args,
|
||||||
|
@ -897,7 +877,7 @@ mod test_parse {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let arg1 = arena.alloc(Located::new(0, 0, 5, 7, Num("12")));
|
let arg1 = arena.alloc(Located::new(0, 0, 5, 7, Num("12")));
|
||||||
let arg2 = arena.alloc(Located::new(0, 0, 8, 10, Num("34")));
|
let arg2 = arena.alloc(Located::new(0, 0, 8, 10, Num("34")));
|
||||||
let args = bumpalo::vec![in &arena; &*arg1, &*arg2];
|
let args = &[&*arg1, &*arg2];
|
||||||
let expected = Expr::Apply(
|
let expected = Expr::Apply(
|
||||||
arena.alloc(Located::new(0, 0, 0, 4, Expr::GlobalTag("Whee"))),
|
arena.alloc(Located::new(0, 0, 0, 4, Expr::GlobalTag("Whee"))),
|
||||||
args,
|
args,
|
||||||
|
@ -915,7 +895,7 @@ mod test_parse {
|
||||||
let int2 = ParensAround(arena.alloc(Num("34")));
|
let int2 = ParensAround(arena.alloc(Num("34")));
|
||||||
let arg1 = arena.alloc(Located::new(0, 0, 6, 8, int1));
|
let arg1 = arena.alloc(Located::new(0, 0, 6, 8, int1));
|
||||||
let arg2 = arena.alloc(Located::new(0, 0, 11, 13, int2));
|
let arg2 = arena.alloc(Located::new(0, 0, 11, 13, int2));
|
||||||
let args = bumpalo::vec![in &arena; &*arg1, &*arg2];
|
let args = &[&*arg1, &*arg2];
|
||||||
let expected = Expr::Apply(
|
let expected = Expr::Apply(
|
||||||
arena.alloc(Located::new(0, 0, 0, 4, Expr::GlobalTag("Whee"))),
|
arena.alloc(Located::new(0, 0, 0, 4, Expr::GlobalTag("Whee"))),
|
||||||
args,
|
args,
|
||||||
|
@ -949,11 +929,8 @@ mod test_parse {
|
||||||
fn tag_pattern() {
|
fn tag_pattern() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let pattern = Located::new(0, 0, 1, 6, Pattern::GlobalTag("Thing"));
|
let pattern = Located::new(0, 0, 1, 6, Pattern::GlobalTag("Thing"));
|
||||||
let patterns = bumpalo::vec![in &arena; pattern];
|
let patterns = &[pattern];
|
||||||
let expected = Closure(
|
let expected = Closure(patterns, arena.alloc(Located::new(0, 0, 10, 12, Num("42"))));
|
||||||
arena.alloc(patterns),
|
|
||||||
arena.alloc(Located::new(0, 0, 10, 12, Num("42"))),
|
|
||||||
);
|
|
||||||
let actual = parse_with(&arena, "\\Thing -> 42");
|
let actual = parse_with(&arena, "\\Thing -> 42");
|
||||||
|
|
||||||
assert_eq!(Ok(expected), actual);
|
assert_eq!(Ok(expected), actual);
|
||||||
|
@ -973,7 +950,7 @@ mod test_parse {
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_list() {
|
fn empty_list() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let elems = Vec::new_in(&arena);
|
let elems = &[];
|
||||||
let expected = List(elems);
|
let expected = List(elems);
|
||||||
let actual = parse_with(&arena, "[]");
|
let actual = parse_with(&arena, "[]");
|
||||||
|
|
||||||
|
@ -984,7 +961,7 @@ mod test_parse {
|
||||||
fn spaces_inside_empty_list() {
|
fn spaces_inside_empty_list() {
|
||||||
// This is a regression test!
|
// This is a regression test!
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let elems = Vec::new_in(&arena);
|
let elems = &[];
|
||||||
let expected = List(elems);
|
let expected = List(elems);
|
||||||
let actual = parse_with(&arena, "[ ]");
|
let actual = parse_with(&arena, "[ ]");
|
||||||
|
|
||||||
|
@ -994,7 +971,7 @@ mod test_parse {
|
||||||
#[test]
|
#[test]
|
||||||
fn packed_singleton_list() {
|
fn packed_singleton_list() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let elems = bumpalo::vec![in &arena; &*arena.alloc(Located::new(0, 0, 1, 2, Num("1")))];
|
let elems = &[&*arena.alloc(Located::new(0, 0, 1, 2, Num("1")))];
|
||||||
let expected = List(elems);
|
let expected = List(elems);
|
||||||
let actual = parse_with(&arena, "[1]");
|
let actual = parse_with(&arena, "[1]");
|
||||||
|
|
||||||
|
@ -1004,7 +981,7 @@ mod test_parse {
|
||||||
#[test]
|
#[test]
|
||||||
fn spaced_singleton_list() {
|
fn spaced_singleton_list() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let elems = bumpalo::vec![in &arena; &*arena.alloc(Located::new(0, 0, 2, 3, Num("1")))];
|
let elems = &[&*arena.alloc(Located::new(0, 0, 2, 3, Num("1")))];
|
||||||
let expected = List(elems);
|
let expected = List(elems);
|
||||||
let actual = parse_with(&arena, "[ 1 ]");
|
let actual = parse_with(&arena, "[ 1 ]");
|
||||||
|
|
||||||
|
@ -1090,7 +1067,7 @@ mod test_parse {
|
||||||
fn basic_apply() {
|
fn basic_apply() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let arg = arena.alloc(Located::new(0, 0, 5, 6, Num("1")));
|
let arg = arena.alloc(Located::new(0, 0, 5, 6, Num("1")));
|
||||||
let args = bumpalo::vec![in &arena; &*arg];
|
let args = &[&*arg];
|
||||||
let expr = Var {
|
let expr = Var {
|
||||||
module_name: "",
|
module_name: "",
|
||||||
ident: "whee",
|
ident: "whee",
|
||||||
|
@ -1110,7 +1087,7 @@ mod test_parse {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let arg1 = arena.alloc(Located::new(0, 0, 6, 8, Num("12")));
|
let arg1 = arena.alloc(Located::new(0, 0, 6, 8, Num("12")));
|
||||||
let arg2 = arena.alloc(Located::new(0, 0, 10, 12, Num("34")));
|
let arg2 = arena.alloc(Located::new(0, 0, 10, 12, Num("34")));
|
||||||
let args = bumpalo::vec![in &arena; &*arg1, &*arg2];
|
let args = &[&*arg1, &*arg2];
|
||||||
let expected = Expr::Apply(
|
let expected = Expr::Apply(
|
||||||
arena.alloc(Located::new(
|
arena.alloc(Located::new(
|
||||||
0,
|
0,
|
||||||
|
@ -1163,7 +1140,7 @@ mod test_parse {
|
||||||
ident: "d",
|
ident: "d",
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
let args = bumpalo::vec![in &arena; &*arg1, &*arg2, &*arg3];
|
let args = &[&*arg1, &*arg2, &*arg3];
|
||||||
let expected = Expr::Apply(
|
let expected = Expr::Apply(
|
||||||
arena.alloc(Located::new(
|
arena.alloc(Located::new(
|
||||||
0,
|
0,
|
||||||
|
@ -1187,7 +1164,7 @@ mod test_parse {
|
||||||
fn parenthetical_apply() {
|
fn parenthetical_apply() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let arg = arena.alloc(Located::new(0, 0, 7, 8, Num("1")));
|
let arg = arena.alloc(Located::new(0, 0, 7, 8, Num("1")));
|
||||||
let args = bumpalo::vec![in &arena; &*arg];
|
let args = &[&*arg];
|
||||||
let parens_var = Expr::ParensAround(arena.alloc(Var {
|
let parens_var = Expr::ParensAround(arena.alloc(Var {
|
||||||
module_name: "",
|
module_name: "",
|
||||||
ident: "whee",
|
ident: "whee",
|
||||||
|
@ -1249,7 +1226,7 @@ mod test_parse {
|
||||||
ident: "foo",
|
ident: "foo",
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
let args = bumpalo::vec![in &arena; &*arg1, &*arg2];
|
let args = &[&*arg1, &*arg2];
|
||||||
let apply_expr = Expr::Apply(
|
let apply_expr = Expr::Apply(
|
||||||
arena.alloc(Located::new(
|
arena.alloc(Located::new(
|
||||||
0,
|
0,
|
||||||
|
@ -1285,7 +1262,7 @@ mod test_parse {
|
||||||
ident: "foo",
|
ident: "foo",
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
let args = bumpalo::vec![in &arena; &*arg1, &*arg2];
|
let args = &[&*arg1, &*arg2];
|
||||||
let apply_expr = Expr::Apply(
|
let apply_expr = Expr::Apply(
|
||||||
arena.alloc(Located::new(
|
arena.alloc(Located::new(
|
||||||
0,
|
0,
|
||||||
|
@ -1321,7 +1298,7 @@ mod test_parse {
|
||||||
ident: "foo",
|
ident: "foo",
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
let args = bumpalo::vec![in &arena; &*arg1, &*arg2];
|
let args = &[&*arg1, &*arg2];
|
||||||
let apply_expr = Expr::ParensAround(arena.alloc(Expr::Apply(
|
let apply_expr = Expr::ParensAround(arena.alloc(Expr::Apply(
|
||||||
arena.alloc(Located::new(
|
arena.alloc(Located::new(
|
||||||
0,
|
0,
|
||||||
|
@ -1357,7 +1334,7 @@ mod test_parse {
|
||||||
ident: "foo",
|
ident: "foo",
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
let args = bumpalo::vec![in &arena; &*arg1, &*arg2];
|
let args = &[&*arg1, &*arg2];
|
||||||
let apply_expr = Expr::ParensAround(arena.alloc(Expr::Apply(
|
let apply_expr = Expr::ParensAround(arena.alloc(Expr::Apply(
|
||||||
arena.alloc(Located::new(
|
arena.alloc(Located::new(
|
||||||
0,
|
0,
|
||||||
|
@ -1390,7 +1367,7 @@ mod test_parse {
|
||||||
let loc_arg1_expr = Located::new(0, 0, 10, 13, var1);
|
let loc_arg1_expr = Located::new(0, 0, 10, 13, var1);
|
||||||
let arg_op = UnaryOp(arena.alloc(loc_arg1_expr), loc_op);
|
let arg_op = UnaryOp(arena.alloc(loc_arg1_expr), loc_op);
|
||||||
let arg2 = arena.alloc(Located::new(0, 0, 9, 13, arg_op));
|
let arg2 = arena.alloc(Located::new(0, 0, 9, 13, arg_op));
|
||||||
let args = bumpalo::vec![in &arena; &*arg1, &*arg2];
|
let args = &[&*arg1, &*arg2];
|
||||||
let var2 = Var {
|
let var2 = Var {
|
||||||
module_name: "",
|
module_name: "",
|
||||||
ident: "whee",
|
ident: "whee",
|
||||||
|
@ -1428,11 +1405,8 @@ mod test_parse {
|
||||||
fn single_arg_closure() {
|
fn single_arg_closure() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let pattern = Located::new(0, 0, 1, 2, Identifier("a"));
|
let pattern = Located::new(0, 0, 1, 2, Identifier("a"));
|
||||||
let patterns = bumpalo::vec![in &arena; pattern];
|
let patterns = &[pattern];
|
||||||
let expected = Closure(
|
let expected = Closure(patterns, arena.alloc(Located::new(0, 0, 6, 8, Num("42"))));
|
||||||
arena.alloc(patterns),
|
|
||||||
arena.alloc(Located::new(0, 0, 6, 8, Num("42"))),
|
|
||||||
);
|
|
||||||
let actual = parse_with(&arena, "\\a -> 42");
|
let actual = parse_with(&arena, "\\a -> 42");
|
||||||
|
|
||||||
assert_eq!(Ok(expected), actual);
|
assert_eq!(Ok(expected), actual);
|
||||||
|
@ -1442,11 +1416,8 @@ mod test_parse {
|
||||||
fn single_underscore_closure() {
|
fn single_underscore_closure() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let pattern = Located::new(0, 0, 1, 2, Underscore);
|
let pattern = Located::new(0, 0, 1, 2, Underscore);
|
||||||
let patterns = bumpalo::vec![in &arena; pattern];
|
let patterns = &[pattern];
|
||||||
let expected = Closure(
|
let expected = Closure(patterns, arena.alloc(Located::new(0, 0, 6, 8, Num("42"))));
|
||||||
arena.alloc(patterns),
|
|
||||||
arena.alloc(Located::new(0, 0, 6, 8, Num("42"))),
|
|
||||||
);
|
|
||||||
let actual = parse_with(&arena, "\\_ -> 42");
|
let actual = parse_with(&arena, "\\_ -> 42");
|
||||||
|
|
||||||
assert_eq!(Ok(expected), actual);
|
assert_eq!(Ok(expected), actual);
|
||||||
|
@ -1468,11 +1439,8 @@ mod test_parse {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let arg1 = Located::new(0, 0, 1, 2, Identifier("a"));
|
let arg1 = Located::new(0, 0, 1, 2, Identifier("a"));
|
||||||
let arg2 = Located::new(0, 0, 4, 5, Identifier("b"));
|
let arg2 = Located::new(0, 0, 4, 5, Identifier("b"));
|
||||||
let patterns = bumpalo::vec![in &arena; arg1, arg2];
|
let patterns = &[arg1, arg2];
|
||||||
let expected = Closure(
|
let expected = Closure(patterns, arena.alloc(Located::new(0, 0, 9, 11, Num("42"))));
|
||||||
arena.alloc(patterns),
|
|
||||||
arena.alloc(Located::new(0, 0, 9, 11, Num("42"))),
|
|
||||||
);
|
|
||||||
let actual = parse_with(&arena, "\\a, b -> 42");
|
let actual = parse_with(&arena, "\\a, b -> 42");
|
||||||
|
|
||||||
assert_eq!(Ok(expected), actual);
|
assert_eq!(Ok(expected), actual);
|
||||||
|
@ -1520,7 +1488,7 @@ mod test_parse {
|
||||||
arena.alloc(Located::new(1, 1, 2, 3, Num("5"))),
|
arena.alloc(Located::new(1, 1, 2, 3, Num("5"))),
|
||||||
);
|
);
|
||||||
let loc_def = &*arena.alloc(Located::new(1, 1, 0, 1, def));
|
let loc_def = &*arena.alloc(Located::new(1, 1, 0, 1, def));
|
||||||
let defs = bumpalo::vec![in &arena; loc_def];
|
let defs = &[loc_def];
|
||||||
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
||||||
let loc_ret = Located::new(3, 3, 0, 2, ret);
|
let loc_ret = Located::new(3, 3, 0, 2, ret);
|
||||||
let reset_indentation = bumpalo::vec![in &arena; LineComment(" leading comment")];
|
let reset_indentation = bumpalo::vec![in &arena; LineComment(" leading comment")];
|
||||||
|
@ -1550,7 +1518,7 @@ mod test_parse {
|
||||||
arena.alloc(Located::new(1, 1, 4, 5, Num("5"))),
|
arena.alloc(Located::new(1, 1, 4, 5, Num("5"))),
|
||||||
);
|
);
|
||||||
let loc_def = &*arena.alloc(Located::new(1, 1, 0, 1, def));
|
let loc_def = &*arena.alloc(Located::new(1, 1, 0, 1, def));
|
||||||
let defs = bumpalo::vec![in &arena; loc_def];
|
let defs = &[loc_def];
|
||||||
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
||||||
let loc_ret = Located::new(3, 3, 0, 2, ret);
|
let loc_ret = Located::new(3, 3, 0, 2, ret);
|
||||||
let reset_indentation = bumpalo::vec![in &arena; LineComment(" leading comment")];
|
let reset_indentation = bumpalo::vec![in &arena; LineComment(" leading comment")];
|
||||||
|
@ -1589,7 +1557,7 @@ mod test_parse {
|
||||||
newline.into_bump_slice(),
|
newline.into_bump_slice(),
|
||||||
);
|
);
|
||||||
let loc_def2 = &*arena.alloc(Located::new(2, 2, 0, 5, def2));
|
let loc_def2 = &*arena.alloc(Located::new(2, 2, 0, 5, def2));
|
||||||
let defs = bumpalo::vec![in &arena; loc_def1, loc_def2];
|
let defs = &[loc_def1, loc_def2];
|
||||||
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
||||||
let loc_ret = Located::new(4, 4, 0, 2, ret);
|
let loc_ret = Located::new(4, 4, 0, 2, ret);
|
||||||
let reset_indentation = bumpalo::vec![in &arena; LineComment(" leading comment")];
|
let reset_indentation = bumpalo::vec![in &arena; LineComment(" leading comment")];
|
||||||
|
@ -1621,13 +1589,7 @@ mod test_parse {
|
||||||
Located::new(1, 1, 5, 7, Identifier("y"))
|
Located::new(1, 1, 5, 7, Identifier("y"))
|
||||||
];
|
];
|
||||||
let def1 = Def::Body(
|
let def1 = Def::Body(
|
||||||
arena.alloc(Located::new(
|
arena.alloc(Located::new(1, 1, 1, 8, RecordDestructure(&fields))),
|
||||||
1,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
8,
|
|
||||||
RecordDestructure(fields.into_bump_slice()),
|
|
||||||
)),
|
|
||||||
arena.alloc(Located::new(1, 1, 11, 12, Num("5"))),
|
arena.alloc(Located::new(1, 1, 11, 12, Num("5"))),
|
||||||
);
|
);
|
||||||
let loc_def1 = &*arena.alloc(Located::new(1, 1, 1, 8, def1));
|
let loc_def1 = &*arena.alloc(Located::new(1, 1, 1, 8, def1));
|
||||||
|
@ -1636,16 +1598,16 @@ mod test_parse {
|
||||||
arena.alloc(Located::new(2, 2, 0, 1, Identifier("y"))),
|
arena.alloc(Located::new(2, 2, 0, 1, Identifier("y"))),
|
||||||
arena.alloc(Located::new(2, 2, 4, 5, Num("6"))),
|
arena.alloc(Located::new(2, 2, 4, 5, Num("6"))),
|
||||||
)),
|
)),
|
||||||
newline.into_bump_slice(),
|
&newline,
|
||||||
);
|
);
|
||||||
let loc_def2 = &*arena.alloc(Located::new(2, 2, 0, 5, def2));
|
let loc_def2 = &*arena.alloc(Located::new(2, 2, 0, 5, def2));
|
||||||
let defs = bumpalo::vec![in &arena; loc_def1, loc_def2 ];
|
let defs = &[loc_def1, loc_def2];
|
||||||
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), &newlines);
|
||||||
let loc_ret = Located::new(4, 4, 0, 2, ret);
|
let loc_ret = Located::new(4, 4, 0, 2, ret);
|
||||||
let reset_indentation = bumpalo::vec![in &arena; LineComment(" leading comment")];
|
let reset_indentation = bumpalo::vec![in &arena; LineComment(" leading comment")];
|
||||||
let expected = Expr::SpaceBefore(
|
let expected = Expr::SpaceBefore(
|
||||||
arena.alloc(Defs(defs, arena.alloc(loc_ret))),
|
arena.alloc(Defs(defs, arena.alloc(loc_ret))),
|
||||||
reset_indentation.into_bump_slice(),
|
&reset_indentation,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_parses_to(
|
assert_parses_to(
|
||||||
|
@ -1675,12 +1637,12 @@ mod test_parse {
|
||||||
arena.alloc(Located::new(1, 1, 0, 3, Identifier("foo"))),
|
arena.alloc(Located::new(1, 1, 0, 3, Identifier("foo"))),
|
||||||
arena.alloc(Located::new(1, 1, 6, 7, Num("4"))),
|
arena.alloc(Located::new(1, 1, 6, 7, Num("4"))),
|
||||||
);
|
);
|
||||||
let spaced_def = Def::SpaceBefore(arena.alloc(def), newline.into_bump_slice());
|
let spaced_def = Def::SpaceBefore(arena.alloc(def), &newline);
|
||||||
let loc_def = &*arena.alloc(Located::new(1, 1, 0, 7, spaced_def));
|
let loc_def = &*arena.alloc(Located::new(1, 1, 0, 7, spaced_def));
|
||||||
|
|
||||||
let loc_ann = &*arena.alloc(Located::new(0, 0, 0, 3, signature));
|
let loc_ann = &*arena.alloc(Located::new(0, 0, 0, 3, signature));
|
||||||
let defs = bumpalo::vec![in &arena; loc_ann, loc_def];
|
let defs = &[loc_ann, loc_def];
|
||||||
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), &newlines);
|
||||||
let loc_ret = Located::new(3, 3, 0, 2, ret);
|
let loc_ret = Located::new(3, 3, 0, 2, ret);
|
||||||
let expected = Defs(defs, arena.alloc(loc_ret));
|
let expected = Defs(defs, arena.alloc(loc_ret));
|
||||||
|
|
||||||
|
@ -1719,7 +1681,7 @@ mod test_parse {
|
||||||
);
|
);
|
||||||
|
|
||||||
let loc_ann = &*arena.alloc(Located::new(0, 0, 0, 3, signature));
|
let loc_ann = &*arena.alloc(Located::new(0, 0, 0, 3, signature));
|
||||||
let defs = bumpalo::vec![in &arena; loc_ann];
|
let defs = &[loc_ann];
|
||||||
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
||||||
let loc_ret = Located::new(2, 2, 0, 2, ret);
|
let loc_ret = Located::new(2, 2, 0, 2, ret);
|
||||||
let expected = Defs(defs, arena.alloc(loc_ret));
|
let expected = Defs(defs, arena.alloc(loc_ret));
|
||||||
|
@ -1755,7 +1717,7 @@ mod test_parse {
|
||||||
};
|
};
|
||||||
|
|
||||||
let loc_ann = &*arena.alloc(Located::new(0, 0, 0, 4, signature));
|
let loc_ann = &*arena.alloc(Located::new(0, 0, 0, 4, signature));
|
||||||
let defs = bumpalo::vec![in &arena; loc_ann];
|
let defs = &[loc_ann];
|
||||||
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
||||||
let loc_ret = Located::new(2, 2, 0, 2, ret);
|
let loc_ret = Located::new(2, 2, 0, 2, ret);
|
||||||
let expected = Defs(defs, arena.alloc(loc_ret));
|
let expected = Defs(defs, arena.alloc(loc_ret));
|
||||||
|
@ -1810,7 +1772,7 @@ mod test_parse {
|
||||||
let loc_def = &*arena.alloc(Located::new(1, 1, 0, 17, spaced));
|
let loc_def = &*arena.alloc(Located::new(1, 1, 0, 17, spaced));
|
||||||
|
|
||||||
let loc_ann = &*arena.alloc(Located::new(0, 0, 0, 3, signature));
|
let loc_ann = &*arena.alloc(Located::new(0, 0, 0, 3, signature));
|
||||||
let defs = bumpalo::vec![in &arena; loc_ann, loc_def];
|
let defs = &[loc_ann, loc_def];
|
||||||
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
||||||
let loc_ret = Located::new(3, 3, 0, 2, ret);
|
let loc_ret = Located::new(3, 3, 0, 2, ret);
|
||||||
let expected = Defs(defs, arena.alloc(loc_ret));
|
let expected = Defs(defs, arena.alloc(loc_ret));
|
||||||
|
@ -1865,7 +1827,7 @@ mod test_parse {
|
||||||
let loc_def = &*arena.alloc(Located::new(1, 1, 0, 10, spaced_def));
|
let loc_def = &*arena.alloc(Located::new(1, 1, 0, 10, spaced_def));
|
||||||
|
|
||||||
let loc_ann = &*arena.alloc(Located::new(0, 0, 0, 3, signature));
|
let loc_ann = &*arena.alloc(Located::new(0, 0, 0, 3, signature));
|
||||||
let defs = bumpalo::vec![in &arena; loc_ann, loc_def];
|
let defs = &[loc_ann, loc_def];
|
||||||
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
||||||
let loc_ret = Located::new(3, 3, 0, 2, ret);
|
let loc_ret = Located::new(3, 3, 0, 2, ret);
|
||||||
let expected = Defs(defs, arena.alloc(loc_ret));
|
let expected = Defs(defs, arena.alloc(loc_ret));
|
||||||
|
@ -1918,7 +1880,7 @@ mod test_parse {
|
||||||
let loc_def = &*arena.alloc(Located::new(1, 1, 0, 10, spaced_def));
|
let loc_def = &*arena.alloc(Located::new(1, 1, 0, 10, spaced_def));
|
||||||
|
|
||||||
let loc_ann = &*arena.alloc(Located::new(0, 0, 0, 3, signature));
|
let loc_ann = &*arena.alloc(Located::new(0, 0, 0, 3, signature));
|
||||||
let defs = bumpalo::vec![in &arena; loc_ann, loc_def];
|
let defs = &[loc_ann, loc_def];
|
||||||
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
||||||
let loc_ret = Located::new(3, 3, 0, 2, ret);
|
let loc_ret = Located::new(3, 3, 0, 2, ret);
|
||||||
let expected = Defs(defs, arena.alloc(loc_ret));
|
let expected = Defs(defs, arena.alloc(loc_ret));
|
||||||
|
@ -1972,7 +1934,7 @@ mod test_parse {
|
||||||
let loc_def = &*arena.alloc(Located::new(1, 1, 0, 10, spaced_def));
|
let loc_def = &*arena.alloc(Located::new(1, 1, 0, 10, spaced_def));
|
||||||
|
|
||||||
let loc_ann = &*arena.alloc(Located::new(0, 0, 0, 3, signature));
|
let loc_ann = &*arena.alloc(Located::new(0, 0, 0, 3, signature));
|
||||||
let defs = bumpalo::vec![in &arena; loc_ann, loc_def];
|
let defs = &[loc_ann, loc_def];
|
||||||
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
||||||
let loc_ret = Located::new(3, 3, 0, 2, ret);
|
let loc_ret = Located::new(3, 3, 0, 2, ret);
|
||||||
let expected = Defs(defs, arena.alloc(loc_ret));
|
let expected = Defs(defs, arena.alloc(loc_ret));
|
||||||
|
@ -2025,7 +1987,7 @@ mod test_parse {
|
||||||
let loc_def = &*arena.alloc(Located::new(1, 1, 0, 10, spaced_def));
|
let loc_def = &*arena.alloc(Located::new(1, 1, 0, 10, spaced_def));
|
||||||
|
|
||||||
let loc_ann = &*arena.alloc(Located::new(0, 0, 0, 3, signature));
|
let loc_ann = &*arena.alloc(Located::new(0, 0, 0, 3, signature));
|
||||||
let defs = bumpalo::vec![in &arena; loc_ann, loc_def];
|
let defs = &[loc_ann, loc_def];
|
||||||
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
||||||
let loc_ret = Located::new(3, 3, 0, 2, ret);
|
let loc_ret = Located::new(3, 3, 0, 2, ret);
|
||||||
let expected = Defs(defs, arena.alloc(loc_ret));
|
let expected = Defs(defs, arena.alloc(loc_ret));
|
||||||
|
@ -2057,24 +2019,21 @@ mod test_parse {
|
||||||
let expr1 = Num("1");
|
let expr1 = Num("1");
|
||||||
let loc_expr1 = Located::new(1, 1, 7, 8, expr1);
|
let loc_expr1 = Located::new(1, 1, 7, 8, expr1);
|
||||||
let branch1 = &*arena.alloc(WhenBranch {
|
let branch1 = &*arena.alloc(WhenBranch {
|
||||||
patterns: bumpalo::vec![in &arena;loc_pattern1],
|
patterns: arena.alloc([loc_pattern1]),
|
||||||
value: loc_expr1,
|
value: loc_expr1,
|
||||||
guard: None,
|
guard: None,
|
||||||
});
|
});
|
||||||
let newlines = bumpalo::vec![in &arena; Newline];
|
let newlines = &[Newline];
|
||||||
let pattern2 = Pattern::SpaceBefore(
|
let pattern2 = Pattern::SpaceBefore(arena.alloc(StrLiteral(PlainLine("mise"))), newlines);
|
||||||
arena.alloc(StrLiteral(PlainLine("mise"))),
|
|
||||||
newlines.into_bump_slice(),
|
|
||||||
);
|
|
||||||
let loc_pattern2 = Located::new(2, 2, 1, 7, pattern2);
|
let loc_pattern2 = Located::new(2, 2, 1, 7, pattern2);
|
||||||
let expr2 = Num("2");
|
let expr2 = Num("2");
|
||||||
let loc_expr2 = Located::new(2, 2, 11, 12, expr2);
|
let loc_expr2 = Located::new(2, 2, 11, 12, expr2);
|
||||||
let branch2 = &*arena.alloc(WhenBranch {
|
let branch2 = &*arena.alloc(WhenBranch {
|
||||||
patterns: bumpalo::vec![in &arena;loc_pattern2 ],
|
patterns: arena.alloc([loc_pattern2]),
|
||||||
value: loc_expr2,
|
value: loc_expr2,
|
||||||
guard: None,
|
guard: None,
|
||||||
});
|
});
|
||||||
let branches = bumpalo::vec![in &arena; branch1, branch2];
|
let branches = &[branch1, branch2];
|
||||||
let var = Var {
|
let var = Var {
|
||||||
module_name: "",
|
module_name: "",
|
||||||
ident: "x",
|
ident: "x",
|
||||||
|
@ -2098,29 +2057,27 @@ mod test_parse {
|
||||||
#[test]
|
#[test]
|
||||||
fn when_with_numbers() {
|
fn when_with_numbers() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let newlines = bumpalo::vec![in &arena; Newline];
|
let newlines = &[Newline];
|
||||||
let pattern1 =
|
let pattern1 = Pattern::SpaceBefore(arena.alloc(NumLiteral("1")), newlines);
|
||||||
Pattern::SpaceBefore(arena.alloc(NumLiteral("1")), newlines.into_bump_slice());
|
|
||||||
let loc_pattern1 = Located::new(1, 1, 1, 2, pattern1);
|
let loc_pattern1 = Located::new(1, 1, 1, 2, pattern1);
|
||||||
let expr1 = Num("2");
|
let expr1 = Num("2");
|
||||||
let loc_expr1 = Located::new(1, 1, 6, 7, expr1);
|
let loc_expr1 = Located::new(1, 1, 6, 7, expr1);
|
||||||
let branch1 = &*arena.alloc(WhenBranch {
|
let branch1 = &*arena.alloc(WhenBranch {
|
||||||
patterns: bumpalo::vec![in &arena;loc_pattern1],
|
patterns: arena.alloc([loc_pattern1]),
|
||||||
value: loc_expr1,
|
value: loc_expr1,
|
||||||
guard: None,
|
guard: None,
|
||||||
});
|
});
|
||||||
let newlines = bumpalo::vec![in &arena; Newline];
|
let newlines = &[Newline];
|
||||||
let pattern2 =
|
let pattern2 = Pattern::SpaceBefore(arena.alloc(NumLiteral("3")), newlines);
|
||||||
Pattern::SpaceBefore(arena.alloc(NumLiteral("3")), newlines.into_bump_slice());
|
|
||||||
let loc_pattern2 = Located::new(2, 2, 1, 2, pattern2);
|
let loc_pattern2 = Located::new(2, 2, 1, 2, pattern2);
|
||||||
let expr2 = Num("4");
|
let expr2 = Num("4");
|
||||||
let loc_expr2 = Located::new(2, 2, 6, 7, expr2);
|
let loc_expr2 = Located::new(2, 2, 6, 7, expr2);
|
||||||
let branch2 = &*arena.alloc(WhenBranch {
|
let branch2 = &*arena.alloc(WhenBranch {
|
||||||
patterns: bumpalo::vec![in &arena;loc_pattern2],
|
patterns: arena.alloc([loc_pattern2]),
|
||||||
value: loc_expr2,
|
value: loc_expr2,
|
||||||
guard: None,
|
guard: None,
|
||||||
});
|
});
|
||||||
let branches = bumpalo::vec![in &arena; branch1, branch2];
|
let branches = &[branch1, branch2];
|
||||||
let var = Var {
|
let var = Var {
|
||||||
module_name: "",
|
module_name: "",
|
||||||
ident: "x",
|
ident: "x",
|
||||||
|
@ -2144,35 +2101,32 @@ mod test_parse {
|
||||||
#[test]
|
#[test]
|
||||||
fn when_with_records() {
|
fn when_with_records() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let newlines = bumpalo::vec![in &arena; Newline];
|
let newlines = &[Newline];
|
||||||
let identifiers1 = bumpalo::vec![in &arena; Located::new(1, 1, 3, 4, Identifier("y")) ];
|
let identifiers1 = &[Located::new(1, 1, 3, 4, Identifier("y"))];
|
||||||
let pattern1 = Pattern::SpaceBefore(
|
let pattern1 = Pattern::SpaceBefore(arena.alloc(RecordDestructure(identifiers1)), newlines);
|
||||||
arena.alloc(RecordDestructure(identifiers1.into_bump_slice())),
|
|
||||||
newlines.into_bump_slice(),
|
|
||||||
);
|
|
||||||
let loc_pattern1 = Located::new(1, 1, 1, 6, pattern1);
|
let loc_pattern1 = Located::new(1, 1, 1, 6, pattern1);
|
||||||
let expr1 = Num("2");
|
let expr1 = Num("2");
|
||||||
let loc_expr1 = Located::new(1, 1, 10, 11, expr1);
|
let loc_expr1 = Located::new(1, 1, 10, 11, expr1);
|
||||||
let branch1 = &*arena.alloc(WhenBranch {
|
let branch1 = &*arena.alloc(WhenBranch {
|
||||||
patterns: bumpalo::vec![in &arena;loc_pattern1 ],
|
patterns: arena.alloc([loc_pattern1]),
|
||||||
value: loc_expr1,
|
value: loc_expr1,
|
||||||
guard: None,
|
guard: None,
|
||||||
});
|
});
|
||||||
let newlines = bumpalo::vec![in &arena; Newline];
|
let newlines = &[Newline];
|
||||||
let identifiers2 = bumpalo::vec![in &arena; Located::new(2, 2, 3, 4, Identifier("z")), Located::new(2, 2, 6, 7, Identifier("w")) ];
|
let identifiers2 = &[
|
||||||
let pattern2 = Pattern::SpaceBefore(
|
Located::new(2, 2, 3, 4, Identifier("z")),
|
||||||
arena.alloc(RecordDestructure(identifiers2.into_bump_slice())),
|
Located::new(2, 2, 6, 7, Identifier("w")),
|
||||||
newlines.into_bump_slice(),
|
];
|
||||||
);
|
let pattern2 = Pattern::SpaceBefore(arena.alloc(RecordDestructure(identifiers2)), newlines);
|
||||||
let loc_pattern2 = Located::new(2, 2, 1, 9, pattern2);
|
let loc_pattern2 = Located::new(2, 2, 1, 9, pattern2);
|
||||||
let expr2 = Num("4");
|
let expr2 = Num("4");
|
||||||
let loc_expr2 = Located::new(2, 2, 13, 14, expr2);
|
let loc_expr2 = Located::new(2, 2, 13, 14, expr2);
|
||||||
let branch2 = &*arena.alloc(WhenBranch {
|
let branch2 = &*arena.alloc(WhenBranch {
|
||||||
patterns: bumpalo::vec![in &arena;loc_pattern2 ],
|
patterns: arena.alloc([loc_pattern2]),
|
||||||
value: loc_expr2,
|
value: loc_expr2,
|
||||||
guard: None,
|
guard: None,
|
||||||
});
|
});
|
||||||
let branches = bumpalo::vec![in &arena; branch1, branch2];
|
let branches = &[branch1, branch2];
|
||||||
let var = Var {
|
let var = Var {
|
||||||
module_name: "",
|
module_name: "",
|
||||||
ident: "x",
|
ident: "x",
|
||||||
|
@ -2196,41 +2150,33 @@ mod test_parse {
|
||||||
#[test]
|
#[test]
|
||||||
fn when_with_alternative_patterns() {
|
fn when_with_alternative_patterns() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let newlines = bumpalo::vec![in &arena; Newline];
|
let newlines = &[Newline];
|
||||||
let pattern1 = Pattern::SpaceBefore(
|
let pattern1 = Pattern::SpaceBefore(arena.alloc(StrLiteral(PlainLine("blah"))), newlines);
|
||||||
arena.alloc(StrLiteral(PlainLine("blah"))),
|
|
||||||
newlines.into_bump_slice(),
|
|
||||||
);
|
|
||||||
let pattern1_alt = StrLiteral(PlainLine("blop"));
|
let pattern1_alt = StrLiteral(PlainLine("blop"));
|
||||||
let loc_pattern1 = Located::new(1, 1, 1, 7, pattern1);
|
let loc_pattern1 = Located::new(1, 1, 1, 7, pattern1);
|
||||||
let loc_pattern1_alt = Located::new(1, 1, 10, 16, pattern1_alt);
|
let loc_pattern1_alt = Located::new(1, 1, 10, 16, pattern1_alt);
|
||||||
let expr1 = Num("1");
|
let expr1 = Num("1");
|
||||||
let loc_expr1 = Located::new(1, 1, 20, 21, expr1);
|
let loc_expr1 = Located::new(1, 1, 20, 21, expr1);
|
||||||
let branch1 = &*arena.alloc(WhenBranch {
|
let branch1 = &*arena.alloc(WhenBranch {
|
||||||
patterns: bumpalo::vec![in &arena;loc_pattern1, loc_pattern1_alt],
|
patterns: arena.alloc([loc_pattern1, loc_pattern1_alt]),
|
||||||
value: loc_expr1,
|
value: loc_expr1,
|
||||||
guard: None,
|
guard: None,
|
||||||
});
|
});
|
||||||
let newlines = bumpalo::vec![in &arena; Newline];
|
let newlines = &[Newline];
|
||||||
let pattern2 = Pattern::SpaceBefore(
|
let pattern2 = Pattern::SpaceBefore(arena.alloc(StrLiteral(PlainLine("foo"))), newlines);
|
||||||
arena.alloc(StrLiteral(PlainLine("foo"))),
|
let newlines = &[Newline];
|
||||||
newlines.into_bump_slice(),
|
let pattern2_alt =
|
||||||
);
|
Pattern::SpaceBefore(arena.alloc(StrLiteral(PlainLine("bar"))), newlines);
|
||||||
let newlines = bumpalo::vec![in &arena; Newline];
|
|
||||||
let pattern2_alt = Pattern::SpaceBefore(
|
|
||||||
arena.alloc(StrLiteral(PlainLine("bar"))),
|
|
||||||
newlines.into_bump_slice(),
|
|
||||||
);
|
|
||||||
let loc_pattern2 = Located::new(2, 2, 1, 6, pattern2);
|
let loc_pattern2 = Located::new(2, 2, 1, 6, pattern2);
|
||||||
let loc_pattern2_alt = Located::new(3, 3, 1, 6, pattern2_alt);
|
let loc_pattern2_alt = Located::new(3, 3, 1, 6, pattern2_alt);
|
||||||
let expr2 = Num("2");
|
let expr2 = Num("2");
|
||||||
let loc_expr2 = Located::new(3, 3, 10, 11, expr2);
|
let loc_expr2 = Located::new(3, 3, 10, 11, expr2);
|
||||||
let branch2 = &*arena.alloc(WhenBranch {
|
let branch2 = &*arena.alloc(WhenBranch {
|
||||||
patterns: bumpalo::vec![in &arena;loc_pattern2, loc_pattern2_alt],
|
patterns: arena.alloc([loc_pattern2, loc_pattern2_alt]),
|
||||||
value: loc_expr2,
|
value: loc_expr2,
|
||||||
guard: None,
|
guard: None,
|
||||||
});
|
});
|
||||||
let branches = bumpalo::vec![in &arena; branch1, branch2];
|
let branches = &[branch1, branch2];
|
||||||
let var = Var {
|
let var = Var {
|
||||||
module_name: "",
|
module_name: "",
|
||||||
ident: "x",
|
ident: "x",
|
||||||
|
@ -2317,9 +2263,9 @@ mod test_parse {
|
||||||
use roc_parse::ast::Def::*;
|
use roc_parse::ast::Def::*;
|
||||||
|
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let newlines1 = bumpalo::vec![in &arena; Newline, Newline];
|
let newlines1 = &[Newline, Newline];
|
||||||
let newlines2 = bumpalo::vec![in &arena; Newline];
|
let newlines2 = &[Newline];
|
||||||
let newlines3 = bumpalo::vec![in &arena; Newline];
|
let newlines3 = &[Newline];
|
||||||
let pattern1 = Identifier("foo");
|
let pattern1 = Identifier("foo");
|
||||||
let pattern2 = Identifier("bar");
|
let pattern2 = Identifier("bar");
|
||||||
let pattern3 = Identifier("baz");
|
let pattern3 = Identifier("baz");
|
||||||
|
@ -2328,27 +2274,27 @@ mod test_parse {
|
||||||
arena.alloc(Located::new(0, 0, 0, 3, pattern1)),
|
arena.alloc(Located::new(0, 0, 0, 3, pattern1)),
|
||||||
arena.alloc(Located::new(0, 0, 6, 7, Num("1"))),
|
arena.alloc(Located::new(0, 0, 6, 7, Num("1"))),
|
||||||
)),
|
)),
|
||||||
newlines1.into_bump_slice(),
|
newlines1,
|
||||||
);
|
);
|
||||||
let def2 = SpaceAfter(
|
let def2 = SpaceAfter(
|
||||||
arena.alloc(Body(
|
arena.alloc(Body(
|
||||||
arena.alloc(Located::new(2, 2, 0, 3, pattern2)),
|
arena.alloc(Located::new(2, 2, 0, 3, pattern2)),
|
||||||
arena.alloc(Located::new(2, 2, 6, 10, Str(PlainLine("hi")))),
|
arena.alloc(Located::new(2, 2, 6, 10, Str(PlainLine("hi")))),
|
||||||
)),
|
)),
|
||||||
newlines2.into_bump_slice(),
|
newlines2,
|
||||||
);
|
);
|
||||||
let def3 = SpaceAfter(
|
let def3 = SpaceAfter(
|
||||||
arena.alloc(Body(
|
arena.alloc(Body(
|
||||||
arena.alloc(Located::new(3, 3, 0, 3, pattern3)),
|
arena.alloc(Located::new(3, 3, 0, 3, pattern3)),
|
||||||
arena.alloc(Located::new(3, 3, 6, 13, Str(PlainLine("stuff")))),
|
arena.alloc(Located::new(3, 3, 6, 13, Str(PlainLine("stuff")))),
|
||||||
)),
|
)),
|
||||||
newlines3.into_bump_slice(),
|
newlines3,
|
||||||
);
|
);
|
||||||
|
|
||||||
let expected = bumpalo::vec![in &arena;
|
let expected = bumpalo::vec![in &arena;
|
||||||
Located::new(0, 0, 0, 7, def1),
|
Located::new(0, 0, 0, 7, def1),
|
||||||
Located::new(2, 2, 0, 10, def2),
|
Located::new(2, 2, 0, 10, def2),
|
||||||
Located::new(3, 3, 0, 13, def3)
|
Located::new(3, 3, 0, 13, def3),
|
||||||
];
|
];
|
||||||
let src = indoc!(
|
let src = indoc!(
|
||||||
r#"
|
r#"
|
||||||
|
@ -2369,15 +2315,15 @@ mod test_parse {
|
||||||
fn newline_after_equals() {
|
fn newline_after_equals() {
|
||||||
// Regression test for https://github.com/rtfeldman/roc/issues/51
|
// Regression test for https://github.com/rtfeldman/roc/issues/51
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let newlines = bumpalo::vec![in &arena; Newline, Newline];
|
let newlines = &[Newline, Newline];
|
||||||
let num = arena.alloc(Num("5"));
|
let num = arena.alloc(Num("5"));
|
||||||
let def = Def::Body(
|
let def = Def::Body(
|
||||||
arena.alloc(Located::new(0, 0, 0, 1, Identifier("x"))),
|
arena.alloc(Located::new(0, 0, 0, 1, Identifier("x"))),
|
||||||
arena.alloc(Located::new(1, 1, 4, 5, Expr::SpaceBefore(num, &[Newline]))),
|
arena.alloc(Located::new(1, 1, 4, 5, Expr::SpaceBefore(num, &[Newline]))),
|
||||||
);
|
);
|
||||||
let loc_def = &*arena.alloc(Located::new(0, 0, 0, 1, def));
|
let loc_def = &*arena.alloc(Located::new(0, 0, 0, 1, def));
|
||||||
let defs = bumpalo::vec![in &arena; loc_def];
|
let defs = &[loc_def];
|
||||||
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines);
|
||||||
let loc_ret = Located::new(3, 3, 0, 2, ret);
|
let loc_ret = Located::new(3, 3, 0, 2, ret);
|
||||||
let expected = Defs(defs, arena.alloc(loc_ret));
|
let expected = Defs(defs, arena.alloc(loc_ret));
|
||||||
|
|
||||||
|
@ -2399,24 +2345,24 @@ mod test_parse {
|
||||||
#[test]
|
#[test]
|
||||||
fn basic_docs() {
|
fn basic_docs() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let newlines = bumpalo::vec![in &arena; Newline, Newline];
|
let newlines = &[Newline, Newline];
|
||||||
let def = Def::Body(
|
let def = Def::Body(
|
||||||
arena.alloc(Located::new(4, 4, 0, 1, Identifier("x"))),
|
arena.alloc(Located::new(4, 4, 0, 1, Identifier("x"))),
|
||||||
arena.alloc(Located::new(4, 4, 4, 5, Num("5"))),
|
arena.alloc(Located::new(4, 4, 4, 5, Num("5"))),
|
||||||
);
|
);
|
||||||
let loc_def = &*arena.alloc(Located::new(4, 4, 0, 1, def));
|
let loc_def = &*arena.alloc(Located::new(4, 4, 0, 1, def));
|
||||||
let defs = bumpalo::vec![in &arena; loc_def];
|
let defs = &[loc_def];
|
||||||
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines);
|
||||||
let loc_ret = Located::new(6, 6, 0, 2, ret);
|
let loc_ret = Located::new(6, 6, 0, 2, ret);
|
||||||
let reset_indentation = bumpalo::vec![in &arena;
|
let reset_indentation = &[
|
||||||
DocComment("first line of docs"),
|
DocComment("first line of docs"),
|
||||||
DocComment(" second line"),
|
DocComment(" second line"),
|
||||||
DocComment(" third line"),
|
DocComment(" third line"),
|
||||||
DocComment("fourth line")
|
DocComment("fourth line"),
|
||||||
];
|
];
|
||||||
let expected = Expr::SpaceBefore(
|
let expected = Expr::SpaceBefore(
|
||||||
arena.alloc(Defs(defs, arena.alloc(loc_ret))),
|
arena.alloc(Defs(defs, arena.alloc(loc_ret))),
|
||||||
reset_indentation.into_bump_slice(),
|
reset_indentation,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_parses_to(
|
assert_parses_to(
|
||||||
|
@ -2438,16 +2384,16 @@ mod test_parse {
|
||||||
#[test]
|
#[test]
|
||||||
fn not_docs() {
|
fn not_docs() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let newlines = bumpalo::vec![in &arena; Newline, Newline];
|
let newlines = &[Newline, Newline];
|
||||||
let def = Def::Body(
|
let def = Def::Body(
|
||||||
arena.alloc(Located::new(4, 4, 0, 1, Identifier("x"))),
|
arena.alloc(Located::new(4, 4, 0, 1, Identifier("x"))),
|
||||||
arena.alloc(Located::new(4, 4, 4, 5, Num("5"))),
|
arena.alloc(Located::new(4, 4, 4, 5, Num("5"))),
|
||||||
);
|
);
|
||||||
let loc_def = &*arena.alloc(Located::new(4, 4, 0, 1, def));
|
let loc_def = &*arena.alloc(Located::new(4, 4, 0, 1, def));
|
||||||
let defs = bumpalo::vec![in &arena; loc_def];
|
let defs = &[loc_def];
|
||||||
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines);
|
||||||
let loc_ret = Located::new(6, 6, 0, 2, ret);
|
let loc_ret = Located::new(6, 6, 0, 2, ret);
|
||||||
let reset_indentation = bumpalo::vec![in &arena;
|
let reset_indentation = &[
|
||||||
LineComment("######"),
|
LineComment("######"),
|
||||||
LineComment("## not docs!"),
|
LineComment("## not docs!"),
|
||||||
LineComment("#still not docs"),
|
LineComment("#still not docs"),
|
||||||
|
@ -2455,7 +2401,7 @@ mod test_parse {
|
||||||
];
|
];
|
||||||
let expected = Expr::SpaceBefore(
|
let expected = Expr::SpaceBefore(
|
||||||
arena.alloc(Defs(defs, arena.alloc(loc_ret))),
|
arena.alloc(Defs(defs, arena.alloc(loc_ret))),
|
||||||
reset_indentation.into_bump_slice(),
|
reset_indentation,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_parses_to(
|
assert_parses_to(
|
||||||
|
@ -2477,16 +2423,16 @@ mod test_parse {
|
||||||
#[test]
|
#[test]
|
||||||
fn mixed_docs() {
|
fn mixed_docs() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let newlines = bumpalo::vec![in &arena; Newline, Newline];
|
let newlines = &[Newline, Newline];
|
||||||
let def = Def::Body(
|
let def = Def::Body(
|
||||||
arena.alloc(Located::new(4, 4, 0, 1, Identifier("x"))),
|
arena.alloc(Located::new(4, 4, 0, 1, Identifier("x"))),
|
||||||
arena.alloc(Located::new(4, 4, 4, 5, Num("5"))),
|
arena.alloc(Located::new(4, 4, 4, 5, Num("5"))),
|
||||||
);
|
);
|
||||||
let loc_def = &*arena.alloc(Located::new(4, 4, 0, 1, def));
|
let loc_def = &*arena.alloc(Located::new(4, 4, 0, 1, def));
|
||||||
let defs = bumpalo::vec![in &arena; loc_def];
|
let defs = &[loc_def];
|
||||||
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
|
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines);
|
||||||
let loc_ret = Located::new(6, 6, 0, 2, ret);
|
let loc_ret = Located::new(6, 6, 0, 2, ret);
|
||||||
let reset_indentation = bumpalo::vec![in &arena;
|
let reset_indentation = &[
|
||||||
LineComment("## not docs!"),
|
LineComment("## not docs!"),
|
||||||
DocComment("docs, but with a problem"),
|
DocComment("docs, but with a problem"),
|
||||||
DocComment("(namely that this is a mix of docs and regular comments)"),
|
DocComment("(namely that this is a mix of docs and regular comments)"),
|
||||||
|
@ -2494,7 +2440,7 @@ mod test_parse {
|
||||||
];
|
];
|
||||||
let expected = Expr::SpaceBefore(
|
let expected = Expr::SpaceBefore(
|
||||||
arena.alloc(Defs(defs, arena.alloc(loc_ret))),
|
arena.alloc(Defs(defs, arena.alloc(loc_ret))),
|
||||||
reset_indentation.into_bump_slice(),
|
reset_indentation,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_parses_to(
|
assert_parses_to(
|
||||||
|
@ -2517,30 +2463,27 @@ mod test_parse {
|
||||||
fn malformed_pattern_field_access() {
|
fn malformed_pattern_field_access() {
|
||||||
// See https://github.com/rtfeldman/roc/issues/399
|
// See https://github.com/rtfeldman/roc/issues/399
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let newlines = bumpalo::vec![in &arena; Newline];
|
let newlines = &[Newline];
|
||||||
let pattern1 = Pattern::SpaceBefore(
|
let pattern1 = Pattern::SpaceBefore(arena.alloc(Pattern::Malformed("bar.and")), newlines);
|
||||||
arena.alloc(Pattern::Malformed("bar.and")),
|
|
||||||
newlines.into_bump_slice(),
|
|
||||||
);
|
|
||||||
let loc_pattern1 = Located::new(1, 1, 4, 11, pattern1);
|
let loc_pattern1 = Located::new(1, 1, 4, 11, pattern1);
|
||||||
let expr1 = Num("1");
|
let expr1 = Num("1");
|
||||||
let loc_expr1 = Located::new(1, 1, 15, 16, expr1);
|
let loc_expr1 = Located::new(1, 1, 15, 16, expr1);
|
||||||
let branch1 = &*arena.alloc(WhenBranch {
|
let branch1 = &*arena.alloc(WhenBranch {
|
||||||
patterns: bumpalo::vec![in &arena;loc_pattern1],
|
patterns: arena.alloc([loc_pattern1]),
|
||||||
value: loc_expr1,
|
value: loc_expr1,
|
||||||
guard: None,
|
guard: None,
|
||||||
});
|
});
|
||||||
let newlines = bumpalo::vec![in &arena; Newline];
|
let newlines = &[Newline];
|
||||||
let pattern2 = Pattern::SpaceBefore(arena.alloc(Underscore), newlines.into_bump_slice());
|
let pattern2 = Pattern::SpaceBefore(arena.alloc(Underscore), newlines);
|
||||||
let loc_pattern2 = Located::new(2, 2, 4, 5, pattern2);
|
let loc_pattern2 = Located::new(2, 2, 4, 5, pattern2);
|
||||||
let expr2 = Num("4");
|
let expr2 = Num("4");
|
||||||
let loc_expr2 = Located::new(2, 2, 9, 10, expr2);
|
let loc_expr2 = Located::new(2, 2, 9, 10, expr2);
|
||||||
let branch2 = &*arena.alloc(WhenBranch {
|
let branch2 = &*arena.alloc(WhenBranch {
|
||||||
patterns: bumpalo::vec![in &arena;loc_pattern2 ],
|
patterns: arena.alloc([loc_pattern2]),
|
||||||
value: loc_expr2,
|
value: loc_expr2,
|
||||||
guard: None,
|
guard: None,
|
||||||
});
|
});
|
||||||
let branches = bumpalo::vec![in &arena; branch1, branch2];
|
let branches = &[branch1, branch2];
|
||||||
let var = Var {
|
let var = Var {
|
||||||
module_name: "",
|
module_name: "",
|
||||||
ident: "x",
|
ident: "x",
|
||||||
|
@ -2565,30 +2508,27 @@ mod test_parse {
|
||||||
fn malformed_pattern_module_name() {
|
fn malformed_pattern_module_name() {
|
||||||
// See https://github.com/rtfeldman/roc/issues/399
|
// See https://github.com/rtfeldman/roc/issues/399
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let newlines = bumpalo::vec![in &arena; Newline];
|
let newlines = &[Newline];
|
||||||
let pattern1 = Pattern::SpaceBefore(
|
let pattern1 = Pattern::SpaceBefore(arena.alloc(Pattern::Malformed("Foo.and")), newlines);
|
||||||
arena.alloc(Pattern::Malformed("Foo.and")),
|
|
||||||
newlines.into_bump_slice(),
|
|
||||||
);
|
|
||||||
let loc_pattern1 = Located::new(1, 1, 4, 11, pattern1);
|
let loc_pattern1 = Located::new(1, 1, 4, 11, pattern1);
|
||||||
let expr1 = Num("1");
|
let expr1 = Num("1");
|
||||||
let loc_expr1 = Located::new(1, 1, 15, 16, expr1);
|
let loc_expr1 = Located::new(1, 1, 15, 16, expr1);
|
||||||
let branch1 = &*arena.alloc(WhenBranch {
|
let branch1 = &*arena.alloc(WhenBranch {
|
||||||
patterns: bumpalo::vec![in &arena;loc_pattern1],
|
patterns: arena.alloc([loc_pattern1]),
|
||||||
value: loc_expr1,
|
value: loc_expr1,
|
||||||
guard: None,
|
guard: None,
|
||||||
});
|
});
|
||||||
let newlines = bumpalo::vec![in &arena; Newline];
|
let newlines = &[Newline];
|
||||||
let pattern2 = Pattern::SpaceBefore(arena.alloc(Underscore), newlines.into_bump_slice());
|
let pattern2 = Pattern::SpaceBefore(arena.alloc(Underscore), newlines);
|
||||||
let loc_pattern2 = Located::new(2, 2, 4, 5, pattern2);
|
let loc_pattern2 = Located::new(2, 2, 4, 5, pattern2);
|
||||||
let expr2 = Num("4");
|
let expr2 = Num("4");
|
||||||
let loc_expr2 = Located::new(2, 2, 9, 10, expr2);
|
let loc_expr2 = Located::new(2, 2, 9, 10, expr2);
|
||||||
let branch2 = &*arena.alloc(WhenBranch {
|
let branch2 = &*arena.alloc(WhenBranch {
|
||||||
patterns: bumpalo::vec![in &arena;loc_pattern2 ],
|
patterns: arena.alloc([loc_pattern2]),
|
||||||
value: loc_expr2,
|
value: loc_expr2,
|
||||||
guard: None,
|
guard: None,
|
||||||
});
|
});
|
||||||
let branches = bumpalo::vec![in &arena; branch1, branch2];
|
let branches = &[branch1, branch2];
|
||||||
let var = Var {
|
let var = Var {
|
||||||
module_name: "",
|
module_name: "",
|
||||||
ident: "x",
|
ident: "x",
|
||||||
|
|
|
@ -1369,7 +1369,7 @@ mod solve_expr {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
int : Num Integer
|
int : Num Integer
|
||||||
int = 5.5
|
int = 5
|
||||||
|
|
||||||
int
|
int
|
||||||
"#
|
"#
|
||||||
|
@ -1384,7 +1384,7 @@ mod solve_expr {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
int : Num.Num Num.Integer
|
int : Num.Num Num.Integer
|
||||||
int = 5.5
|
int = 5
|
||||||
|
|
||||||
int
|
int
|
||||||
"#
|
"#
|
||||||
|
@ -2039,16 +2039,17 @@ mod solve_expr {
|
||||||
infer_eq(
|
infer_eq(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
Peano : [ S Peano, Z ]
|
app Test provides [ main ] imports []
|
||||||
|
|
||||||
map : Peano -> Peano
|
Peano : [ S Peano, Z ]
|
||||||
map = \peano ->
|
|
||||||
when peano is
|
|
||||||
Z -> Z
|
|
||||||
S rest ->
|
|
||||||
map rest |> S
|
|
||||||
|
|
||||||
|
map : Peano -> Peano
|
||||||
|
map = \peano ->
|
||||||
|
when peano is
|
||||||
|
Z -> Z
|
||||||
|
S rest -> S (map rest)
|
||||||
|
|
||||||
|
main =
|
||||||
map
|
map
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
|
|
|
@ -328,11 +328,7 @@ impl Subs {
|
||||||
let l_key = self.utable.get_root_key(key);
|
let l_key = self.utable.get_root_key(key);
|
||||||
|
|
||||||
self.utable.update_value(l_key, |node| {
|
self.utable.update_value(l_key, |node| {
|
||||||
let mut new_desc = node.value.clone();
|
node.value.rank = rank;
|
||||||
|
|
||||||
new_desc.rank = rank;
|
|
||||||
|
|
||||||
node.value = new_desc;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,11 +336,7 @@ impl Subs {
|
||||||
let l_key = self.utable.get_root_key(key);
|
let l_key = self.utable.get_root_key(key);
|
||||||
|
|
||||||
self.utable.update_value(l_key, |node| {
|
self.utable.update_value(l_key, |node| {
|
||||||
let mut new_desc = node.value.clone();
|
node.value.mark = mark;
|
||||||
|
|
||||||
new_desc.mark = mark;
|
|
||||||
|
|
||||||
node.value = new_desc;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,11 +344,7 @@ impl Subs {
|
||||||
let l_key = self.utable.get_root_key(key);
|
let l_key = self.utable.get_root_key(key);
|
||||||
|
|
||||||
self.utable.update_value(l_key, |node| {
|
self.utable.update_value(l_key, |node| {
|
||||||
let mut new_desc = node.value.clone();
|
node.value.content = content;
|
||||||
|
|
||||||
new_desc.content = content;
|
|
||||||
|
|
||||||
node.value = new_desc;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
nix/bin/llvm-as-10
Executable file
2
nix/bin/llvm-as-10
Executable file
|
@ -0,0 +1,2 @@
|
||||||
|
#!/bin/sh
|
||||||
|
llvm-as "$@"
|
36
nix/zig.nix
Normal file
36
nix/zig.nix
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
{ pkgs, isMacOS }:
|
||||||
|
|
||||||
|
# We require at least specific commit of Zig after the latest tagged
|
||||||
|
# release (0.6.0), so we just download the binaries for that commit
|
||||||
|
|
||||||
|
let
|
||||||
|
version = "0.6.0+0088efc4b";
|
||||||
|
osName =
|
||||||
|
if isMacOS
|
||||||
|
then "macos"
|
||||||
|
else "linux";
|
||||||
|
archiveName = "zig-${osName}-x86_64-${version}";
|
||||||
|
sha256 =
|
||||||
|
if isMacOS
|
||||||
|
then "665c1a7f472cfc5e0715f0ddf6ff8409fb749ac91cbbae68c443b4a37ebd058e"
|
||||||
|
else "bab70ae3bd0af538022bc3ef50d8f34fa8dceac39ba7d9e5d528eee7e6d5a1cf";
|
||||||
|
in
|
||||||
|
pkgs.stdenv.mkDerivation {
|
||||||
|
pname = "zig";
|
||||||
|
version = version;
|
||||||
|
buildInputs = [ pkgs.gzip ];
|
||||||
|
src = pkgs.fetchurl {
|
||||||
|
inherit sha256;
|
||||||
|
name = "${archiveName}.tar.xz";
|
||||||
|
url = "https://ziglang.org/builds/${archiveName}.tar.xz";
|
||||||
|
};
|
||||||
|
phases = [ "installPhase" ];
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p $out/bin
|
||||||
|
tar -xf $src
|
||||||
|
cp ${archiveName}/zig $out/zig
|
||||||
|
cp -r ${archiveName}/lib $out/lib
|
||||||
|
ln -s "$out/zig" "$out/bin/zig"
|
||||||
|
chmod +x $out/bin/zig
|
||||||
|
'';
|
||||||
|
}
|
28
nix/zls.nix
Normal file
28
nix/zls.nix
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{ pkgs, zig }:
|
||||||
|
|
||||||
|
# As of 2020-10-25, building zls is not available on Nix. For some reason,
|
||||||
|
# this hangs on `zig build`. I'll try to figure it our later.
|
||||||
|
|
||||||
|
let
|
||||||
|
rev = "e8c20351d85da8eb4bf22480045b994007284d69";
|
||||||
|
in
|
||||||
|
pkgs.stdenv.mkDerivation {
|
||||||
|
pname = "zig-language-server";
|
||||||
|
version = rev;
|
||||||
|
src = pkgs.fetchgit {
|
||||||
|
inherit rev;
|
||||||
|
fetchSubmodules = true;
|
||||||
|
url = "https://github.com/zigtools/zls.git";
|
||||||
|
sha256 = "06g8gml1g0fmvcfysy93bd1hb64vjd2v12x3kgxz58kmk5z0168y";
|
||||||
|
};
|
||||||
|
phases = [ "buildPhase" "installPhase" ];
|
||||||
|
buildInputs = [ zig ];
|
||||||
|
buildPhase = ''
|
||||||
|
zig build
|
||||||
|
'';
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p $out/bin
|
||||||
|
cp ./zig-cache/bin/zls $out/bin/zls
|
||||||
|
chmod +x $out/bin/zls
|
||||||
|
'';
|
||||||
|
}
|
|
@ -382,6 +382,12 @@ impl RocStr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&str> for RocStr {
|
||||||
|
fn from(str: &str) -> Self {
|
||||||
|
Self::from_slice(str.as_bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Debug for RocStr {
|
impl fmt::Debug for RocStr {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
// RocStr { is_small_str: false, storage: Refcounted(3), elements: [ 1,2,3,4] }
|
// RocStr { is_small_str: false, storage: Refcounted(3), elements: [ 1,2,3,4] }
|
||||||
|
|
11
shell.nix
11
shell.nix
|
@ -9,10 +9,11 @@ with {
|
||||||
ref = "refs/heads/nixpkgs-unstable";
|
ref = "refs/heads/nixpkgs-unstable";
|
||||||
rev = "502845c3e31ef3de0e424f3fcb09217df2ce6df6";
|
rev = "502845c3e31ef3de0e424f3fcb09217df2ce6df6";
|
||||||
}) { };
|
}) { };
|
||||||
|
|
||||||
|
isMacOS = builtins.currentSystem == "x86_64-darwin";
|
||||||
};
|
};
|
||||||
|
|
||||||
let
|
let
|
||||||
isMacOS = builtins.currentSystem == "x86_64-darwin";
|
|
||||||
darwin-frameworks =
|
darwin-frameworks =
|
||||||
if isMacOS then
|
if isMacOS then
|
||||||
with pkgs.darwin.apple_sdk.frameworks; [
|
with pkgs.darwin.apple_sdk.frameworks; [
|
||||||
|
@ -28,6 +29,7 @@ let
|
||||||
[ ];
|
[ ];
|
||||||
llvm = pkgs.llvm_10;
|
llvm = pkgs.llvm_10;
|
||||||
lld = pkgs.lld_10; # this should match llvm's version
|
lld = pkgs.lld_10; # this should match llvm's version
|
||||||
|
zig = import ./nix/zig.nix { inherit pkgs isMacOS; };
|
||||||
inputs =
|
inputs =
|
||||||
[
|
[
|
||||||
# build libraries
|
# build libraries
|
||||||
|
@ -35,6 +37,7 @@ let
|
||||||
pkgs.cargo
|
pkgs.cargo
|
||||||
llvm
|
llvm
|
||||||
pkgs.valgrind
|
pkgs.valgrind
|
||||||
|
zig
|
||||||
# llb deps
|
# llb deps
|
||||||
pkgs.libffi
|
pkgs.libffi
|
||||||
pkgs.libxml2
|
pkgs.libxml2
|
||||||
|
@ -43,10 +46,16 @@ let
|
||||||
lld
|
lld
|
||||||
# dev tools
|
# dev tools
|
||||||
pkgs.rust-analyzer
|
pkgs.rust-analyzer
|
||||||
|
# (import ./nix/zls.nix { inherit pkgs zig; })
|
||||||
pkgs.ccls
|
pkgs.ccls
|
||||||
];
|
];
|
||||||
in pkgs.mkShell {
|
in pkgs.mkShell {
|
||||||
buildInputs = inputs ++ darwin-frameworks;
|
buildInputs = inputs ++ darwin-frameworks;
|
||||||
LLVM_SYS_100_PREFIX = "${llvm}";
|
LLVM_SYS_100_PREFIX = "${llvm}";
|
||||||
|
|
||||||
|
# Aliases don't work cross shell, so we do this
|
||||||
|
shellHook = ''
|
||||||
|
export PATH="$PATH:$PWD/nix/bin"
|
||||||
|
'';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue