mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 13:59:08 +00:00
Merge branch 'trunk' into rvcas/list_functions
This commit is contained in:
commit
dfcf7bb7a2
58 changed files with 1971 additions and 1318 deletions
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
|
@ -40,6 +40,12 @@ jobs:
|
||||||
path: ~/.cargo/git
|
path: ~/.cargo/git
|
||||||
key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
|
key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
|
||||||
|
|
||||||
|
- name: Cache compiled valgrind
|
||||||
|
uses: actions/cache@v1
|
||||||
|
with:
|
||||||
|
path: ~/valgrind-3.6.1/
|
||||||
|
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
|
||||||
|
|
||||||
- uses: actions-rs/cargo@v1
|
- uses: actions-rs/cargo@v1
|
||||||
name: cargo fmt --check
|
name: cargo fmt --check
|
||||||
with:
|
with:
|
||||||
|
|
|
@ -59,7 +59,21 @@ esac
|
||||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
|
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 libc6-dbg
|
||||||
|
|
||||||
|
wget https://sourceware.org/pub/valgrind/valgrind-3.16.1.tar.bz2
|
||||||
|
tar -xf valgrind-3.16.1.tar.bz2
|
||||||
|
mv valgrind-3.16.1 ~
|
||||||
|
pushd ~/valgrind-3.16.1
|
||||||
|
apt-get install -y autotools-dev automake
|
||||||
|
./autogen.sh
|
||||||
|
./configure
|
||||||
|
make -j`nproc`
|
||||||
|
sudo make install
|
||||||
|
popd
|
||||||
|
|
||||||
|
# Report current valgrind version, to confirm it installed properly
|
||||||
|
valgrind --version
|
||||||
|
|
||||||
# install zig - can't use apt-get since we require at least a specific commit later then the most recent tag (0.6.0)
|
# 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
|
wget -c https://ziglang.org/builds/zig-linux-x86_64-0.6.0+0088efc4b.tar.xz --no-check-certificate
|
||||||
|
|
|
@ -85,6 +85,9 @@ pub fn build_file(
|
||||||
buf
|
buf
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let cwd = app_o_file.parent().unwrap();
|
||||||
|
let binary_path = cwd.join(&*loaded.output_path); // TODO should join ".exe" on Windows
|
||||||
|
|
||||||
program::gen_from_mono_module(
|
program::gen_from_mono_module(
|
||||||
&arena,
|
&arena,
|
||||||
loaded,
|
loaded,
|
||||||
|
@ -106,11 +109,8 @@ pub fn build_file(
|
||||||
size,
|
size,
|
||||||
);
|
);
|
||||||
|
|
||||||
let cwd = app_o_file.parent().unwrap();
|
|
||||||
|
|
||||||
// Step 2: link the precompiled host and compiled app
|
// Step 2: link the precompiled host and compiled app
|
||||||
let host_input_path = cwd.join("platform").join("host.o");
|
let host_input_path = cwd.join("platform").join("host.o");
|
||||||
let binary_path = cwd.join("app"); // TODO should be app.exe on Windows
|
|
||||||
|
|
||||||
// TODO we should no longer need to do this once we have platforms on
|
// TODO we should no longer need to do this once we have platforms on
|
||||||
// a package repository, as we can then get precompiled hosts from there.
|
// a package repository, as we can then get precompiled hosts from there.
|
||||||
|
|
|
@ -109,7 +109,7 @@ pub fn gen_and_eval(src: &[u8], target: Triple, opt_level: OptLevel) -> Result<R
|
||||||
Ok(ReplOutput::Problems(lines))
|
Ok(ReplOutput::Problems(lines))
|
||||||
} else {
|
} else {
|
||||||
let context = Context::create();
|
let context = Context::create();
|
||||||
let module = arena.alloc(roc_gen::llvm::build::module_from_builtins(&context, "app"));
|
let module = arena.alloc(roc_gen::llvm::build::module_from_builtins(&context, ""));
|
||||||
let builder = context.create_builder();
|
let builder = context.create_builder();
|
||||||
|
|
||||||
// mark our zig-defined builtins as internal
|
// mark our zig-defined builtins as internal
|
||||||
|
@ -274,7 +274,8 @@ pub fn gen_and_eval(src: &[u8], target: Triple, opt_level: OptLevel) -> Result<R
|
||||||
}
|
}
|
||||||
|
|
||||||
fn promote_expr_to_module(src: &str) -> String {
|
fn promote_expr_to_module(src: &str) -> String {
|
||||||
let mut buffer = String::from("app Repl provides [ replOutput ] imports []\n\nreplOutput =\n");
|
let mut buffer =
|
||||||
|
String::from("app \"app\" provides [ replOutput ] to \"./platform\"\n\nreplOutput =\n");
|
||||||
|
|
||||||
for line in src.lines() {
|
for line in src.lines() {
|
||||||
// indent the body!
|
// indent the body!
|
||||||
|
|
|
@ -17,7 +17,13 @@ mod cli_run {
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
fn check_output(file: &Path, flags: &[&str], expected_ending: &str, use_valgrind: bool) {
|
fn check_output(
|
||||||
|
file: &Path,
|
||||||
|
executable_filename: &str,
|
||||||
|
flags: &[&str],
|
||||||
|
expected_ending: &str,
|
||||||
|
use_valgrind: bool,
|
||||||
|
) {
|
||||||
let compile_out = run_roc(&[&["build", file.to_str().unwrap()], flags].concat());
|
let compile_out = run_roc(&[&["build", file.to_str().unwrap()], flags].concat());
|
||||||
if !compile_out.stderr.is_empty() {
|
if !compile_out.stderr.is_empty() {
|
||||||
panic!(compile_out.stderr);
|
panic!(compile_out.stderr);
|
||||||
|
@ -26,14 +32,31 @@ mod cli_run {
|
||||||
|
|
||||||
let out = if use_valgrind {
|
let out = if use_valgrind {
|
||||||
let (valgrind_out, raw_xml) =
|
let (valgrind_out, raw_xml) =
|
||||||
run_with_valgrind(&[file.with_file_name("app").to_str().unwrap()]);
|
run_with_valgrind(&[file.with_file_name(executable_filename).to_str().unwrap()]);
|
||||||
let memory_errors = extract_valgrind_errors(&raw_xml);
|
|
||||||
if !memory_errors.is_empty() {
|
if valgrind_out.status.success() {
|
||||||
panic!("{:?}", memory_errors);
|
let memory_errors = extract_valgrind_errors(&raw_xml).unwrap_or_else(|err| {
|
||||||
|
panic!("failed to parse the `valgrind` xml output. Error was:\n\n{:?}\n\nvalgrind xml was: \"{}\"\n\nvalgrind stdout was: \"{}\"\n\nvalgrind stderr was: \"{}\"", err, raw_xml, valgrind_out.stdout, valgrind_out.stderr);
|
||||||
|
});
|
||||||
|
|
||||||
|
if !memory_errors.is_empty() {
|
||||||
|
panic!("{:?}", memory_errors);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let exit_code = match valgrind_out.status.code() {
|
||||||
|
Some(code) => format!("exit code {}", code),
|
||||||
|
None => "no exit code".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
panic!("`valgrind` exited with {}. valgrind stdout was: \"{}\"\n\nvalgrind stderr was: \"{}\"", exit_code, valgrind_out.stdout, valgrind_out.stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
valgrind_out
|
valgrind_out
|
||||||
} else {
|
} else {
|
||||||
run_cmd(file.with_file_name("app").to_str().unwrap(), &[])
|
run_cmd(
|
||||||
|
file.with_file_name(executable_filename).to_str().unwrap(),
|
||||||
|
&[],
|
||||||
|
)
|
||||||
};
|
};
|
||||||
if !&out.stdout.ends_with(expected_ending) {
|
if !&out.stdout.ends_with(expected_ending) {
|
||||||
panic!(
|
panic!(
|
||||||
|
@ -49,6 +72,7 @@ mod cli_run {
|
||||||
fn run_hello_world() {
|
fn run_hello_world() {
|
||||||
check_output(
|
check_output(
|
||||||
&example_file("hello-world", "Hello.roc"),
|
&example_file("hello-world", "Hello.roc"),
|
||||||
|
"hello-world",
|
||||||
&[],
|
&[],
|
||||||
"Hello, World!!!!!!!!!!!!!\n",
|
"Hello, World!!!!!!!!!!!!!\n",
|
||||||
true,
|
true,
|
||||||
|
@ -60,6 +84,7 @@ mod cli_run {
|
||||||
fn run_hello_world_optimized() {
|
fn run_hello_world_optimized() {
|
||||||
check_output(
|
check_output(
|
||||||
&example_file("hello-world", "Hello.roc"),
|
&example_file("hello-world", "Hello.roc"),
|
||||||
|
"hello-world",
|
||||||
&[],
|
&[],
|
||||||
"Hello, World!!!!!!!!!!!!!\n",
|
"Hello, World!!!!!!!!!!!!!\n",
|
||||||
true,
|
true,
|
||||||
|
@ -71,6 +96,7 @@ mod cli_run {
|
||||||
fn run_quicksort_not_optimized() {
|
fn run_quicksort_not_optimized() {
|
||||||
check_output(
|
check_output(
|
||||||
&example_file("quicksort", "Quicksort.roc"),
|
&example_file("quicksort", "Quicksort.roc"),
|
||||||
|
"quicksort",
|
||||||
&[],
|
&[],
|
||||||
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
||||||
false,
|
false,
|
||||||
|
@ -82,6 +108,7 @@ mod cli_run {
|
||||||
fn run_quicksort_optimized() {
|
fn run_quicksort_optimized() {
|
||||||
check_output(
|
check_output(
|
||||||
&example_file("quicksort", "Quicksort.roc"),
|
&example_file("quicksort", "Quicksort.roc"),
|
||||||
|
"quicksort",
|
||||||
&["--optimize"],
|
&["--optimize"],
|
||||||
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
||||||
false,
|
false,
|
||||||
|
@ -95,6 +122,7 @@ mod cli_run {
|
||||||
fn run_quicksort_valgrind() {
|
fn run_quicksort_valgrind() {
|
||||||
check_output(
|
check_output(
|
||||||
&example_file("quicksort", "Quicksort.roc"),
|
&example_file("quicksort", "Quicksort.roc"),
|
||||||
|
"quicksort",
|
||||||
&[],
|
&[],
|
||||||
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
||||||
true,
|
true,
|
||||||
|
@ -108,6 +136,7 @@ mod cli_run {
|
||||||
fn run_quicksort_optimized_valgrind() {
|
fn run_quicksort_optimized_valgrind() {
|
||||||
check_output(
|
check_output(
|
||||||
&example_file("quicksort", "Quicksort.roc"),
|
&example_file("quicksort", "Quicksort.roc"),
|
||||||
|
"quicksort",
|
||||||
&["--optimize"],
|
&["--optimize"],
|
||||||
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
||||||
true,
|
true,
|
||||||
|
@ -119,6 +148,7 @@ mod cli_run {
|
||||||
fn run_multi_module() {
|
fn run_multi_module() {
|
||||||
check_output(
|
check_output(
|
||||||
&example_file("multi-module", "Quicksort.roc"),
|
&example_file("multi-module", "Quicksort.roc"),
|
||||||
|
"quicksort",
|
||||||
&[],
|
&[],
|
||||||
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
||||||
false,
|
false,
|
||||||
|
@ -130,6 +160,7 @@ mod cli_run {
|
||||||
fn run_multi_module_optimized() {
|
fn run_multi_module_optimized() {
|
||||||
check_output(
|
check_output(
|
||||||
&example_file("multi-module", "Quicksort.roc"),
|
&example_file("multi-module", "Quicksort.roc"),
|
||||||
|
"quicksort",
|
||||||
&["--optimize"],
|
&["--optimize"],
|
||||||
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
||||||
false,
|
false,
|
||||||
|
@ -143,6 +174,7 @@ mod cli_run {
|
||||||
fn run_multi_module_valgrind() {
|
fn run_multi_module_valgrind() {
|
||||||
check_output(
|
check_output(
|
||||||
&example_file("multi-module", "Quicksort.roc"),
|
&example_file("multi-module", "Quicksort.roc"),
|
||||||
|
"quicksort",
|
||||||
&[],
|
&[],
|
||||||
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
||||||
true,
|
true,
|
||||||
|
@ -156,6 +188,7 @@ mod cli_run {
|
||||||
fn run_multi_module_optimized_valgrind() {
|
fn run_multi_module_optimized_valgrind() {
|
||||||
check_output(
|
check_output(
|
||||||
&example_file("multi-module", "Quicksort.roc"),
|
&example_file("multi-module", "Quicksort.roc"),
|
||||||
|
"quicksort",
|
||||||
&["--optimize"],
|
&["--optimize"],
|
||||||
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
||||||
true,
|
true,
|
||||||
|
@ -178,6 +211,7 @@ mod cli_run {
|
||||||
fn run_multi_dep_str_unoptimized() {
|
fn run_multi_dep_str_unoptimized() {
|
||||||
check_output(
|
check_output(
|
||||||
&fixture_file("multi-dep-str", "Main.roc"),
|
&fixture_file("multi-dep-str", "Main.roc"),
|
||||||
|
"multi-dep-str",
|
||||||
&[],
|
&[],
|
||||||
"I am Dep2.str2\n",
|
"I am Dep2.str2\n",
|
||||||
true,
|
true,
|
||||||
|
@ -189,6 +223,7 @@ mod cli_run {
|
||||||
fn run_multi_dep_str_optimized() {
|
fn run_multi_dep_str_optimized() {
|
||||||
check_output(
|
check_output(
|
||||||
&fixture_file("multi-dep-str", "Main.roc"),
|
&fixture_file("multi-dep-str", "Main.roc"),
|
||||||
|
"multi-dep-str",
|
||||||
&["--optimize"],
|
&["--optimize"],
|
||||||
"I am Dep2.str2\n",
|
"I am Dep2.str2\n",
|
||||||
true,
|
true,
|
||||||
|
@ -200,6 +235,7 @@ mod cli_run {
|
||||||
fn run_multi_dep_thunk_unoptimized() {
|
fn run_multi_dep_thunk_unoptimized() {
|
||||||
check_output(
|
check_output(
|
||||||
&fixture_file("multi-dep-thunk", "Main.roc"),
|
&fixture_file("multi-dep-thunk", "Main.roc"),
|
||||||
|
"multi-dep-thunk",
|
||||||
&[],
|
&[],
|
||||||
"I am Dep2.value2\n",
|
"I am Dep2.value2\n",
|
||||||
true,
|
true,
|
||||||
|
@ -211,6 +247,7 @@ mod cli_run {
|
||||||
fn run_multi_dep_thunk_optimized() {
|
fn run_multi_dep_thunk_optimized() {
|
||||||
check_output(
|
check_output(
|
||||||
&fixture_file("multi-dep-thunk", "Main.roc"),
|
&fixture_file("multi-dep-thunk", "Main.roc"),
|
||||||
|
"multi-dep-thunk",
|
||||||
&["--optimize"],
|
&["--optimize"],
|
||||||
"I am Dep2.value2\n",
|
"I am Dep2.value2\n",
|
||||||
true,
|
true,
|
||||||
|
|
5
cli/tests/fixtures/.gitignore
vendored
5
cli/tests/fixtures/.gitignore
vendored
|
@ -1,4 +1,3 @@
|
||||||
app
|
app
|
||||||
host.o
|
*.o
|
||||||
c_host.o
|
*.dSYM
|
||||||
app.dSYM
|
|
||||||
|
|
1
cli/tests/fixtures/multi-dep-str/.gitignore
vendored
Normal file
1
cli/tests/fixtures/multi-dep-str/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
multi-dep-str
|
2
cli/tests/fixtures/multi-dep-str/Main.roc
vendored
2
cli/tests/fixtures/multi-dep-str/Main.roc
vendored
|
@ -1,4 +1,4 @@
|
||||||
app Main provides [ main ] imports [ Dep1 ]
|
app "multi-dep-str" imports [ Dep1 ] provides [ main ] to "./platform"
|
||||||
|
|
||||||
main : Str
|
main : Str
|
||||||
main = Dep1.str1
|
main = Dep1.str1
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
platform roc/quicksort
|
platform examples/multi-module
|
||||||
provides []
|
requires { main : Str }
|
||||||
requires {}
|
exposes []
|
||||||
|
packages {}
|
||||||
imports []
|
imports []
|
||||||
|
provides [ main ]
|
||||||
effects Effect {}
|
effects Effect {}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use roc_std::RocStr;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#[link_name = "Main_main_1_exposed"]
|
#[link_name = "roc__main_1_exposed"]
|
||||||
fn say_hello(output: &mut RocCallResult<RocStr>) -> ();
|
fn say_hello(output: &mut RocCallResult<RocStr>) -> ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1
cli/tests/fixtures/multi-dep-thunk/.gitignore
vendored
Normal file
1
cli/tests/fixtures/multi-dep-thunk/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
multi-dep-thunk
|
2
cli/tests/fixtures/multi-dep-thunk/Main.roc
vendored
2
cli/tests/fixtures/multi-dep-thunk/Main.roc
vendored
|
@ -1,4 +1,4 @@
|
||||||
app Main provides [ main ] imports [ Dep1 ]
|
app "multi-dep-thunk" imports [ Dep1 ] provides [ main ] to "./platform"
|
||||||
|
|
||||||
main : Str
|
main : Str
|
||||||
main = Dep1.value1 {}
|
main = Dep1.value1 {}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
platform roc/quicksort
|
platform examples/multi-dep-thunk
|
||||||
provides []
|
requires { main : Str }
|
||||||
requires {}
|
exposes []
|
||||||
|
packages {}
|
||||||
imports []
|
imports []
|
||||||
|
provides [ main ]
|
||||||
effects Effect {}
|
effects Effect {}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use roc_std::RocStr;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#[link_name = "Main_main_1_exposed"]
|
#[link_name = "roc__main_1_exposed"]
|
||||||
fn say_hello(output: &mut RocCallResult<RocStr>) -> ();
|
fn say_hello(output: &mut RocCallResult<RocStr>) -> ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -161,18 +161,18 @@ pub struct ValgrindErrorXWhat {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn extract_valgrind_errors(xml: &str) -> Vec<ValgrindError> {
|
pub fn extract_valgrind_errors(xml: &str) -> Result<Vec<ValgrindError>, serde_xml_rs::Error> {
|
||||||
let parsed_xml: ValgrindOutput =
|
let parsed_xml: ValgrindOutput = from_str(xml)?;
|
||||||
from_str(xml).unwrap_or_else(|err|
|
let answer = parsed_xml
|
||||||
panic!("failed to parse the `valgrind` xml output. Error was:\n\n{:?}\n\nRaw valgrind output was:\n\n{}", err, xml));
|
|
||||||
parsed_xml
|
|
||||||
.fields
|
.fields
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|field| match field {
|
.filter_map(|field| match field {
|
||||||
ValgrindField::Error(err) => Some(err.clone()),
|
ValgrindField::Error(err) => Some(err.clone()),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.collect()
|
.collect();
|
||||||
|
|
||||||
|
Ok(answer)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
use crate::spaces::{fmt_spaces, INDENT};
|
use crate::spaces::{fmt_spaces, INDENT};
|
||||||
use bumpalo::collections::{String, Vec};
|
use bumpalo::collections::{String, Vec};
|
||||||
use roc_parse::ast::{
|
use roc_parse::ast::Module;
|
||||||
AppHeader, ExposesEntry, ImportsEntry, InterfaceHeader, Module, PlatformHeader,
|
use roc_parse::header::{AppHeader, ExposesEntry, ImportsEntry, InterfaceHeader, PlatformHeader};
|
||||||
};
|
|
||||||
use roc_region::all::Located;
|
use roc_region::all::Located;
|
||||||
|
|
||||||
pub fn fmt_module<'a>(buf: &mut String<'a>, module: &'a Module<'a>) {
|
pub fn fmt_module<'a>(buf: &mut String<'a>, module: &'a Module<'a>) {
|
||||||
|
@ -113,7 +112,7 @@ fn fmt_imports<'a>(
|
||||||
|
|
||||||
fn fmt_exposes<'a>(
|
fn fmt_exposes<'a>(
|
||||||
buf: &mut String<'a>,
|
buf: &mut String<'a>,
|
||||||
loc_entries: &'a Vec<'a, Located<ExposesEntry<'a>>>,
|
loc_entries: &'a Vec<'a, Located<ExposesEntry<'a, &'a str>>>,
|
||||||
indent: u16,
|
indent: u16,
|
||||||
) {
|
) {
|
||||||
buf.push('[');
|
buf.push('[');
|
||||||
|
@ -137,11 +136,11 @@ fn fmt_exposes<'a>(
|
||||||
buf.push(']');
|
buf.push(']');
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fmt_exposes_entry<'a>(buf: &mut String<'a>, entry: &'a ExposesEntry<'a>, indent: u16) {
|
fn fmt_exposes_entry<'a>(buf: &mut String<'a>, entry: &'a ExposesEntry<'a, &'a str>, indent: u16) {
|
||||||
use roc_parse::ast::ExposesEntry::*;
|
use roc_parse::header::ExposesEntry::*;
|
||||||
|
|
||||||
match entry {
|
match entry {
|
||||||
Ident(ident) => buf.push_str(ident),
|
Exposed(ident) => buf.push_str(ident),
|
||||||
|
|
||||||
SpaceBefore(sub_entry, spaces) => {
|
SpaceBefore(sub_entry, spaces) => {
|
||||||
fmt_spaces(buf, spaces.iter(), indent);
|
fmt_spaces(buf, spaces.iter(), indent);
|
||||||
|
@ -155,7 +154,7 @@ fn fmt_exposes_entry<'a>(buf: &mut String<'a>, entry: &'a ExposesEntry<'a>, inde
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fmt_imports_entry<'a>(buf: &mut String<'a>, entry: &'a ImportsEntry<'a>, indent: u16) {
|
fn fmt_imports_entry<'a>(buf: &mut String<'a>, entry: &'a ImportsEntry<'a>, indent: u16) {
|
||||||
use roc_parse::ast::ImportsEntry::*;
|
use roc_parse::header::ImportsEntry::*;
|
||||||
|
|
||||||
match entry {
|
match entry {
|
||||||
Module(module, loc_exposes_entries) => {
|
Module(module, loc_exposes_entries) => {
|
||||||
|
@ -176,6 +175,10 @@ fn fmt_imports_entry<'a>(buf: &mut String<'a>, entry: &'a ImportsEntry<'a>, inde
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Package(_name, _entries) => {
|
||||||
|
todo!("TODO Format imported package");
|
||||||
|
}
|
||||||
|
|
||||||
SpaceBefore(sub_entry, spaces) => {
|
SpaceBefore(sub_entry, spaces) => {
|
||||||
fmt_spaces(buf, spaces.iter(), indent);
|
fmt_spaces(buf, spaces.iter(), indent);
|
||||||
fmt_imports_entry(buf, sub_entry, indent);
|
fmt_imports_entry(buf, sub_entry, indent);
|
||||||
|
|
|
@ -1707,7 +1707,8 @@ fn expose_function_to_host<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
roc_function: FunctionValue<'ctx>,
|
roc_function: FunctionValue<'ctx>,
|
||||||
) {
|
) {
|
||||||
let c_function_name: String = format!("{}_exposed", roc_function.get_name().to_str().unwrap());
|
let c_function_name: String =
|
||||||
|
format!("roc_{}_exposed", roc_function.get_name().to_str().unwrap());
|
||||||
|
|
||||||
let result = expose_function_to_host_help(env, roc_function, &c_function_name);
|
let result = expose_function_to_host_help(env, roc_function, &c_function_name);
|
||||||
|
|
||||||
|
|
|
@ -1186,7 +1186,7 @@ mod gen_list {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Quicksort provides [ main ] imports []
|
app "quicksort" provides [ main ] to "./platform"
|
||||||
|
|
||||||
|
|
||||||
swap : Int, Int, List a -> List a
|
swap : Int, Int, List a -> List a
|
||||||
|
|
|
@ -535,7 +535,7 @@ mod gen_primitives {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app LinkedListLen0 provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
pi = 3.1415
|
pi = 3.1415
|
||||||
|
|
||||||
|
@ -553,7 +553,7 @@ mod gen_primitives {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
LinkedList a : [ Nil, Cons a (LinkedList a) ]
|
LinkedList a : [ Nil, Cons a (LinkedList a) ]
|
||||||
|
|
||||||
|
@ -580,7 +580,7 @@ mod gen_primitives {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app LinkedListLenTwice0 provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
LinkedList a : [ Nil, Cons a (LinkedList a) ]
|
LinkedList a : [ Nil, Cons a (LinkedList a) ]
|
||||||
|
|
||||||
|
@ -607,7 +607,7 @@ mod gen_primitives {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
LinkedList a : [ Nil, Cons a (LinkedList a) ]
|
LinkedList a : [ Nil, Cons a (LinkedList a) ]
|
||||||
|
|
||||||
|
@ -634,7 +634,7 @@ mod gen_primitives {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
LinkedList a : [ Nil, Cons a (LinkedList a) ]
|
LinkedList a : [ Nil, Cons a (LinkedList a) ]
|
||||||
|
|
||||||
|
@ -661,7 +661,7 @@ mod gen_primitives {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
LinkedList a : [ Nil, Cons a (LinkedList a) ]
|
LinkedList a : [ Nil, Cons a (LinkedList a) ]
|
||||||
|
|
||||||
|
@ -689,7 +689,7 @@ mod gen_primitives {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
LinkedList a : [ Nil, Cons a (LinkedList a) ]
|
LinkedList a : [ Nil, Cons a (LinkedList a) ]
|
||||||
|
|
||||||
|
@ -717,7 +717,7 @@ mod gen_primitives {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
LinkedList a : [ Nil, Cons a (LinkedList a) ]
|
LinkedList a : [ Nil, Cons a (LinkedList a) ]
|
||||||
|
|
||||||
|
@ -744,7 +744,7 @@ mod gen_primitives {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
LinkedList a : [ Nil, Cons a (LinkedList a) ]
|
LinkedList a : [ Nil, Cons a (LinkedList a) ]
|
||||||
|
|
||||||
|
@ -907,7 +907,7 @@ mod gen_primitives {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
x = 42
|
x = 42
|
||||||
|
|
||||||
|
@ -928,7 +928,7 @@ mod gen_primitives {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
foo = \{} ->
|
foo = \{} ->
|
||||||
x = 41
|
x = 41
|
||||||
|
@ -951,7 +951,7 @@ mod gen_primitives {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
foo = \{} ->
|
foo = \{} ->
|
||||||
x = 41
|
x = 41
|
||||||
|
@ -978,7 +978,7 @@ mod gen_primitives {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
foo = \{} ->
|
foo = \{} ->
|
||||||
x = 41
|
x = 41
|
||||||
|
@ -1006,7 +1006,7 @@ mod gen_primitives {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
Effect a : [ @Effect ({} -> a) ]
|
Effect a : [ @Effect ({} -> a) ]
|
||||||
|
|
||||||
|
@ -1036,7 +1036,7 @@ mod gen_primitives {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
# succeed : a -> ({} -> a)
|
# succeed : a -> ({} -> a)
|
||||||
succeed = \x -> \{} -> x
|
succeed = \x -> \{} -> x
|
||||||
|
@ -1063,7 +1063,7 @@ mod gen_primitives {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
Effect a : [ @Effect ({} -> a) ]
|
Effect a : [ @Effect ({} -> a) ]
|
||||||
|
|
||||||
|
@ -1085,7 +1085,7 @@ mod gen_primitives {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
Effect a : [ @Effect ({} -> a) ]
|
Effect a : [ @Effect ({} -> a) ]
|
||||||
|
|
||||||
|
@ -1110,7 +1110,7 @@ mod gen_primitives {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
ConsList a : [ Cons a (ConsList a), Nil ]
|
ConsList a : [ Cons a (ConsList a), Nil ]
|
||||||
|
|
||||||
|
@ -1144,7 +1144,7 @@ mod gen_primitives {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
ConsList a : [ Cons a (ConsList a), Nil ]
|
ConsList a : [ Cons a (ConsList a), Nil ]
|
||||||
|
|
||||||
|
@ -1175,7 +1175,7 @@ mod gen_primitives {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
State a : { count : Int, x : a }
|
State a : { count : Int, x : a }
|
||||||
|
|
||||||
|
@ -1202,7 +1202,7 @@ mod gen_primitives {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
NodeColor : [ Red, Black ]
|
NodeColor : [ Red, Black ]
|
||||||
|
|
||||||
|
@ -1284,7 +1284,7 @@ mod gen_primitives {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
NodeColor : [ Red, Black ]
|
NodeColor : [ Red, Black ]
|
||||||
|
|
||||||
|
@ -1323,7 +1323,7 @@ mod gen_primitives {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
Dict k : [ Node k (Dict k) (Dict k), Empty ]
|
Dict k : [ Node k (Dict k) (Dict k), Empty ]
|
||||||
|
|
||||||
|
@ -1353,7 +1353,7 @@ mod gen_primitives {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
NodeColor : [ Red, Black ]
|
NodeColor : [ Red, Black ]
|
||||||
|
|
||||||
|
@ -1393,7 +1393,7 @@ mod gen_primitives {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
NodeColor : [ Red, Black ]
|
NodeColor : [ Red, Black ]
|
||||||
|
|
||||||
|
@ -1444,7 +1444,7 @@ mod gen_primitives {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
ConsList a : [ Cons a (ConsList a), Nil ]
|
ConsList a : [ Cons a (ConsList a), Nil ]
|
||||||
|
|
||||||
|
@ -1470,7 +1470,7 @@ mod gen_primitives {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
ConsList a : [ Cons a (ConsList a), Nil ]
|
ConsList a : [ Cons a (ConsList a), Nil ]
|
||||||
|
|
||||||
|
@ -1498,7 +1498,7 @@ mod gen_primitives {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
ConsList a : [ Cons a (ConsList a), Nil ]
|
ConsList a : [ Cons a (ConsList a), Nil ]
|
||||||
|
|
||||||
|
@ -1527,7 +1527,7 @@ mod gen_primitives {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
ConsList a : [ Cons a (ConsList a), Nil ]
|
ConsList a : [ Cons a (ConsList a), Nil ]
|
||||||
|
|
||||||
|
@ -1552,7 +1552,7 @@ mod gen_primitives {
|
||||||
assert_non_opt_evals_to!(
|
assert_non_opt_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
BTree : [ Node BTree BTree, Leaf Int ]
|
BTree : [ Node BTree BTree, Leaf Int ]
|
||||||
|
|
||||||
|
|
|
@ -405,7 +405,7 @@ mod gen_records {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
f = \r ->
|
f = \r ->
|
||||||
when r is
|
when r is
|
||||||
|
@ -455,7 +455,7 @@ mod gen_records {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
f = \r ->
|
f = \r ->
|
||||||
{ x ? 10, y } = r
|
{ x ? 10, y } = r
|
||||||
|
@ -492,7 +492,7 @@ mod gen_records {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
f = \r ->
|
f = \r ->
|
||||||
{ x ? 10, y } = r
|
{ x ? 10, y } = r
|
||||||
|
@ -512,7 +512,7 @@ mod gen_records {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
f = \r ->
|
f = \r ->
|
||||||
{ x ? 10, y } = r
|
{ x ? 10, y } = r
|
||||||
|
@ -565,7 +565,7 @@ mod gen_records {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
f = \{ x ? 10, y } -> x + y
|
f = \{ x ? 10, y } -> x + y
|
||||||
|
|
||||||
|
|
|
@ -417,7 +417,7 @@ mod gen_tags {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
Maybe a : [ Just a, Nothing ]
|
Maybe a : [ Just a, Nothing ]
|
||||||
|
|
||||||
|
@ -630,7 +630,7 @@ mod gen_tags {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
Maybe a : [ Nothing, Just a ]
|
Maybe a : [ Nothing, Just a ]
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ use roc_build::program::FunctionIterator;
|
||||||
use roc_collections::all::{MutMap, MutSet};
|
use roc_collections::all::{MutMap, MutSet};
|
||||||
|
|
||||||
fn promote_expr_to_module(src: &str) -> String {
|
fn promote_expr_to_module(src: &str) -> String {
|
||||||
let mut buffer = String::from("app Test provides [ main ] imports []\n\nmain =\n");
|
let mut buffer = String::from("app \"test\" provides [ main ] to \"./platform\"\n\nmain =\n");
|
||||||
|
|
||||||
for line in src.lines() {
|
for line in src.lines() {
|
||||||
// indent the body!
|
// indent the body!
|
||||||
|
|
|
@ -19,9 +19,8 @@ use roc_mono::ir::{
|
||||||
CapturedSymbols, ExternalSpecializations, PartialProc, PendingSpecialization, Proc, Procs,
|
CapturedSymbols, ExternalSpecializations, PartialProc, PendingSpecialization, Proc, Procs,
|
||||||
};
|
};
|
||||||
use roc_mono::layout::{Layout, LayoutCache};
|
use roc_mono::layout::{Layout, LayoutCache};
|
||||||
use roc_parse::ast::{
|
use roc_parse::ast::{self, Attempting, StrLiteral, TypeAnnotation};
|
||||||
self, Attempting, ExposesEntry, ImportsEntry, PlatformHeader, TypeAnnotation, TypedIdent,
|
use roc_parse::header::{ExposesEntry, ImportsEntry, PlatformHeader, TypedIdent};
|
||||||
};
|
|
||||||
use roc_parse::module::module_defs;
|
use roc_parse::module::module_defs;
|
||||||
use roc_parse::parser::{self, Fail, Parser};
|
use roc_parse::parser::{self, Fail, Parser};
|
||||||
use roc_region::all::{Located, Region};
|
use roc_region::all::{Located, Region};
|
||||||
|
@ -40,6 +39,9 @@ use std::str::from_utf8_unchecked;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
|
|
||||||
|
/// Default name for the binary generated for an app, if an invalid one was specified.
|
||||||
|
const DEFAULT_APP_OUTPUT_PATH: &str = "app";
|
||||||
|
|
||||||
/// Filename extension for normal Roc modules
|
/// Filename extension for normal Roc modules
|
||||||
const ROC_FILE_EXTENSION: &str = "roc";
|
const ROC_FILE_EXTENSION: &str = "roc";
|
||||||
|
|
||||||
|
@ -534,7 +536,7 @@ pub enum BuildProblem<'a> {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct ModuleHeader<'a> {
|
struct ModuleHeader<'a> {
|
||||||
module_id: ModuleId,
|
module_id: ModuleId,
|
||||||
module_name: ModuleName,
|
module_name: AppOrInterfaceName<'a>,
|
||||||
module_path: PathBuf,
|
module_path: PathBuf,
|
||||||
exposed_ident_ids: IdentIds,
|
exposed_ident_ids: IdentIds,
|
||||||
deps_by_name: MutMap<ModuleName, ModuleId>,
|
deps_by_name: MutMap<ModuleName, ModuleId>,
|
||||||
|
@ -581,6 +583,7 @@ pub struct MonomorphizedModule<'a> {
|
||||||
pub module_id: ModuleId,
|
pub module_id: ModuleId,
|
||||||
pub interns: Interns,
|
pub interns: Interns,
|
||||||
pub subs: Subs,
|
pub subs: Subs,
|
||||||
|
pub output_path: Box<str>,
|
||||||
pub can_problems: MutMap<ModuleId, Vec<roc_problem::can::Problem>>,
|
pub can_problems: MutMap<ModuleId, Vec<roc_problem::can::Problem>>,
|
||||||
pub type_problems: MutMap<ModuleId, Vec<solve::TypeError>>,
|
pub type_problems: MutMap<ModuleId, Vec<solve::TypeError>>,
|
||||||
pub mono_problems: MutMap<ModuleId, Vec<roc_mono::ir::MonoProblem>>,
|
pub mono_problems: MutMap<ModuleId, Vec<roc_mono::ir::MonoProblem>>,
|
||||||
|
@ -599,7 +602,7 @@ pub struct VariablySizedLayouts<'a> {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct ParsedModule<'a> {
|
struct ParsedModule<'a> {
|
||||||
module_id: ModuleId,
|
module_id: ModuleId,
|
||||||
module_name: ModuleName,
|
module_name: AppOrInterfaceName<'a>,
|
||||||
module_path: PathBuf,
|
module_path: PathBuf,
|
||||||
src: &'a str,
|
src: &'a str,
|
||||||
module_timing: ModuleTiming,
|
module_timing: ModuleTiming,
|
||||||
|
@ -618,7 +621,7 @@ enum Msg<'a> {
|
||||||
CanonicalizedAndConstrained {
|
CanonicalizedAndConstrained {
|
||||||
constrained_module: ConstrainedModule,
|
constrained_module: ConstrainedModule,
|
||||||
canonicalization_problems: Vec<roc_problem::can::Problem>,
|
canonicalization_problems: Vec<roc_problem::can::Problem>,
|
||||||
module_docs: ModuleDocumentation,
|
module_docs: Option<ModuleDocumentation>,
|
||||||
},
|
},
|
||||||
MadeEffectModule {
|
MadeEffectModule {
|
||||||
constrained_module: ConstrainedModule,
|
constrained_module: ConstrainedModule,
|
||||||
|
@ -672,6 +675,7 @@ struct State<'a> {
|
||||||
pub goal_phase: Phase,
|
pub goal_phase: Phase,
|
||||||
pub stdlib: StdLib,
|
pub stdlib: StdLib,
|
||||||
pub exposed_types: SubsByModule,
|
pub exposed_types: SubsByModule,
|
||||||
|
pub output_path: Option<&'a str>,
|
||||||
|
|
||||||
pub headers_parsed: MutSet<ModuleId>,
|
pub headers_parsed: MutSet<ModuleId>,
|
||||||
|
|
||||||
|
@ -1243,6 +1247,7 @@ where
|
||||||
root_id,
|
root_id,
|
||||||
goal_phase,
|
goal_phase,
|
||||||
stdlib,
|
stdlib,
|
||||||
|
output_path: None,
|
||||||
module_cache: ModuleCache::default(),
|
module_cache: ModuleCache::default(),
|
||||||
dependencies: Dependencies::default(),
|
dependencies: Dependencies::default(),
|
||||||
procedures: MutMap::default(),
|
procedures: MutMap::default(),
|
||||||
|
@ -1427,6 +1432,22 @@ fn update<'a>(
|
||||||
.sources
|
.sources
|
||||||
.insert(parsed.module_id, (parsed.module_path.clone(), parsed.src));
|
.insert(parsed.module_id, (parsed.module_path.clone(), parsed.src));
|
||||||
|
|
||||||
|
// If this was an app module, set the output path to be
|
||||||
|
// the module's declared "name".
|
||||||
|
//
|
||||||
|
// e.g. for `app "blah"` we should generate an output file named "blah"
|
||||||
|
match &parsed.module_name {
|
||||||
|
AppOrInterfaceName::App(output_str) => match output_str {
|
||||||
|
StrLiteral::PlainLine(path) => {
|
||||||
|
state.output_path = Some(path);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
todo!("TODO gracefully handle a malformed string literal after `app` keyword.");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
AppOrInterfaceName::Interface(_) => {}
|
||||||
|
}
|
||||||
|
|
||||||
let module_id = parsed.module_id;
|
let module_id = parsed.module_id;
|
||||||
|
|
||||||
state.module_cache.parsed.insert(parsed.module_id, parsed);
|
state.module_cache.parsed.insert(parsed.module_id, parsed);
|
||||||
|
@ -1450,10 +1471,9 @@ fn update<'a>(
|
||||||
.can_problems
|
.can_problems
|
||||||
.insert(module_id, canonicalization_problems);
|
.insert(module_id, canonicalization_problems);
|
||||||
|
|
||||||
state
|
if let Some(docs) = module_docs {
|
||||||
.module_cache
|
state.module_cache.documentation.insert(module_id, docs);
|
||||||
.documentation
|
}
|
||||||
.insert(module_id, module_docs);
|
|
||||||
|
|
||||||
state
|
state
|
||||||
.module_cache
|
.module_cache
|
||||||
|
@ -1751,6 +1771,7 @@ fn finish_specialization<'a>(
|
||||||
let State {
|
let State {
|
||||||
procedures,
|
procedures,
|
||||||
module_cache,
|
module_cache,
|
||||||
|
output_path,
|
||||||
..
|
..
|
||||||
} = state;
|
} = state;
|
||||||
|
|
||||||
|
@ -1771,6 +1792,7 @@ fn finish_specialization<'a>(
|
||||||
can_problems,
|
can_problems,
|
||||||
mono_problems,
|
mono_problems,
|
||||||
type_problems,
|
type_problems,
|
||||||
|
output_path: output_path.unwrap_or(DEFAULT_APP_OUTPUT_PATH).into(),
|
||||||
exposed_to_host,
|
exposed_to_host,
|
||||||
module_id: state.root_id,
|
module_id: state.root_id,
|
||||||
subs,
|
subs,
|
||||||
|
@ -1967,7 +1989,10 @@ fn parse_header<'a>(
|
||||||
|
|
||||||
match parsed {
|
match parsed {
|
||||||
Ok((ast::Module::Interface { header }, parse_state)) => Ok(send_header(
|
Ok((ast::Module::Interface { header }, parse_state)) => Ok(send_header(
|
||||||
header.name,
|
Located {
|
||||||
|
region: header.name.region,
|
||||||
|
value: AppOrInterfaceName::Interface(header.name.value),
|
||||||
|
},
|
||||||
filename,
|
filename,
|
||||||
header.exposes.into_bump_slice(),
|
header.exposes.into_bump_slice(),
|
||||||
header.imports.into_bump_slice(),
|
header.imports.into_bump_slice(),
|
||||||
|
@ -1981,7 +2006,10 @@ fn parse_header<'a>(
|
||||||
pkg_config_dir.pop();
|
pkg_config_dir.pop();
|
||||||
|
|
||||||
let (module_id, app_module_header_msg) = send_header(
|
let (module_id, app_module_header_msg) = send_header(
|
||||||
header.name,
|
Located {
|
||||||
|
region: header.name.region,
|
||||||
|
value: AppOrInterfaceName::App(header.name.value),
|
||||||
|
},
|
||||||
filename,
|
filename,
|
||||||
header.provides.into_bump_slice(),
|
header.provides.into_bump_slice(),
|
||||||
header.imports.into_bump_slice(),
|
header.imports.into_bump_slice(),
|
||||||
|
@ -2083,21 +2111,35 @@ fn load_from_str<'a>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum AppOrInterfaceName<'a> {
|
||||||
|
/// A filename
|
||||||
|
App(StrLiteral<'a>),
|
||||||
|
Interface(roc_parse::header::ModuleName<'a>),
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn send_header<'a>(
|
fn send_header<'a>(
|
||||||
name: Located<roc_parse::header::ModuleName<'a>>,
|
loc_name: Located<AppOrInterfaceName<'a>>,
|
||||||
filename: PathBuf,
|
filename: PathBuf,
|
||||||
exposes: &'a [Located<ExposesEntry<'a>>],
|
exposes: &'a [Located<ExposesEntry<'a, &'a str>>],
|
||||||
imports: &'a [Located<ImportsEntry<'a>>],
|
imports: &'a [Located<ImportsEntry<'a>>],
|
||||||
parse_state: parser::State<'a>,
|
parse_state: parser::State<'a>,
|
||||||
module_ids: Arc<Mutex<ModuleIds>>,
|
module_ids: Arc<Mutex<ModuleIds>>,
|
||||||
ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
|
ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
|
||||||
module_timing: ModuleTiming,
|
module_timing: ModuleTiming,
|
||||||
) -> (ModuleId, Msg<'a>) {
|
) -> (ModuleId, Msg<'a>) {
|
||||||
let declared_name: ModuleName = name.value.as_str().into();
|
use AppOrInterfaceName::*;
|
||||||
|
|
||||||
// TODO check to see if declared_name is consistent with filename.
|
let declared_name: ModuleName = match &loc_name.value {
|
||||||
// If it isn't, report a problem!
|
App(_) => ModuleName::APP.into(),
|
||||||
|
Interface(module_name) => {
|
||||||
|
// TODO check to see if module_name is consistent with filename.
|
||||||
|
// If it isn't, report a problem!
|
||||||
|
|
||||||
|
module_name.as_str().into()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let mut imported: Vec<(ModuleName, Vec<Ident>, Region)> = Vec::with_capacity(imports.len());
|
let mut imported: Vec<(ModuleName, Vec<Ident>, Region)> = Vec::with_capacity(imports.len());
|
||||||
let mut imported_modules: MutSet<ModuleId> = MutSet::default();
|
let mut imported_modules: MutSet<ModuleId> = MutSet::default();
|
||||||
|
@ -2200,15 +2242,13 @@ fn send_header<'a>(
|
||||||
// We always need to send these, even if deps is empty,
|
// We always need to send these, even if deps is empty,
|
||||||
// because the coordinator thread needs to receive this message
|
// because the coordinator thread needs to receive this message
|
||||||
// to decrement its "pending" count.
|
// to decrement its "pending" count.
|
||||||
|
|
||||||
// Send the header the main thread for processing,
|
|
||||||
(
|
(
|
||||||
home,
|
home,
|
||||||
Msg::Header(ModuleHeader {
|
Msg::Header(ModuleHeader {
|
||||||
module_id: home,
|
module_id: home,
|
||||||
module_path: filename,
|
module_path: filename,
|
||||||
exposed_ident_ids: ident_ids,
|
exposed_ident_ids: ident_ids,
|
||||||
module_name: declared_name,
|
module_name: loc_name.value,
|
||||||
imported_modules,
|
imported_modules,
|
||||||
deps_by_name,
|
deps_by_name,
|
||||||
exposes: exposed,
|
exposes: exposed,
|
||||||
|
@ -2619,8 +2659,14 @@ fn canonicalize_and_constrain<'a>(
|
||||||
|
|
||||||
// Generate documentation information
|
// Generate documentation information
|
||||||
// TODO: store timing information?
|
// TODO: store timing information?
|
||||||
let module_docs =
|
let module_docs = match module_name {
|
||||||
crate::docs::generate_module_docs(module_name, &exposed_ident_ids, &parsed_defs);
|
AppOrInterfaceName::App(_) => None,
|
||||||
|
AppOrInterfaceName::Interface(name) => Some(crate::docs::generate_module_docs(
|
||||||
|
name.as_str().into(),
|
||||||
|
&exposed_ident_ids,
|
||||||
|
&parsed_defs,
|
||||||
|
)),
|
||||||
|
};
|
||||||
|
|
||||||
let mut var_store = VarStore::default();
|
let mut var_store = VarStore::default();
|
||||||
let canonicalized = canonicalize_module_defs(
|
let canonicalized = canonicalize_module_defs(
|
||||||
|
@ -2737,7 +2783,7 @@ fn parse<'a>(arena: &'a Bump, header: ModuleHeader<'a>) -> Result<Msg<'a>, Loadi
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exposed_from_import(entry: &ImportsEntry<'_>) -> (ModuleName, Vec<Ident>) {
|
fn exposed_from_import(entry: &ImportsEntry<'_>) -> (ModuleName, Vec<Ident>) {
|
||||||
use roc_parse::ast::ImportsEntry::*;
|
use roc_parse::header::ImportsEntry::*;
|
||||||
|
|
||||||
match entry {
|
match entry {
|
||||||
Module(module_name, exposes) => {
|
Module(module_name, exposes) => {
|
||||||
|
@ -2750,6 +2796,10 @@ fn exposed_from_import(entry: &ImportsEntry<'_>) -> (ModuleName, Vec<Ident>) {
|
||||||
(module_name.as_str().into(), exposed)
|
(module_name.as_str().into(), exposed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Package(_package_name, _exposes) => {
|
||||||
|
todo!("TODO support exposing package-qualified module names.");
|
||||||
|
}
|
||||||
|
|
||||||
SpaceBefore(sub_entry, _) | SpaceAfter(sub_entry, _) => {
|
SpaceBefore(sub_entry, _) | SpaceAfter(sub_entry, _) => {
|
||||||
// Ignore spaces.
|
// Ignore spaces.
|
||||||
exposed_from_import(*sub_entry)
|
exposed_from_import(*sub_entry)
|
||||||
|
@ -2757,11 +2807,11 @@ fn exposed_from_import(entry: &ImportsEntry<'_>) -> (ModuleName, Vec<Ident>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ident_from_exposed(entry: &ExposesEntry<'_>) -> Ident {
|
fn ident_from_exposed(entry: &ExposesEntry<'_, &str>) -> Ident {
|
||||||
use roc_parse::ast::ExposesEntry::*;
|
use roc_parse::header::ExposesEntry::*;
|
||||||
|
|
||||||
match entry {
|
match entry {
|
||||||
Ident(ident) => (*ident).into(),
|
Exposed(ident) => (*ident).into(),
|
||||||
SpaceBefore(sub_entry, _) | SpaceAfter(sub_entry, _) => ident_from_exposed(sub_entry),
|
SpaceBefore(sub_entry, _) | SpaceAfter(sub_entry, _) => ident_from_exposed(sub_entry),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
app Primary
|
app "primary"
|
||||||
provides [ blah2, blah3, str, alwaysThree, identity, z, w, succeed, withDefault, yay ]
|
packages { blah: "./blah" }
|
||||||
imports [ Dep1, Dep2.{ two, foo }, Dep3.Blah.{ bar }, Res ]
|
imports [ Dep1, Dep2.{ two, foo }, Dep3.Blah.{ bar }, Res ]
|
||||||
|
provides [ blah2, blah3, str, alwaysThree, identity, z, w, succeed, withDefault, yay ] to blah
|
||||||
|
|
||||||
blah2 = Dep2.two
|
blah2 = Dep2.two
|
||||||
blah3 = bar
|
blah3 = bar
|
||||||
|
@ -12,7 +13,7 @@ alwaysThree = \_ -> "foo"
|
||||||
|
|
||||||
identity = \a -> a
|
identity = \a -> a
|
||||||
|
|
||||||
z = identity (Primary.alwaysThree {})
|
z = identity (alwaysThree {})
|
||||||
|
|
||||||
w : Dep1.Identity {}
|
w : Dep1.Identity {}
|
||||||
w = Identity {}
|
w = Identity {}
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
app Quicksort
|
app "quicksort" provides [ swap, partition, partitionHelp, quicksort ] to "./platform"
|
||||||
provides [ swap, partition, partitionHelp, quicksort ]
|
|
||||||
imports []
|
|
||||||
|
|
||||||
quicksort : List (Num a), Int, Int -> List (Num a)
|
quicksort : List (Num a), Int, Int -> List (Num a)
|
||||||
quicksort = \list, low, high ->
|
quicksort = \list, low, high ->
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
app QuicksortOneDef provides [ quicksort ] imports []
|
app "quicksort" provides [ quicksort ] to "./platform"
|
||||||
|
|
||||||
quicksort = \originalList ->
|
quicksort = \originalList ->
|
||||||
quicksortHelp : List (Num a), Int, Int -> List (Num a)
|
quicksortHelp : List (Num a), Int, Int -> List (Num a)
|
||||||
|
@ -53,5 +53,5 @@ quicksort = \originalList ->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
n = List.len originalList
|
n = List.len originalList
|
||||||
quicksortHelp originalList 0 (n - 1)
|
quicksortHelp originalList 0 (n - 1)
|
||||||
|
|
|
@ -23,6 +23,7 @@ mod test_load {
|
||||||
use roc_collections::all::MutMap;
|
use roc_collections::all::MutMap;
|
||||||
use roc_constrain::module::SubsByModule;
|
use roc_constrain::module::SubsByModule;
|
||||||
use roc_load::file::LoadedModule;
|
use roc_load::file::LoadedModule;
|
||||||
|
use roc_module::ident::ModuleName;
|
||||||
use roc_module::symbol::{Interns, ModuleId};
|
use roc_module::symbol::{Interns, ModuleId};
|
||||||
use roc_types::pretty_print::{content_to_string, name_all_type_vars};
|
use roc_types::pretty_print::{content_to_string, name_all_type_vars};
|
||||||
use roc_types::subs::Subs;
|
use roc_types::subs::Subs;
|
||||||
|
@ -148,7 +149,10 @@ mod test_load {
|
||||||
.get_name(loaded_module.module_id)
|
.get_name(loaded_module.module_id)
|
||||||
.expect("Test ModuleID not found in module_ids");
|
.expect("Test ModuleID not found in module_ids");
|
||||||
|
|
||||||
assert_eq!(expected_name, &InlinableString::from(module_name));
|
// App module names are hardcoded and not based on anything user-specified
|
||||||
|
if expected_name != ModuleName::APP {
|
||||||
|
assert_eq!(expected_name, &InlinableString::from(module_name));
|
||||||
|
}
|
||||||
|
|
||||||
loaded_module
|
loaded_module
|
||||||
}
|
}
|
||||||
|
@ -238,31 +242,34 @@ mod test_load {
|
||||||
"RBTree",
|
"RBTree",
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
interface RBTree exposes [ Dict, empty ] imports []
|
interface RBTree exposes [ Dict, empty ] imports []
|
||||||
|
|
||||||
# The color of a node. Leaves are considered Black.
|
# The color of a node. Leaves are considered Black.
|
||||||
NodeColor : [ Red, Black ]
|
NodeColor : [ Red, Black ]
|
||||||
|
|
||||||
Dict k v : [ Node NodeColor k v (Dict k v) (Dict k v), Empty ]
|
Dict k v : [ Node NodeColor k v (Dict k v) (Dict k v), Empty ]
|
||||||
|
|
||||||
# Create an empty dictionary.
|
# Create an empty dictionary.
|
||||||
empty : Dict k v
|
empty : Dict k v
|
||||||
empty =
|
empty =
|
||||||
Empty
|
Empty
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"Main",
|
"Main",
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports [ RBTree ]
|
app "test-app"
|
||||||
|
packages { blah: "./blah" }
|
||||||
|
imports [ RBTree ]
|
||||||
|
provides [ main ] to blah
|
||||||
|
|
||||||
empty : RBTree.Dict Int Int
|
empty : RBTree.Dict Int Int
|
||||||
empty = RBTree.empty
|
empty = RBTree.empty
|
||||||
|
|
||||||
main = empty
|
main = empty
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
|
@ -22,6 +22,7 @@ mod test_uniq_load {
|
||||||
use roc_collections::all::MutMap;
|
use roc_collections::all::MutMap;
|
||||||
use roc_constrain::module::SubsByModule;
|
use roc_constrain::module::SubsByModule;
|
||||||
use roc_load::file::LoadedModule;
|
use roc_load::file::LoadedModule;
|
||||||
|
use roc_module::ident::ModuleName;
|
||||||
use roc_module::symbol::{Interns, ModuleId};
|
use roc_module::symbol::{Interns, ModuleId};
|
||||||
use roc_types::pretty_print::{content_to_string, name_all_type_vars};
|
use roc_types::pretty_print::{content_to_string, name_all_type_vars};
|
||||||
use roc_types::subs::Subs;
|
use roc_types::subs::Subs;
|
||||||
|
@ -66,7 +67,10 @@ mod test_uniq_load {
|
||||||
.get_name(loaded_module.module_id)
|
.get_name(loaded_module.module_id)
|
||||||
.expect("Test ModuleID not found in module_ids");
|
.expect("Test ModuleID not found in module_ids");
|
||||||
|
|
||||||
assert_eq!(expected_name, &InlinableString::from(module_name));
|
// App module names are hardcoded and not based on anything user-specified
|
||||||
|
if expected_name != ModuleName::APP {
|
||||||
|
assert_eq!(expected_name, &InlinableString::from(module_name));
|
||||||
|
}
|
||||||
|
|
||||||
loaded_module
|
loaded_module
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,7 @@ impl TagName {
|
||||||
impl ModuleName {
|
impl ModuleName {
|
||||||
// NOTE: After adding one of these, go to `impl ModuleId` and
|
// NOTE: After adding one of these, go to `impl ModuleId` and
|
||||||
// add a corresponding ModuleId to there!
|
// add a corresponding ModuleId to there!
|
||||||
|
pub const APP: &'static str = ""; // app modules have no module name
|
||||||
pub const BOOL: &'static str = "Bool";
|
pub const BOOL: &'static str = "Bool";
|
||||||
pub const STR: &'static str = "Str";
|
pub const STR: &'static str = "Str";
|
||||||
pub const NUM: &'static str = "Num";
|
pub const NUM: &'static str = "Num";
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,7 +1,6 @@
|
||||||
use crate::header::{ModuleName, PackageName};
|
use crate::header::{AppHeader, ImportsEntry, InterfaceHeader, PlatformHeader, TypedIdent};
|
||||||
use crate::ident::Ident;
|
use crate::ident::Ident;
|
||||||
use bumpalo::collections::String;
|
use bumpalo::collections::String;
|
||||||
use bumpalo::collections::Vec;
|
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_module::operator::{BinOp, CalledVia, UnaryOp};
|
use roc_module::operator::{BinOp, CalledVia, UnaryOp};
|
||||||
use roc_region::all::{Loc, Region};
|
use roc_region::all::{Loc, Region};
|
||||||
|
@ -13,20 +12,6 @@ pub enum Module<'a> {
|
||||||
Platform { header: PlatformHeader<'a> },
|
Platform { header: PlatformHeader<'a> },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct InterfaceHeader<'a> {
|
|
||||||
pub name: Loc<ModuleName<'a>>,
|
|
||||||
pub exposes: Vec<'a, Loc<ExposesEntry<'a>>>,
|
|
||||||
pub imports: Vec<'a, Loc<ImportsEntry<'a>>>,
|
|
||||||
|
|
||||||
// Potential comments and newlines - these will typically all be empty.
|
|
||||||
pub after_interface_keyword: &'a [CommentOrNewline<'a>],
|
|
||||||
pub before_exposes: &'a [CommentOrNewline<'a>],
|
|
||||||
pub after_exposes: &'a [CommentOrNewline<'a>],
|
|
||||||
pub before_imports: &'a [CommentOrNewline<'a>],
|
|
||||||
pub after_imports: &'a [CommentOrNewline<'a>],
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct WhenBranch<'a> {
|
pub struct WhenBranch<'a> {
|
||||||
pub patterns: &'a [Loc<Pattern<'a>>],
|
pub patterns: &'a [Loc<Pattern<'a>>],
|
||||||
|
@ -34,94 +19,6 @@ pub struct WhenBranch<'a> {
|
||||||
pub guard: Option<Loc<Expr<'a>>>,
|
pub guard: Option<Loc<Expr<'a>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct AppHeader<'a> {
|
|
||||||
pub name: Loc<ModuleName<'a>>,
|
|
||||||
pub provides: Vec<'a, Loc<ExposesEntry<'a>>>,
|
|
||||||
pub imports: Vec<'a, Loc<ImportsEntry<'a>>>,
|
|
||||||
|
|
||||||
// Potential comments and newlines - these will typically all be empty.
|
|
||||||
pub after_app_keyword: &'a [CommentOrNewline<'a>],
|
|
||||||
pub before_provides: &'a [CommentOrNewline<'a>],
|
|
||||||
pub after_provides: &'a [CommentOrNewline<'a>],
|
|
||||||
pub before_imports: &'a [CommentOrNewline<'a>],
|
|
||||||
pub after_imports: &'a [CommentOrNewline<'a>],
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct PlatformHeader<'a> {
|
|
||||||
pub name: Loc<PackageName<'a>>,
|
|
||||||
pub provides: Vec<'a, Loc<ExposesEntry<'a>>>,
|
|
||||||
pub requires: Vec<'a, Loc<TypedIdent<'a>>>,
|
|
||||||
pub imports: Vec<'a, Loc<ImportsEntry<'a>>>,
|
|
||||||
pub effects: Effects<'a>,
|
|
||||||
|
|
||||||
// Potential comments and newlines - these will typically all be empty.
|
|
||||||
pub after_platform_keyword: &'a [CommentOrNewline<'a>],
|
|
||||||
pub before_provides: &'a [CommentOrNewline<'a>],
|
|
||||||
pub after_provides: &'a [CommentOrNewline<'a>],
|
|
||||||
pub before_requires: &'a [CommentOrNewline<'a>],
|
|
||||||
pub after_requires: &'a [CommentOrNewline<'a>],
|
|
||||||
pub before_imports: &'a [CommentOrNewline<'a>],
|
|
||||||
pub after_imports: &'a [CommentOrNewline<'a>],
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct Effects<'a> {
|
|
||||||
pub spaces_before_effects_keyword: &'a [CommentOrNewline<'a>],
|
|
||||||
pub spaces_after_effects_keyword: &'a [CommentOrNewline<'a>],
|
|
||||||
pub spaces_after_type_name: &'a [CommentOrNewline<'a>],
|
|
||||||
pub type_name: &'a str,
|
|
||||||
pub entries: Vec<'a, Loc<TypedIdent<'a>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub enum TypedIdent<'a> {
|
|
||||||
/// e.g.
|
|
||||||
///
|
|
||||||
/// printLine : Str -> Effect {}
|
|
||||||
Entry {
|
|
||||||
ident: Loc<&'a str>,
|
|
||||||
spaces_before_colon: &'a [CommentOrNewline<'a>],
|
|
||||||
ann: Loc<TypeAnnotation<'a>>,
|
|
||||||
},
|
|
||||||
|
|
||||||
// Spaces
|
|
||||||
SpaceBefore(&'a TypedIdent<'a>, &'a [CommentOrNewline<'a>]),
|
|
||||||
SpaceAfter(&'a TypedIdent<'a>, &'a [CommentOrNewline<'a>]),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub enum ExposesEntry<'a> {
|
|
||||||
/// e.g. `Task`
|
|
||||||
Ident(&'a str),
|
|
||||||
|
|
||||||
// Spaces
|
|
||||||
SpaceBefore(&'a ExposesEntry<'a>, &'a [CommentOrNewline<'a>]),
|
|
||||||
SpaceAfter(&'a ExposesEntry<'a>, &'a [CommentOrNewline<'a>]),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub enum ImportsEntry<'a> {
|
|
||||||
/// e.g. `Task` or `Task.{ Task, after }`
|
|
||||||
Module(ModuleName<'a>, Vec<'a, Loc<ExposesEntry<'a>>>),
|
|
||||||
|
|
||||||
// Spaces
|
|
||||||
SpaceBefore(&'a ImportsEntry<'a>, &'a [CommentOrNewline<'a>]),
|
|
||||||
SpaceAfter(&'a ImportsEntry<'a>, &'a [CommentOrNewline<'a>]),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ExposesEntry<'a> {
|
|
||||||
pub fn as_str(&'a self) -> &'a str {
|
|
||||||
use ExposesEntry::*;
|
|
||||||
|
|
||||||
match self {
|
|
||||||
Ident(string) => string,
|
|
||||||
SpaceBefore(sub_entry, _) | SpaceAfter(sub_entry, _) => sub_entry.as_str(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct WhenPattern<'a> {
|
pub struct WhenPattern<'a> {
|
||||||
pub pattern: Loc<Pattern<'a>>,
|
pub pattern: Loc<Pattern<'a>>,
|
||||||
|
@ -633,15 +530,6 @@ impl<'a> Spaceable<'a> for TypeAnnotation<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Spaceable<'a> for ExposesEntry<'a> {
|
|
||||||
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
|
||||||
ExposesEntry::SpaceBefore(self, spaces)
|
|
||||||
}
|
|
||||||
fn after(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
|
||||||
ExposesEntry::SpaceAfter(self, spaces)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Spaceable<'a> for ImportsEntry<'a> {
|
impl<'a> Spaceable<'a> for ImportsEntry<'a> {
|
||||||
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||||
ImportsEntry::SpaceBefore(self, spaces)
|
ImportsEntry::SpaceBefore(self, spaces)
|
||||||
|
|
|
@ -1730,17 +1730,8 @@ fn ident_etc<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
|
||||||
};
|
};
|
||||||
let region = loc_ident.region;
|
let region = loc_ident.region;
|
||||||
let loc_pattern = Located { region, value };
|
let loc_pattern = Located { region, value };
|
||||||
let (spaces_after_colon, state) = space0(min_indent).parse(arena, state)?;
|
|
||||||
let (parsed_expr, state) =
|
|
||||||
parse_def_signature(min_indent, colon_indent, arena, state, loc_pattern)?;
|
|
||||||
|
|
||||||
let answer = if spaces_after_colon.is_empty() {
|
parse_def_signature(min_indent, colon_indent, arena, state, loc_pattern)
|
||||||
parsed_expr
|
|
||||||
} else {
|
|
||||||
Expr::SpaceBefore(arena.alloc(parsed_expr), spaces_after_colon)
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok((answer, state))
|
|
||||||
}
|
}
|
||||||
(None, None) => {
|
(None, None) => {
|
||||||
// We got nothin'
|
// We got nothin'
|
||||||
|
@ -1977,17 +1968,8 @@ fn record_literal<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
|
||||||
Pattern::SpaceAfter(arena.alloc(pattern), spaces_before_colon)
|
Pattern::SpaceAfter(arena.alloc(pattern), spaces_before_colon)
|
||||||
};
|
};
|
||||||
let loc_pattern = Located { region, value };
|
let loc_pattern = Located { region, value };
|
||||||
let (spaces_after_equals, state) = space0(min_indent).parse(arena, state)?;
|
|
||||||
let (parsed_expr, state) =
|
|
||||||
parse_def_signature(min_indent, colon_indent, arena, state, loc_pattern)?;
|
|
||||||
|
|
||||||
let answer = if spaces_after_equals.is_empty() {
|
parse_def_signature(min_indent, colon_indent, arena, state, loc_pattern)
|
||||||
parsed_expr
|
|
||||||
} else {
|
|
||||||
Expr::SpaceBefore(arena.alloc(parsed_expr), spaces_after_equals)
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok((answer, state))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,15 +1,43 @@
|
||||||
use crate::ast::CommentOrNewline;
|
use crate::ast::{CommentOrNewline, Spaceable, StrLiteral, TypeAnnotation};
|
||||||
|
use crate::blankspace::space0;
|
||||||
|
use crate::ident::lowercase_ident;
|
||||||
|
use crate::module::package_name;
|
||||||
|
use crate::parser::{ascii_char, optional, Either, Parser};
|
||||||
|
use crate::string_literal;
|
||||||
use bumpalo::collections::Vec;
|
use bumpalo::collections::Vec;
|
||||||
use inlinable_string::InlinableString;
|
use inlinable_string::InlinableString;
|
||||||
use roc_region::all::Loc;
|
use roc_region::all::Loc;
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
pub struct PackageName<'a> {
|
pub struct PackageName<'a> {
|
||||||
pub account: &'a str,
|
pub account: &'a str,
|
||||||
pub pkg: &'a str,
|
pub pkg: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
|
pub enum Version<'a> {
|
||||||
|
Exact(&'a str),
|
||||||
|
Range {
|
||||||
|
min: &'a str,
|
||||||
|
min_comparison: VersionComparison,
|
||||||
|
max: &'a str,
|
||||||
|
max_comparison: VersionComparison,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
|
pub enum VersionComparison {
|
||||||
|
AllowsEqual,
|
||||||
|
DisallowsEqual,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
pub enum PackageOrPath<'a> {
|
||||||
|
Package(PackageName<'a>, Version<'a>),
|
||||||
|
Path(StrLiteral<'a>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
pub struct ModuleName<'a>(&'a str);
|
pub struct ModuleName<'a>(&'a str);
|
||||||
|
|
||||||
impl<'a> Into<&'a str> for ModuleName<'a> {
|
impl<'a> Into<&'a str> for ModuleName<'a> {
|
||||||
|
@ -34,46 +62,224 @@ impl<'a> ModuleName<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO is this all duplicated from parse::ast?
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct InterfaceHeader<'a> {
|
pub struct InterfaceHeader<'a> {
|
||||||
pub name: Loc<ModuleName<'a>>,
|
pub name: Loc<ModuleName<'a>>,
|
||||||
pub exposes: Vec<'a, Loc<Exposes<'a>>>,
|
pub exposes: Vec<'a, Loc<ExposesEntry<'a, &'a str>>>,
|
||||||
pub imports: Vec<'a, (ModuleName<'a>, Vec<'a, Loc<Imports<'a>>>)>,
|
pub imports: Vec<'a, Loc<ImportsEntry<'a>>>,
|
||||||
|
|
||||||
// Potential comments and newlines - these will typically all be empty.
|
// Potential comments and newlines - these will typically all be empty.
|
||||||
pub after_interface: &'a [CommentOrNewline<'a>],
|
pub after_interface_keyword: &'a [CommentOrNewline<'a>],
|
||||||
pub before_exposes: &'a [CommentOrNewline<'a>],
|
pub before_exposes: &'a [CommentOrNewline<'a>],
|
||||||
pub after_exposes: &'a [CommentOrNewline<'a>],
|
pub after_exposes: &'a [CommentOrNewline<'a>],
|
||||||
pub before_imports: &'a [CommentOrNewline<'a>],
|
pub before_imports: &'a [CommentOrNewline<'a>],
|
||||||
pub after_imports: &'a [CommentOrNewline<'a>],
|
pub after_imports: &'a [CommentOrNewline<'a>],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum To<'a> {
|
||||||
|
ExistingPackage(&'a str),
|
||||||
|
NewPackage(PackageOrPath<'a>),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct AppHeader<'a> {
|
pub struct AppHeader<'a> {
|
||||||
pub imports: Vec<'a, (ModuleName<'a>, Loc<Imports<'a>>)>,
|
pub name: Loc<StrLiteral<'a>>,
|
||||||
|
pub packages: Vec<'a, Loc<PackageEntry<'a>>>,
|
||||||
|
pub imports: Vec<'a, Loc<ImportsEntry<'a>>>,
|
||||||
|
pub provides: Vec<'a, Loc<ExposesEntry<'a, &'a str>>>,
|
||||||
|
pub to: Loc<To<'a>>,
|
||||||
|
|
||||||
// Potential comments and newlines - these will typically all be empty.
|
// Potential comments and newlines - these will typically all be empty.
|
||||||
|
pub after_app_keyword: &'a [CommentOrNewline<'a>],
|
||||||
|
pub before_packages: &'a [CommentOrNewline<'a>],
|
||||||
|
pub after_packages: &'a [CommentOrNewline<'a>],
|
||||||
|
pub before_imports: &'a [CommentOrNewline<'a>],
|
||||||
|
pub after_imports: &'a [CommentOrNewline<'a>],
|
||||||
|
pub before_provides: &'a [CommentOrNewline<'a>],
|
||||||
|
pub after_provides: &'a [CommentOrNewline<'a>],
|
||||||
|
pub before_to: &'a [CommentOrNewline<'a>],
|
||||||
|
pub after_to: &'a [CommentOrNewline<'a>],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct PackageHeader<'a> {
|
||||||
|
pub name: Loc<PackageName<'a>>,
|
||||||
|
pub exposes: Vec<'a, Loc<ExposesEntry<'a, &'a str>>>,
|
||||||
|
pub packages: Vec<'a, (Loc<&'a str>, Loc<PackageOrPath<'a>>)>,
|
||||||
|
pub imports: Vec<'a, Loc<ImportsEntry<'a>>>,
|
||||||
|
|
||||||
|
// Potential comments and newlines - these will typically all be empty.
|
||||||
|
pub after_package_keyword: &'a [CommentOrNewline<'a>],
|
||||||
|
pub before_exposes: &'a [CommentOrNewline<'a>],
|
||||||
|
pub after_exposes: &'a [CommentOrNewline<'a>],
|
||||||
|
pub before_packages: &'a [CommentOrNewline<'a>],
|
||||||
|
pub after_packages: &'a [CommentOrNewline<'a>],
|
||||||
pub before_imports: &'a [CommentOrNewline<'a>],
|
pub before_imports: &'a [CommentOrNewline<'a>],
|
||||||
pub after_imports: &'a [CommentOrNewline<'a>],
|
pub after_imports: &'a [CommentOrNewline<'a>],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum Exposes<'a> {
|
pub struct PlatformHeader<'a> {
|
||||||
/// e.g. `Task`
|
pub name: Loc<PackageName<'a>>,
|
||||||
Ident(&'a str),
|
pub requires: Vec<'a, Loc<TypedIdent<'a>>>,
|
||||||
|
pub exposes: Vec<'a, Loc<ExposesEntry<'a, ModuleName<'a>>>>,
|
||||||
|
pub packages: Vec<'a, Loc<PackageEntry<'a>>>,
|
||||||
|
pub imports: Vec<'a, Loc<ImportsEntry<'a>>>,
|
||||||
|
pub provides: Vec<'a, Loc<ExposesEntry<'a, &'a str>>>,
|
||||||
|
pub effects: Effects<'a>,
|
||||||
|
|
||||||
// Spaces
|
// Potential comments and newlines - these will typically all be empty.
|
||||||
SpaceBefore(&'a Exposes<'a>, &'a [CommentOrNewline<'a>]),
|
pub after_platform_keyword: &'a [CommentOrNewline<'a>],
|
||||||
SpaceAfter(&'a Exposes<'a>, &'a [CommentOrNewline<'a>]),
|
pub before_requires: &'a [CommentOrNewline<'a>],
|
||||||
|
pub after_requires: &'a [CommentOrNewline<'a>],
|
||||||
|
pub before_exposes: &'a [CommentOrNewline<'a>],
|
||||||
|
pub after_exposes: &'a [CommentOrNewline<'a>],
|
||||||
|
pub before_packages: &'a [CommentOrNewline<'a>],
|
||||||
|
pub after_packages: &'a [CommentOrNewline<'a>],
|
||||||
|
pub before_imports: &'a [CommentOrNewline<'a>],
|
||||||
|
pub after_imports: &'a [CommentOrNewline<'a>],
|
||||||
|
pub before_provides: &'a [CommentOrNewline<'a>],
|
||||||
|
pub after_provides: &'a [CommentOrNewline<'a>],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum Imports<'a> {
|
pub struct Effects<'a> {
|
||||||
/// e.g. `Task` or `Task.{ Task, after }`
|
pub spaces_before_effects_keyword: &'a [CommentOrNewline<'a>],
|
||||||
Ident(&'a str, Vec<'a, &'a str>),
|
pub spaces_after_effects_keyword: &'a [CommentOrNewline<'a>],
|
||||||
|
pub spaces_after_type_name: &'a [CommentOrNewline<'a>],
|
||||||
|
pub type_name: &'a str,
|
||||||
|
pub entries: Vec<'a, Loc<TypedIdent<'a>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum ExposesEntry<'a, T> {
|
||||||
|
/// e.g. `Task`
|
||||||
|
Exposed(T),
|
||||||
|
|
||||||
// Spaces
|
// Spaces
|
||||||
SpaceBefore(&'a Imports<'a>, &'a [CommentOrNewline<'a>]),
|
SpaceBefore(&'a ExposesEntry<'a, T>, &'a [CommentOrNewline<'a>]),
|
||||||
SpaceAfter(&'a Imports<'a>, &'a [CommentOrNewline<'a>]),
|
SpaceAfter(&'a ExposesEntry<'a, T>, &'a [CommentOrNewline<'a>]),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Spaceable<'a> for ExposesEntry<'a, T> {
|
||||||
|
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||||
|
ExposesEntry::SpaceBefore(self, spaces)
|
||||||
|
}
|
||||||
|
fn after(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||||
|
ExposesEntry::SpaceAfter(self, spaces)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum ImportsEntry<'a> {
|
||||||
|
/// e.g. `Task` or `Task.{ Task, after }`
|
||||||
|
Module(ModuleName<'a>, Vec<'a, Loc<ExposesEntry<'a, &'a str>>>),
|
||||||
|
|
||||||
|
/// e.g. `base.Task` or `base.Task.{ after }` or `base.{ Task.{ Task, after } }`
|
||||||
|
Package(&'a str, Vec<'a, Loc<&'a ImportsEntry<'a>>>),
|
||||||
|
|
||||||
|
// Spaces
|
||||||
|
SpaceBefore(&'a ImportsEntry<'a>, &'a [CommentOrNewline<'a>]),
|
||||||
|
SpaceAfter(&'a ImportsEntry<'a>, &'a [CommentOrNewline<'a>]),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ExposesEntry<'a, &'a str> {
|
||||||
|
pub fn as_str(&'a self) -> &'a str {
|
||||||
|
use ExposesEntry::*;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
Exposed(string) => string,
|
||||||
|
SpaceBefore(sub_entry, _) | SpaceAfter(sub_entry, _) => sub_entry.as_str(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum TypedIdent<'a> {
|
||||||
|
/// e.g.
|
||||||
|
///
|
||||||
|
/// printLine : Str -> Effect {}
|
||||||
|
Entry {
|
||||||
|
ident: Loc<&'a str>,
|
||||||
|
spaces_before_colon: &'a [CommentOrNewline<'a>],
|
||||||
|
ann: Loc<TypeAnnotation<'a>>,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Spaces
|
||||||
|
SpaceBefore(&'a TypedIdent<'a>, &'a [CommentOrNewline<'a>]),
|
||||||
|
SpaceAfter(&'a TypedIdent<'a>, &'a [CommentOrNewline<'a>]),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum PackageEntry<'a> {
|
||||||
|
Entry {
|
||||||
|
shorthand: &'a str,
|
||||||
|
spaces_after_shorthand: &'a [CommentOrNewline<'a>],
|
||||||
|
package_or_path: Loc<PackageOrPath<'a>>,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Spaces
|
||||||
|
SpaceBefore(&'a PackageEntry<'a>, &'a [CommentOrNewline<'a>]),
|
||||||
|
SpaceAfter(&'a PackageEntry<'a>, &'a [CommentOrNewline<'a>]),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Spaceable<'a> for PackageEntry<'a> {
|
||||||
|
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||||
|
PackageEntry::SpaceBefore(self, spaces)
|
||||||
|
}
|
||||||
|
fn after(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||||
|
PackageEntry::SpaceAfter(self, spaces)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn package_entry<'a>() -> impl Parser<'a, PackageEntry<'a>> {
|
||||||
|
move |arena, state| {
|
||||||
|
// You may optionally have a package shorthand,
|
||||||
|
// e.g. "uc" in `uc: roc/unicode 1.0.0`
|
||||||
|
//
|
||||||
|
// (Indirect dependencies don't have a shorthand.)
|
||||||
|
let (opt_shorthand, state) = optional(and!(
|
||||||
|
skip_second!(lowercase_ident(), ascii_char(b':')),
|
||||||
|
space0(1)
|
||||||
|
))
|
||||||
|
.parse(arena, state)?;
|
||||||
|
let (package_or_path, state) = loc!(package_or_path()).parse(arena, state)?;
|
||||||
|
let entry = match opt_shorthand {
|
||||||
|
Some((shorthand, spaces_after_shorthand)) => PackageEntry::Entry {
|
||||||
|
shorthand,
|
||||||
|
spaces_after_shorthand,
|
||||||
|
package_or_path,
|
||||||
|
},
|
||||||
|
None => PackageEntry::Entry {
|
||||||
|
shorthand: "",
|
||||||
|
spaces_after_shorthand: &[],
|
||||||
|
package_or_path,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((entry, state))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn package_or_path<'a>() -> impl Parser<'a, PackageOrPath<'a>> {
|
||||||
|
map!(
|
||||||
|
either!(
|
||||||
|
string_literal::parse(),
|
||||||
|
and!(
|
||||||
|
package_name(),
|
||||||
|
skip_first!(one_or_more!(ascii_char(b' ')), package_version())
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|answer| {
|
||||||
|
match answer {
|
||||||
|
Either::First(str_literal) => PackageOrPath::Path(str_literal),
|
||||||
|
Either::Second((name, version)) => PackageOrPath::Package(name, version),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn package_version<'a>() -> impl Parser<'a, Version<'a>> {
|
||||||
|
move |_, _| todo!("TODO parse package version")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
use crate::ast::{
|
use crate::ast::{Attempting, CommentOrNewline, Def, Module};
|
||||||
AppHeader, Attempting, CommentOrNewline, Def, Effects, ExposesEntry, ImportsEntry,
|
|
||||||
InterfaceHeader, Module, PlatformHeader, TypedIdent,
|
|
||||||
};
|
|
||||||
use crate::blankspace::{space0, space0_around, space0_before, space1};
|
use crate::blankspace::{space0, space0_around, space0_before, space1};
|
||||||
use crate::expr::def;
|
use crate::expr::def;
|
||||||
use crate::header::{ModuleName, PackageName};
|
use crate::header::{
|
||||||
|
package_entry, package_or_path, AppHeader, Effects, ExposesEntry, ImportsEntry,
|
||||||
|
InterfaceHeader, ModuleName, PackageEntry, PackageName, PackageOrPath, PlatformHeader, To,
|
||||||
|
TypedIdent,
|
||||||
|
};
|
||||||
use crate::ident::{lowercase_ident, unqualified_ident, uppercase_ident};
|
use crate::ident::{lowercase_ident, unqualified_ident, uppercase_ident};
|
||||||
use crate::parser::{
|
use crate::parser::{
|
||||||
self, ascii_char, ascii_string, loc, optional, peek_utf8_char, peek_utf8_char_at, unexpected,
|
self, ascii_char, ascii_string, loc, optional, peek_utf8_char, peek_utf8_char_at, unexpected,
|
||||||
unexpected_eof, ParseResult, Parser, State,
|
unexpected_eof, Either, ParseResult, Parser, State,
|
||||||
};
|
};
|
||||||
|
use crate::string_literal;
|
||||||
use crate::type_annotation;
|
use crate::type_annotation;
|
||||||
use bumpalo::collections::{String, Vec};
|
use bumpalo::collections::{String, Vec};
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
|
@ -44,7 +46,7 @@ pub fn interface_header<'a>() -> impl Parser<'a, InterfaceHeader<'a>> {
|
||||||
ascii_string("interface"),
|
ascii_string("interface"),
|
||||||
and!(space1(1), loc!(module_name()))
|
and!(space1(1), loc!(module_name()))
|
||||||
),
|
),
|
||||||
and!(exposes(), imports())
|
and!(exposes_values(), imports())
|
||||||
),
|
),
|
||||||
|(
|
|(
|
||||||
(after_interface_keyword, name),
|
(after_interface_keyword, name),
|
||||||
|
@ -173,66 +175,114 @@ pub fn module_name<'a>() -> impl Parser<'a, ModuleName<'a>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn app_header<'a>() -> impl Parser<'a, AppHeader<'a>> {
|
pub fn app_header<'a>() -> impl Parser<'a, AppHeader<'a>> {
|
||||||
parser::map(
|
map_with_arena!(
|
||||||
and!(
|
and!(
|
||||||
skip_first!(ascii_string("app"), and!(space1(1), loc!(module_name()))),
|
skip_first!(
|
||||||
and!(provides(), imports())
|
ascii_string("app"),
|
||||||
),
|
and!(space1(1), loc!(string_literal::parse()))
|
||||||
|(
|
|
||||||
(after_app_keyword, name),
|
|
||||||
(
|
|
||||||
((before_provides, after_provides), provides),
|
|
||||||
((before_imports, after_imports), imports),
|
|
||||||
),
|
),
|
||||||
)| {
|
and!(
|
||||||
|
optional(packages()),
|
||||||
|
and!(optional(imports()), provides_to())
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|arena, ((after_app_keyword, name), (opt_pkgs, (opt_imports, provides)))| {
|
||||||
|
let (before_packages, after_packages, package_entries) = match opt_pkgs {
|
||||||
|
Some(pkgs) => {
|
||||||
|
let pkgs: Packages<'a> = pkgs; // rustc must be told the type here
|
||||||
|
|
||||||
|
(
|
||||||
|
pkgs.before_packages_keyword,
|
||||||
|
pkgs.after_packages_keyword,
|
||||||
|
pkgs.entries,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
None => (&[] as _, &[] as _, Vec::new_in(arena)),
|
||||||
|
};
|
||||||
|
|
||||||
|
// rustc must be told the type here
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
let opt_imports: Option<(
|
||||||
|
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
|
||||||
|
Vec<'a, Located<ImportsEntry<'a>>>,
|
||||||
|
)> = opt_imports;
|
||||||
|
|
||||||
|
let ((before_imports, after_imports), imports) =
|
||||||
|
opt_imports.unwrap_or_else(|| ((&[] as _, &[] as _), Vec::new_in(arena)));
|
||||||
|
let provides: ProvidesTo<'a> = provides; // rustc must be told the type here
|
||||||
|
|
||||||
AppHeader {
|
AppHeader {
|
||||||
name,
|
name,
|
||||||
provides,
|
packages: package_entries,
|
||||||
imports,
|
imports,
|
||||||
|
provides: provides.entries,
|
||||||
|
to: provides.to,
|
||||||
after_app_keyword,
|
after_app_keyword,
|
||||||
before_provides,
|
before_packages,
|
||||||
after_provides,
|
after_packages,
|
||||||
before_imports,
|
before_imports,
|
||||||
after_imports,
|
after_imports,
|
||||||
|
before_provides: provides.before_provides_keyword,
|
||||||
|
after_provides: provides.after_provides_keyword,
|
||||||
|
before_to: provides.before_to_keyword,
|
||||||
|
after_to: provides.after_to_keyword,
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn platform_header<'a>() -> impl Parser<'a, PlatformHeader<'a>> {
|
pub fn platform_header<'a>() -> impl Parser<'a, PlatformHeader<'a>> {
|
||||||
parser::map(
|
parser::map(
|
||||||
and!(
|
and!(
|
||||||
skip_first!(
|
skip_first!(
|
||||||
ascii_string("platform"),
|
ascii_string("platform"),
|
||||||
and!(space1(1), loc!(package_name()))
|
and!(space1(1), loc!(package_name()))
|
||||||
),
|
),
|
||||||
and!(provides(), and!(requires(), and!(imports(), effects())))
|
and!(
|
||||||
|
and!(
|
||||||
|
and!(requires(), and!(exposes_modules(), packages())),
|
||||||
|
and!(imports(), provides_without_to())
|
||||||
|
),
|
||||||
|
effects()
|
||||||
|
)
|
||||||
),
|
),
|
||||||
|(
|
|(
|
||||||
(after_platform_keyword, name),
|
(after_platform_keyword, name),
|
||||||
(
|
(
|
||||||
((before_provides, after_provides), provides),
|
|
||||||
(
|
(
|
||||||
((before_requires, after_requires), requires),
|
(
|
||||||
(((before_imports, after_imports), imports), effects),
|
((before_requires, after_requires), requires),
|
||||||
|
(((before_exposes, after_exposes), exposes), packages),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
((before_imports, after_imports), imports),
|
||||||
|
((before_provides, after_provides), provides),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
effects,
|
||||||
),
|
),
|
||||||
)| {
|
)| {
|
||||||
PlatformHeader {
|
PlatformHeader {
|
||||||
name,
|
name,
|
||||||
provides,
|
|
||||||
requires,
|
requires,
|
||||||
|
exposes,
|
||||||
|
packages: packages.entries,
|
||||||
imports,
|
imports,
|
||||||
|
provides,
|
||||||
effects,
|
effects,
|
||||||
after_platform_keyword,
|
after_platform_keyword,
|
||||||
before_provides,
|
|
||||||
after_provides,
|
|
||||||
before_requires,
|
before_requires,
|
||||||
after_requires,
|
after_requires,
|
||||||
|
before_exposes,
|
||||||
|
after_exposes,
|
||||||
|
before_packages: packages.before_packages_keyword,
|
||||||
|
after_packages: packages.after_packages_keyword,
|
||||||
before_imports,
|
before_imports,
|
||||||
after_imports,
|
after_imports,
|
||||||
|
before_provides,
|
||||||
|
after_provides,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -243,19 +293,80 @@ pub fn module_defs<'a>() -> impl Parser<'a, Vec<'a, Located<Def<'a>>>> {
|
||||||
zero_or_more!(space0_around(loc(def(0)), 0))
|
zero_or_more!(space0_around(loc(def(0)), 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ProvidesTo<'a> {
|
||||||
|
entries: Vec<'a, Located<ExposesEntry<'a, &'a str>>>,
|
||||||
|
to: Located<To<'a>>,
|
||||||
|
|
||||||
|
before_provides_keyword: &'a [CommentOrNewline<'a>],
|
||||||
|
after_provides_keyword: &'a [CommentOrNewline<'a>],
|
||||||
|
before_to_keyword: &'a [CommentOrNewline<'a>],
|
||||||
|
after_to_keyword: &'a [CommentOrNewline<'a>],
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn provides<'a>() -> impl Parser<
|
fn provides_to<'a>() -> impl Parser<'a, ProvidesTo<'a>> {
|
||||||
|
map!(
|
||||||
|
and!(
|
||||||
|
and!(skip_second!(space1(1), ascii_string("provides")), space1(1)),
|
||||||
|
and!(
|
||||||
|
collection!(
|
||||||
|
ascii_char(b'['),
|
||||||
|
loc!(map!(unqualified_ident(), ExposesEntry::Exposed)),
|
||||||
|
ascii_char(b','),
|
||||||
|
ascii_char(b']'),
|
||||||
|
1
|
||||||
|
),
|
||||||
|
and!(
|
||||||
|
space1(1),
|
||||||
|
skip_first!(
|
||||||
|
ascii_string("to"),
|
||||||
|
and!(
|
||||||
|
space1(1),
|
||||||
|
loc!(either!(lowercase_ident(), package_or_path()))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|(
|
||||||
|
(before_provides_keyword, after_provides_keyword),
|
||||||
|
(entries, (before_to_keyword, (after_to_keyword, loc_to))),
|
||||||
|
)| {
|
||||||
|
let loc_to: Located<Either<&'a str, PackageOrPath<'a>>> = loc_to;
|
||||||
|
let to_val = match loc_to.value {
|
||||||
|
Either::First(pkg) => To::ExistingPackage(pkg),
|
||||||
|
Either::Second(pkg) => To::NewPackage(pkg),
|
||||||
|
};
|
||||||
|
let to = Located {
|
||||||
|
value: to_val,
|
||||||
|
region: loc_to.region,
|
||||||
|
};
|
||||||
|
|
||||||
|
ProvidesTo {
|
||||||
|
entries,
|
||||||
|
to,
|
||||||
|
before_provides_keyword,
|
||||||
|
after_provides_keyword,
|
||||||
|
before_to_keyword,
|
||||||
|
after_to_keyword,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn provides_without_to<'a>() -> impl Parser<
|
||||||
'a,
|
'a,
|
||||||
(
|
(
|
||||||
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
|
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
|
||||||
Vec<'a, Located<ExposesEntry<'a>>>,
|
Vec<'a, Located<ExposesEntry<'a, &'a str>>>,
|
||||||
),
|
),
|
||||||
> {
|
> {
|
||||||
and!(
|
and!(
|
||||||
and!(skip_second!(space1(1), ascii_string("provides")), space1(1)),
|
and!(skip_second!(space1(1), ascii_string("provides")), space1(1)),
|
||||||
collection!(
|
collection!(
|
||||||
ascii_char(b'['),
|
ascii_char(b'['),
|
||||||
loc!(exposes_entry()),
|
loc!(map!(unqualified_ident(), ExposesEntry::Exposed)),
|
||||||
ascii_char(b','),
|
ascii_char(b','),
|
||||||
ascii_char(b']'),
|
ascii_char(b']'),
|
||||||
1
|
1
|
||||||
|
@ -284,18 +395,18 @@ fn requires<'a>() -> impl Parser<
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn exposes<'a>() -> impl Parser<
|
fn exposes_values<'a>() -> impl Parser<
|
||||||
'a,
|
'a,
|
||||||
(
|
(
|
||||||
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
|
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
|
||||||
Vec<'a, Located<ExposesEntry<'a>>>,
|
Vec<'a, Located<ExposesEntry<'a, &'a str>>>,
|
||||||
),
|
),
|
||||||
> {
|
> {
|
||||||
and!(
|
and!(
|
||||||
and!(skip_second!(space1(1), ascii_string("exposes")), space1(1)),
|
and!(skip_second!(space1(1), ascii_string("exposes")), space1(1)),
|
||||||
collection!(
|
collection!(
|
||||||
ascii_char(b'['),
|
ascii_char(b'['),
|
||||||
loc!(exposes_entry()),
|
loc!(map!(unqualified_ident(), ExposesEntry::Exposed)),
|
||||||
ascii_char(b','),
|
ascii_char(b','),
|
||||||
ascii_char(b']'),
|
ascii_char(b']'),
|
||||||
1
|
1
|
||||||
|
@ -303,6 +414,56 @@ fn exposes<'a>() -> impl Parser<
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn exposes_modules<'a>() -> impl Parser<
|
||||||
|
'a,
|
||||||
|
(
|
||||||
|
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
|
||||||
|
Vec<'a, Located<ExposesEntry<'a, ModuleName<'a>>>>,
|
||||||
|
),
|
||||||
|
> {
|
||||||
|
and!(
|
||||||
|
and!(skip_second!(space1(1), ascii_string("exposes")), space1(1)),
|
||||||
|
collection!(
|
||||||
|
ascii_char(b'['),
|
||||||
|
loc!(map!(module_name(), ExposesEntry::Exposed)),
|
||||||
|
ascii_char(b','),
|
||||||
|
ascii_char(b']'),
|
||||||
|
1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Packages<'a> {
|
||||||
|
entries: Vec<'a, Located<PackageEntry<'a>>>,
|
||||||
|
|
||||||
|
before_packages_keyword: &'a [CommentOrNewline<'a>],
|
||||||
|
after_packages_keyword: &'a [CommentOrNewline<'a>],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn packages<'a>() -> impl Parser<'a, Packages<'a>> {
|
||||||
|
map!(
|
||||||
|
and!(
|
||||||
|
and!(skip_second!(space1(1), ascii_string("packages")), space1(1)),
|
||||||
|
collection!(
|
||||||
|
ascii_char(b'{'),
|
||||||
|
loc!(package_entry()),
|
||||||
|
ascii_char(b','),
|
||||||
|
ascii_char(b'}'),
|
||||||
|
1
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|((before_packages_keyword, after_packages_keyword), entries)| {
|
||||||
|
Packages {
|
||||||
|
entries,
|
||||||
|
before_packages_keyword,
|
||||||
|
after_packages_keyword,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn imports<'a>() -> impl Parser<
|
fn imports<'a>() -> impl Parser<
|
||||||
'a,
|
'a,
|
||||||
|
@ -382,11 +543,6 @@ fn typed_ident<'a>() -> impl Parser<'a, TypedIdent<'a>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn exposes_entry<'a>() -> impl Parser<'a, ExposesEntry<'a>> {
|
|
||||||
map!(unqualified_ident(), ExposesEntry::Ident)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn imports_entry<'a>() -> impl Parser<'a, ImportsEntry<'a>> {
|
fn imports_entry<'a>() -> impl Parser<'a, ImportsEntry<'a>> {
|
||||||
map_with_arena!(
|
map_with_arena!(
|
||||||
|
@ -398,7 +554,7 @@ fn imports_entry<'a>() -> impl Parser<'a, ImportsEntry<'a>> {
|
||||||
ascii_char(b'.'),
|
ascii_char(b'.'),
|
||||||
collection!(
|
collection!(
|
||||||
ascii_char(b'{'),
|
ascii_char(b'{'),
|
||||||
loc!(exposes_entry()),
|
loc!(map!(unqualified_ident(), ExposesEntry::Exposed)),
|
||||||
ascii_char(b','),
|
ascii_char(b','),
|
||||||
ascii_char(b'}'),
|
ascii_char(b'}'),
|
||||||
1
|
1
|
||||||
|
@ -408,7 +564,7 @@ fn imports_entry<'a>() -> impl Parser<'a, ImportsEntry<'a>> {
|
||||||
|arena,
|
|arena,
|
||||||
(module_name, opt_values): (
|
(module_name, opt_values): (
|
||||||
ModuleName<'a>,
|
ModuleName<'a>,
|
||||||
Option<Vec<'a, Located<ExposesEntry<'a>>>>
|
Option<Vec<'a, Located<ExposesEntry<'a, &'a str>>>>
|
||||||
)| {
|
)| {
|
||||||
let exposed_values = opt_values.unwrap_or_else(|| Vec::new_in(arena));
|
let exposed_values = opt_values.unwrap_or_else(|| Vec::new_in(arena));
|
||||||
|
|
||||||
|
|
|
@ -1037,7 +1037,11 @@ macro_rules! one_or_more {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err((_, new_state)) => Err(unexpected_eof(0, new_state.attempting, new_state)),
|
Err((_, new_state)) => Err($crate::parser::unexpected_eof(
|
||||||
|
0,
|
||||||
|
new_state.attempting,
|
||||||
|
new_state,
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1083,9 +1087,9 @@ macro_rules! either {
|
||||||
let original_attempting = state.attempting;
|
let original_attempting = state.attempting;
|
||||||
|
|
||||||
match $p1.parse(arena, state) {
|
match $p1.parse(arena, state) {
|
||||||
Ok((output, state)) => Ok((Either::First(output), state)),
|
Ok((output, state)) => Ok(($crate::parser::Either::First(output), state)),
|
||||||
Err((_, state)) => match $p2.parse(arena, state) {
|
Err((_, state)) => match $p2.parse(arena, state) {
|
||||||
Ok((output, state)) => Ok((Either::Second(output), state)),
|
Ok((output, state)) => Ok(($crate::parser::Either::Second(output), state)),
|
||||||
Err((fail, state)) => Err((
|
Err((fail, state)) => Err((
|
||||||
Fail {
|
Fail {
|
||||||
attempting: original_attempting,
|
attempting: original_attempting,
|
||||||
|
|
|
@ -12,10 +12,10 @@ pub fn parse_expr_with<'a>(arena: &'a Bump, input: &'a str) -> Result<ast::Expr<
|
||||||
parse_loc_with(arena, input).map(|loc_expr| loc_expr.value)
|
parse_loc_with(arena, input).map(|loc_expr| loc_expr.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn parse_header_with<'a>(arena: &'a Bump, input: &'a str) -> Result<ast::Module<'a>, Fail> {
|
pub fn parse_header_with<'a>(arena: &'a Bump, input: &'a str) -> Result<ast::Module<'a>, Fail> {
|
||||||
let state = State::new(input.trim().as_bytes(), Attempting::Module);
|
let state = State::new(input.trim().as_bytes(), Attempting::Module);
|
||||||
let answer = header().parse(arena, state);
|
let answer = header().parse(arena, state);
|
||||||
|
|
||||||
answer
|
answer
|
||||||
.map(|(loc_expr, _)| loc_expr)
|
.map(|(loc_expr, _)| loc_expr)
|
||||||
.map_err(|(fail, _)| fail)
|
.map_err(|(fail, _)| fail)
|
||||||
|
|
|
@ -21,13 +21,16 @@ mod test_parse {
|
||||||
use roc_parse::ast::CommentOrNewline::*;
|
use roc_parse::ast::CommentOrNewline::*;
|
||||||
use roc_parse::ast::Expr::{self, *};
|
use roc_parse::ast::Expr::{self, *};
|
||||||
use roc_parse::ast::Pattern::{self, *};
|
use roc_parse::ast::Pattern::{self, *};
|
||||||
use roc_parse::ast::StrLiteral::*;
|
use roc_parse::ast::StrLiteral::{self, *};
|
||||||
use roc_parse::ast::StrSegment::*;
|
use roc_parse::ast::StrSegment::*;
|
||||||
use roc_parse::ast::{
|
use roc_parse::ast::{
|
||||||
self, Attempting, Def, EscapedChar, InterfaceHeader, Spaceable, TypeAnnotation, WhenBranch,
|
self, Attempting, Def, EscapedChar, Spaceable, TypeAnnotation, WhenBranch,
|
||||||
};
|
};
|
||||||
use roc_parse::header::ModuleName;
|
use roc_parse::header::{
|
||||||
use roc_parse::module::{interface_header, module_defs};
|
AppHeader, Effects, ExposesEntry, InterfaceHeader, ModuleName, PackageEntry, PackageName,
|
||||||
|
PackageOrPath, PlatformHeader, To,
|
||||||
|
};
|
||||||
|
use roc_parse::module::{app_header, interface_header, module_defs, platform_header};
|
||||||
use roc_parse::parser::{Fail, FailReason, Parser, State};
|
use roc_parse::parser::{Fail, FailReason, Parser, State};
|
||||||
use roc_parse::test_helpers::parse_expr_with;
|
use roc_parse::test_helpers::parse_expr_with;
|
||||||
use roc_region::all::{Located, Region};
|
use roc_region::all::{Located, Region};
|
||||||
|
@ -1733,6 +1736,45 @@ mod test_parse {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn multiline_type_signature() {
|
||||||
|
assert_parses_to(
|
||||||
|
"f :\n {}\n\n42",
|
||||||
|
Defs(
|
||||||
|
&[&Located::new(
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
6,
|
||||||
|
Def::Annotation(
|
||||||
|
Located::new(0, 0, 0, 1, Pattern::Identifier("f")),
|
||||||
|
Located::new(
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
4,
|
||||||
|
6,
|
||||||
|
TypeAnnotation::SpaceBefore(
|
||||||
|
&TypeAnnotation::Record {
|
||||||
|
fields: &[],
|
||||||
|
ext: None,
|
||||||
|
final_comments: &[],
|
||||||
|
},
|
||||||
|
&[Newline],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)],
|
||||||
|
&Located::new(
|
||||||
|
3,
|
||||||
|
3,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
Expr::SpaceBefore(&Expr::Num("42"), &[Newline, Newline]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// #[test]
|
// #[test]
|
||||||
// fn type_signature_function_def() {
|
// fn type_signature_function_def() {
|
||||||
// use TypeAnnotation;
|
// use TypeAnnotation;
|
||||||
|
@ -2200,7 +2242,237 @@ mod test_parse {
|
||||||
// MODULE
|
// MODULE
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_module() {
|
fn empty_app_header() {
|
||||||
|
let arena = Bump::new();
|
||||||
|
let packages = Vec::new_in(&arena);
|
||||||
|
let imports = Vec::new_in(&arena);
|
||||||
|
let provides = Vec::new_in(&arena);
|
||||||
|
let module_name = StrLiteral::PlainLine("test-app");
|
||||||
|
let expected = AppHeader {
|
||||||
|
name: Located::new(0, 0, 4, 14, module_name),
|
||||||
|
packages,
|
||||||
|
imports,
|
||||||
|
provides,
|
||||||
|
to: Located::new(0, 0, 53, 57, To::ExistingPackage("blah")),
|
||||||
|
after_app_keyword: &[],
|
||||||
|
before_packages: &[],
|
||||||
|
after_packages: &[],
|
||||||
|
before_imports: &[],
|
||||||
|
after_imports: &[],
|
||||||
|
before_provides: &[],
|
||||||
|
after_provides: &[],
|
||||||
|
before_to: &[],
|
||||||
|
after_to: &[],
|
||||||
|
};
|
||||||
|
|
||||||
|
let src = indoc!(
|
||||||
|
r#"
|
||||||
|
app "test-app" packages {} imports [] provides [] to blah
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
let actual = app_header()
|
||||||
|
.parse(&arena, State::new(src.as_bytes(), Attempting::Module))
|
||||||
|
.map(|tuple| tuple.0);
|
||||||
|
|
||||||
|
assert_eq!(Ok(expected), actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn minimal_app_header() {
|
||||||
|
use PackageOrPath::Path;
|
||||||
|
|
||||||
|
let arena = Bump::new();
|
||||||
|
let packages = Vec::new_in(&arena);
|
||||||
|
let imports = Vec::new_in(&arena);
|
||||||
|
let provides = Vec::new_in(&arena);
|
||||||
|
let module_name = StrLiteral::PlainLine("test-app");
|
||||||
|
let expected = AppHeader {
|
||||||
|
name: Located::new(0, 0, 4, 14, module_name),
|
||||||
|
packages,
|
||||||
|
imports,
|
||||||
|
provides,
|
||||||
|
to: Located::new(0, 0, 30, 38, To::NewPackage(Path(PlainLine("./blah")))),
|
||||||
|
after_app_keyword: &[],
|
||||||
|
before_packages: &[],
|
||||||
|
after_packages: &[],
|
||||||
|
before_imports: &[],
|
||||||
|
after_imports: &[],
|
||||||
|
before_provides: &[],
|
||||||
|
after_provides: &[],
|
||||||
|
before_to: &[],
|
||||||
|
after_to: &[],
|
||||||
|
};
|
||||||
|
|
||||||
|
let src = indoc!(
|
||||||
|
r#"
|
||||||
|
app "test-app" provides [] to "./blah"
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
let actual = app_header()
|
||||||
|
.parse(&arena, State::new(src.as_bytes(), Attempting::Module))
|
||||||
|
.map(|tuple| tuple.0);
|
||||||
|
|
||||||
|
assert_eq!(Ok(expected), actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn full_app_header() {
|
||||||
|
use ExposesEntry::Exposed;
|
||||||
|
use PackageOrPath::Path;
|
||||||
|
|
||||||
|
let pkg_entry = PackageEntry::Entry {
|
||||||
|
shorthand: "base",
|
||||||
|
spaces_after_shorthand: &[],
|
||||||
|
package_or_path: Located::new(0, 0, 33, 45, Path(PlainLine("./platform"))),
|
||||||
|
};
|
||||||
|
let loc_pkg_entry = Located::new(0, 0, 27, 45, pkg_entry);
|
||||||
|
let arena = Bump::new();
|
||||||
|
let packages = bumpalo::vec![in &arena; loc_pkg_entry];
|
||||||
|
let imports = Vec::new_in(&arena);
|
||||||
|
let provide_entry = Located::new(0, 0, 59, 68, Exposed("quicksort"));
|
||||||
|
let provides = bumpalo::vec![in &arena; provide_entry];
|
||||||
|
let module_name = StrLiteral::PlainLine("quicksort");
|
||||||
|
let expected = AppHeader {
|
||||||
|
name: Located::new(0, 0, 4, 15, module_name),
|
||||||
|
packages,
|
||||||
|
imports,
|
||||||
|
provides,
|
||||||
|
to: Located::new(0, 0, 74, 78, To::ExistingPackage("base")),
|
||||||
|
after_app_keyword: &[],
|
||||||
|
before_packages: &[],
|
||||||
|
after_packages: &[],
|
||||||
|
before_imports: &[],
|
||||||
|
after_imports: &[],
|
||||||
|
before_provides: &[],
|
||||||
|
after_provides: &[],
|
||||||
|
before_to: &[],
|
||||||
|
after_to: &[],
|
||||||
|
};
|
||||||
|
|
||||||
|
let src = indoc!(
|
||||||
|
r#"
|
||||||
|
app "quicksort" packages { base: "./platform" } provides [ quicksort ] to base
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
let actual = app_header()
|
||||||
|
.parse(&arena, State::new(src.as_bytes(), Attempting::Module))
|
||||||
|
.map(|tuple| tuple.0);
|
||||||
|
|
||||||
|
assert_eq!(Ok(expected), actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn empty_platform_header() {
|
||||||
|
let pkg_name = PackageName {
|
||||||
|
account: "rtfeldman",
|
||||||
|
pkg: "blah",
|
||||||
|
};
|
||||||
|
let arena = Bump::new();
|
||||||
|
let effects = Effects {
|
||||||
|
type_name: "Blah",
|
||||||
|
entries: Vec::new_in(&arena),
|
||||||
|
spaces_before_effects_keyword: &[],
|
||||||
|
spaces_after_effects_keyword: &[],
|
||||||
|
spaces_after_type_name: &[],
|
||||||
|
};
|
||||||
|
let expected = PlatformHeader {
|
||||||
|
name: Located::new(0, 0, 9, 23, pkg_name),
|
||||||
|
requires: Vec::new_in(&arena),
|
||||||
|
exposes: Vec::new_in(&arena),
|
||||||
|
packages: Vec::new_in(&arena),
|
||||||
|
imports: Vec::new_in(&arena),
|
||||||
|
provides: Vec::new_in(&arena),
|
||||||
|
effects,
|
||||||
|
after_platform_keyword: &[],
|
||||||
|
before_requires: &[],
|
||||||
|
after_requires: &[],
|
||||||
|
before_exposes: &[],
|
||||||
|
after_exposes: &[],
|
||||||
|
before_packages: &[],
|
||||||
|
after_packages: &[],
|
||||||
|
before_imports: &[],
|
||||||
|
after_imports: &[],
|
||||||
|
before_provides: &[],
|
||||||
|
after_provides: &[],
|
||||||
|
};
|
||||||
|
|
||||||
|
let src = "platform rtfeldman/blah requires {} exposes [] packages {} imports [] provides [] effects Blah {}";
|
||||||
|
let actual = platform_header()
|
||||||
|
.parse(&arena, State::new(src.as_bytes(), Attempting::Module))
|
||||||
|
.map(|tuple| tuple.0);
|
||||||
|
|
||||||
|
assert_eq!(Ok(expected), actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn nonempty_platform_header() {
|
||||||
|
use ExposesEntry::Exposed;
|
||||||
|
use PackageOrPath::Path;
|
||||||
|
|
||||||
|
let newlines = &[Newline];
|
||||||
|
let pkg_name = PackageName {
|
||||||
|
account: "foo",
|
||||||
|
pkg: "barbaz",
|
||||||
|
};
|
||||||
|
let pkg_entry = PackageEntry::Entry {
|
||||||
|
shorthand: "foo",
|
||||||
|
spaces_after_shorthand: &[],
|
||||||
|
package_or_path: Located::new(3, 3, 20, 27, Path(PlainLine("./foo"))),
|
||||||
|
};
|
||||||
|
let loc_pkg_entry = Located::new(3, 3, 15, 27, pkg_entry);
|
||||||
|
let arena = Bump::new();
|
||||||
|
let packages = bumpalo::vec![in &arena; loc_pkg_entry];
|
||||||
|
let imports = Vec::new_in(&arena);
|
||||||
|
let provide_entry = Located::new(5, 5, 15, 26, Exposed("mainForHost"));
|
||||||
|
let provides = bumpalo::vec![in &arena; provide_entry];
|
||||||
|
let effects = Effects {
|
||||||
|
type_name: "Effect",
|
||||||
|
entries: Vec::new_in(&arena),
|
||||||
|
spaces_before_effects_keyword: newlines,
|
||||||
|
spaces_after_effects_keyword: &[],
|
||||||
|
spaces_after_type_name: &[],
|
||||||
|
};
|
||||||
|
let expected = PlatformHeader {
|
||||||
|
name: Located::new(0, 0, 9, 19, pkg_name),
|
||||||
|
requires: Vec::new_in(&arena),
|
||||||
|
exposes: Vec::new_in(&arena),
|
||||||
|
packages,
|
||||||
|
imports,
|
||||||
|
provides,
|
||||||
|
effects,
|
||||||
|
after_platform_keyword: &[],
|
||||||
|
before_requires: newlines,
|
||||||
|
after_requires: &[],
|
||||||
|
before_exposes: newlines,
|
||||||
|
after_exposes: &[],
|
||||||
|
before_packages: newlines,
|
||||||
|
after_packages: &[],
|
||||||
|
before_imports: newlines,
|
||||||
|
after_imports: &[],
|
||||||
|
before_provides: newlines,
|
||||||
|
after_provides: &[],
|
||||||
|
};
|
||||||
|
|
||||||
|
let src = indoc!(
|
||||||
|
r#"
|
||||||
|
platform foo/barbaz
|
||||||
|
requires {}
|
||||||
|
exposes []
|
||||||
|
packages { foo: "./foo" }
|
||||||
|
imports []
|
||||||
|
provides [ mainForHost ]
|
||||||
|
effects Effect {}
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
let actual = platform_header()
|
||||||
|
.parse(&arena, State::new(src.as_bytes(), Attempting::Module))
|
||||||
|
.map(|tuple| tuple.0);
|
||||||
|
|
||||||
|
assert_eq!(Ok(expected), actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn empty_interface_header() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let exposes = Vec::new_in(&arena);
|
let exposes = Vec::new_in(&arena);
|
||||||
let imports = Vec::new_in(&arena);
|
let imports = Vec::new_in(&arena);
|
||||||
|
|
|
@ -128,7 +128,8 @@ mod solve_expr {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn promote_expr_to_module(src: &str) -> String {
|
fn promote_expr_to_module(src: &str) -> String {
|
||||||
let mut buffer = String::from("app Test provides [ main ] imports []\n\nmain =\n");
|
let mut buffer =
|
||||||
|
String::from("app \"test\" provides [ main ] to \"./platform\"\n\nmain =\n");
|
||||||
|
|
||||||
for line in src.lines() {
|
for line in src.lines() {
|
||||||
// indent the body!
|
// indent the body!
|
||||||
|
@ -2054,7 +2055,7 @@ mod solve_expr {
|
||||||
infer_eq(
|
infer_eq(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
Peano : [ S Peano, Z ]
|
Peano : [ S Peano, Z ]
|
||||||
|
|
||||||
|
@ -2138,7 +2139,7 @@ mod solve_expr {
|
||||||
infer_eq_without_problem(
|
infer_eq_without_problem(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
ConsList a : [ Cons a (ConsList a), Nil ]
|
ConsList a : [ Cons a (ConsList a), Nil ]
|
||||||
|
|
||||||
|
@ -2194,7 +2195,7 @@ mod solve_expr {
|
||||||
infer_eq(
|
infer_eq(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
map =
|
map =
|
||||||
\peano ->
|
\peano ->
|
||||||
|
@ -2632,7 +2633,7 @@ mod solve_expr {
|
||||||
infer_eq_without_problem(
|
infer_eq_without_problem(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
boom = \_ -> boom {}
|
boom = \_ -> boom {}
|
||||||
|
|
||||||
|
@ -2978,7 +2979,7 @@ mod solve_expr {
|
||||||
infer_eq_without_problem(
|
infer_eq_without_problem(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
|
|
||||||
main : List x
|
main : List x
|
||||||
|
@ -2998,7 +2999,7 @@ mod solve_expr {
|
||||||
infer_eq_without_problem(
|
infer_eq_without_problem(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
|
|
||||||
main =
|
main =
|
||||||
|
@ -3019,7 +3020,7 @@ mod solve_expr {
|
||||||
infer_eq_without_problem(
|
infer_eq_without_problem(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
Bar : [ Bar ]
|
Bar : [ Bar ]
|
||||||
Foo : [ Foo Bar Int, Empty ]
|
Foo : [ Foo Bar Int, Empty ]
|
||||||
|
@ -3045,7 +3046,7 @@ mod solve_expr {
|
||||||
infer_eq_without_problem(
|
infer_eq_without_problem(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
Foo : [ @Foo [ @Bar ] Int, @Empty ]
|
Foo : [ @Foo [ @Bar ] Int, @Empty ]
|
||||||
|
|
||||||
|
@ -3070,7 +3071,7 @@ mod solve_expr {
|
||||||
infer_eq_without_problem(
|
infer_eq_without_problem(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
State a : { count : Int, x : a }
|
State a : { count : Int, x : a }
|
||||||
|
|
||||||
|
@ -3095,7 +3096,7 @@ mod solve_expr {
|
||||||
infer_eq_without_problem(
|
infer_eq_without_problem(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
# The color of a node. Leaves are considered Black.
|
# The color of a node. Leaves are considered Black.
|
||||||
NodeColor : [ Red, Black ]
|
NodeColor : [ Red, Black ]
|
||||||
|
@ -3128,7 +3129,7 @@ mod solve_expr {
|
||||||
infer_eq_without_problem(
|
infer_eq_without_problem(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
Dict k : [ Node k (Dict k), Empty ]
|
Dict k : [ Node k (Dict k), Empty ]
|
||||||
|
|
||||||
|
@ -3153,7 +3154,7 @@ mod solve_expr {
|
||||||
infer_eq_without_problem(
|
infer_eq_without_problem(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
NodeColor : [ Red, Black ]
|
NodeColor : [ Red, Black ]
|
||||||
|
|
||||||
|
@ -3383,7 +3384,7 @@ mod solve_expr {
|
||||||
infer_eq_without_problem(
|
infer_eq_without_problem(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
Dict k : [ Node k (Dict k) (Dict k), Empty ]
|
Dict k : [ Node k (Dict k) (Dict k), Empty ]
|
||||||
|
|
||||||
|
@ -3423,7 +3424,7 @@ mod solve_expr {
|
||||||
infer_eq_without_problem(
|
infer_eq_without_problem(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
NodeColor : [ Red, Black ]
|
NodeColor : [ Red, Black ]
|
||||||
|
|
||||||
|
@ -3499,7 +3500,7 @@ mod solve_expr {
|
||||||
infer_eq_without_problem(
|
infer_eq_without_problem(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ partitionHelp ] imports []
|
app "test" provides [ partitionHelp ] to "./platform"
|
||||||
|
|
||||||
swap : Int, Int, List a -> List a
|
swap : Int, Int, List a -> List a
|
||||||
swap = \i, j, list ->
|
swap = \i, j, list ->
|
||||||
|
@ -3537,7 +3538,7 @@ mod solve_expr {
|
||||||
infer_eq_without_problem(
|
infer_eq_without_problem(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
Dict k : [ Node k (Dict k) (Dict k), Empty ]
|
Dict k : [ Node k (Dict k) (Dict k), Empty ]
|
||||||
|
|
||||||
|
@ -3559,7 +3560,7 @@ mod solve_expr {
|
||||||
infer_eq_without_problem(
|
infer_eq_without_problem(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
Dict k : [ Node k (Dict k) (Dict k), Empty ]
|
Dict k : [ Node k (Dict k) (Dict k), Empty ]
|
||||||
|
|
||||||
|
@ -3583,7 +3584,7 @@ mod solve_expr {
|
||||||
infer_eq_without_problem(
|
infer_eq_without_problem(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app Test provides [ main ] imports []
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
NodeColor : [ Red, Black ]
|
NodeColor : [ Red, Black ]
|
||||||
|
|
||||||
|
|
6
examples/.gitignore
vendored
6
examples/.gitignore
vendored
|
@ -1,5 +1,3 @@
|
||||||
app
|
app
|
||||||
host.o
|
*.o
|
||||||
c_host.o
|
*.dSYM
|
||||||
roc_app.o
|
|
||||||
app.dSYM
|
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
app Closure provides [ makeClosure ] imports []
|
app "closure" provides [ makeClosure ] to "./platform/"
|
||||||
|
|
||||||
makeClosure : ({} -> Int) as MyClosure
|
makeClosure : ({} -> Int) as MyClosure
|
||||||
makeClosure =
|
makeClosure =
|
||||||
x = 42
|
x = 42
|
||||||
y = 42
|
y = 42
|
||||||
|
|
||||||
\{} -> x + y
|
\{} -> x + y
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
platform roc/quicksort
|
platform examples/closure
|
||||||
provides []
|
requires { main : Effect {} }
|
||||||
requires {}
|
exposes []
|
||||||
|
packages {}
|
||||||
imports []
|
imports []
|
||||||
effects Effect {}
|
provides [ mainForHost ]
|
||||||
|
effects Effect
|
||||||
|
{
|
||||||
|
putChar : Int -> Effect {},
|
||||||
|
putLine : Str -> Effect {},
|
||||||
|
getLine : Effect Str
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
app Main provides [ main ] imports [ Effect, RBTree ]
|
app "effect-example" provides [ main ] imports [ Effect, RBTree ]
|
||||||
|
|
||||||
toAndFro : Int
|
toAndFro : Int
|
||||||
toAndFro =
|
toAndFro =
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
platform folkertdev/foo
|
platform folkertdev/foo
|
||||||
provides [ mainForHost ]
|
|
||||||
requires { main : Effect {} }
|
requires { main : Effect {} }
|
||||||
|
exposes []
|
||||||
|
packages {}
|
||||||
imports []
|
imports []
|
||||||
|
provides [ mainForHost ]
|
||||||
effects Effect
|
effects Effect
|
||||||
{
|
{
|
||||||
putChar : Int -> Effect {},
|
putChar : Int -> Effect {},
|
||||||
|
|
1
examples/hello-world/.gitignore
vendored
Normal file
1
examples/hello-world/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
hello-world
|
|
@ -1,4 +1,4 @@
|
||||||
app Hello provides [ main ] imports []
|
app "hello-world" provides [ main ] to "./platform"
|
||||||
|
|
||||||
greeting =
|
greeting =
|
||||||
hi = "Hello"
|
hi = "Hello"
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
platform roc/quicksort
|
platform examples/hello-world
|
||||||
provides []
|
requires { main : Str }
|
||||||
requires {}
|
exposes []
|
||||||
|
packages {}
|
||||||
imports []
|
imports []
|
||||||
|
provides [ main ]
|
||||||
effects Effect {}
|
effects Effect {}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use roc_std::RocStr;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#[link_name = "Hello_main_1_exposed"]
|
#[link_name = "roc__main_1_exposed"]
|
||||||
fn say_hello(output: &mut RocCallResult<RocStr>) -> ();
|
fn say_hello(output: &mut RocCallResult<RocStr>) -> ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1
examples/multi-module/.gitignore
vendored
Normal file
1
examples/multi-module/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
quicksort
|
|
@ -1,8 +1,8 @@
|
||||||
app Quicksort provides [ quicksort ] imports [ Utils.{swap} ]
|
app "quicksort" imports [ Utils.{ swap } ] provides [ quicksort ] to "./platform"
|
||||||
|
|
||||||
|
|
||||||
quicksort : List Int -> List Int
|
quicksort : List Int -> List Int
|
||||||
quicksort = \originalList ->
|
quicksort = \originalList ->
|
||||||
quicksortHelp : List (Num a), Int, Int -> List (Num a)
|
quicksortHelp : List (Num a), Int, Int -> List (Num a)
|
||||||
quicksortHelp = \list, low, high ->
|
quicksortHelp = \list, low, high ->
|
||||||
if low < high then
|
if low < high then
|
||||||
|
@ -43,5 +43,5 @@ quicksort = \originalList ->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
n = List.len originalList
|
n = List.len originalList
|
||||||
quicksortHelp originalList 0 (n - 1)
|
quicksortHelp originalList 0 (n - 1)
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
platform roc/quicksort
|
platform examples/multi-module
|
||||||
provides []
|
requires { quicksort : List (Num a) -> List (Num a) }
|
||||||
requires {}
|
exposes []
|
||||||
|
packages {}
|
||||||
imports []
|
imports []
|
||||||
|
provides [ main ]
|
||||||
effects Effect {}
|
effects Effect {}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use roc_std::RocList;
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#[link_name = "Quicksort_quicksort_1_exposed"]
|
#[link_name = "roc__quicksort_1_exposed"]
|
||||||
fn quicksort(list: RocList<i64>, output: &mut RocCallResult<RocList<i64>>) -> ();
|
fn quicksort(list: RocList<i64>, output: &mut RocCallResult<RocList<i64>>) -> ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1
examples/quicksort/.gitignore
vendored
Normal file
1
examples/quicksort/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
quicksort
|
|
@ -1,4 +1,4 @@
|
||||||
app Quicksort provides [ quicksort ] imports []
|
app "quicksort" provides [ quicksort ] to "./platform"
|
||||||
|
|
||||||
quicksort = \originalList ->
|
quicksort = \originalList ->
|
||||||
|
|
||||||
|
@ -52,11 +52,5 @@ quicksort = \originalList ->
|
||||||
_ ->
|
_ ->
|
||||||
[]
|
[]
|
||||||
|
|
||||||
n = List.len originalList
|
n = List.len originalList
|
||||||
quicksortHelp originalList 0 (n - 1)
|
quicksortHelp originalList 0 (n - 1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
platform roc/quicksort
|
platform examples/quicksort
|
||||||
provides []
|
requires { quicksort : List (Num a) -> List (Num a) }
|
||||||
requires {}
|
exposes []
|
||||||
|
packages {}
|
||||||
imports []
|
imports []
|
||||||
|
provides [ main ]
|
||||||
effects Effect {}
|
effects Effect {}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use roc_std::RocList;
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#[link_name = "Quicksort_quicksort_1_exposed"]
|
#[link_name = "roc__quicksort_1_exposed"]
|
||||||
fn quicksort(list: RocList<i64>, output: &mut RocCallResult<RocList<i64>>) -> ();
|
fn quicksort(list: RocList<i64>, output: &mut RocCallResult<RocList<i64>>) -> ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
app Quicksort provides [ quicksort ] imports []
|
app "quicksort" packages { base: "./platform" } provides [ quicksort ] to base
|
||||||
|
|
||||||
quicksort : List Int -> List Int
|
quicksort : List Int -> List Int
|
||||||
quicksort = \originalList -> helper originalList
|
quicksort = \originalList -> helper originalList
|
||||||
|
|
||||||
helper : List Int -> List Int
|
helper : List Int -> List Int
|
||||||
helper = \originalList ->
|
helper = \originalList ->
|
||||||
|
|
||||||
quicksortHelp : List (Num a), Int, Int -> List (Num a)
|
quicksortHelp : List (Num a), Int, Int -> List (Num a)
|
||||||
quicksortHelp = \list, low, high ->
|
quicksortHelp = \list, low, high ->
|
||||||
if low < high then
|
if low < high then
|
||||||
|
@ -66,4 +66,3 @@ helper = \originalList ->
|
||||||
# Absolutely make the `originalList` Shared by using it again here
|
# Absolutely make the `originalList` Shared by using it again here
|
||||||
# but this branch is not evaluated, so should not affect performance
|
# but this branch is not evaluated, so should not affect performance
|
||||||
List.set originalList 0 (List.len originalList)
|
List.set originalList 0 (List.len originalList)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
platform roc/quicksort
|
platform examples/shared-quicksort
|
||||||
provides []
|
requires { main : Effect {} }
|
||||||
requires {}
|
exposes []
|
||||||
|
packages {}
|
||||||
imports []
|
imports []
|
||||||
effects Effect {}
|
provides [ mainForHost ]
|
||||||
|
effects Effect
|
||||||
|
{
|
||||||
|
putChar : Int -> Effect {},
|
||||||
|
putLine : Str -> Effect {},
|
||||||
|
getLine : Effect Str
|
||||||
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use roc_std::RocList;
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#[link_name = "Main_quicksort_1_exposed"]
|
#[link_name = "_quicksort_1_exposed"]
|
||||||
fn quicksort(list: RocList<i64>, output: &mut RocCallResult<RocList<i64>>) -> ();
|
fn quicksort(list: RocList<i64>, output: &mut RocCallResult<RocList<i64>>) -> ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue