mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
WIP Merge remote-tracking branch 'remote/main' into rebuild-platform
This commit is contained in:
commit
e3afeaa7ff
138 changed files with 3544 additions and 4651 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -119,3 +119,6 @@ crates/glue/tests/fixtures/*/build.rs
|
||||||
crates/glue/tests/fixtures/*/host.c
|
crates/glue/tests/fixtures/*/host.c
|
||||||
crates/glue/tests/fixtures/*/src/main.rs
|
crates/glue/tests/fixtures/*/src/main.rs
|
||||||
crates/glue/tests/fixtures/*/test_glue/
|
crates/glue/tests/fixtures/*/test_glue/
|
||||||
|
|
||||||
|
# ignore the zig glue files copied into test platforms
|
||||||
|
**/*platform/glue/*
|
||||||
|
|
65
Cargo.lock
generated
65
Cargo.lock
generated
|
@ -384,11 +384,11 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.83"
|
version = "1.1.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"shlex",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1400,9 +1400,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.149"
|
version = "0.2.158"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
|
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libloading"
|
name = "libloading"
|
||||||
|
@ -1541,6 +1541,15 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memmap2"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memoffset"
|
name = "memoffset"
|
||||||
version = "0.6.5"
|
version = "0.6.5"
|
||||||
|
@ -1657,6 +1666,12 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-conv"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.17"
|
version = "0.2.17"
|
||||||
|
@ -1865,9 +1880,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.69"
|
version = "1.0.86"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
|
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
@ -1933,9 +1948,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.33"
|
version = "1.0.37"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
@ -2366,6 +2381,7 @@ name = "roc_cli"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
|
"chrono",
|
||||||
"clap 4.4.6",
|
"clap 4.4.6",
|
||||||
"cli_utils",
|
"cli_utils",
|
||||||
"const_format",
|
"const_format",
|
||||||
|
@ -2374,6 +2390,7 @@ dependencies = [
|
||||||
"errno",
|
"errno",
|
||||||
"indoc",
|
"indoc",
|
||||||
"inkwell",
|
"inkwell",
|
||||||
|
"insta",
|
||||||
"libc",
|
"libc",
|
||||||
"libloading",
|
"libloading",
|
||||||
"mimalloc",
|
"mimalloc",
|
||||||
|
@ -2704,7 +2721,7 @@ dependencies = [
|
||||||
"indoc",
|
"indoc",
|
||||||
"libc",
|
"libc",
|
||||||
"mach_object",
|
"mach_object",
|
||||||
"memmap2",
|
"memmap2 0.5.10",
|
||||||
"object",
|
"object",
|
||||||
"roc_collections",
|
"roc_collections",
|
||||||
"roc_error_macros",
|
"roc_error_macros",
|
||||||
|
@ -3132,6 +3149,14 @@ dependencies = [
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "roc_std_heap"
|
||||||
|
version = "0.0.1"
|
||||||
|
dependencies = [
|
||||||
|
"memmap2 0.9.4",
|
||||||
|
"roc_std",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "roc_target"
|
name = "roc_target"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
|
@ -3296,9 +3321,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.14"
|
version = "1.0.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
|
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rusty-fork"
|
name = "rusty-fork"
|
||||||
|
@ -3526,6 +3551,12 @@ dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shlex"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook"
|
name = "signal-hook"
|
||||||
version = "0.3.17"
|
version = "0.3.17"
|
||||||
|
@ -3939,12 +3970,13 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.3.30"
|
version = "0.3.36"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5"
|
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"deranged",
|
"deranged",
|
||||||
"itoa",
|
"itoa",
|
||||||
|
"num-conv",
|
||||||
"powerfmt",
|
"powerfmt",
|
||||||
"serde",
|
"serde",
|
||||||
"time-core",
|
"time-core",
|
||||||
|
@ -3959,10 +3991,11 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time-macros"
|
name = "time-macros"
|
||||||
version = "0.2.15"
|
version = "0.2.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20"
|
checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"num-conv",
|
||||||
"time-core",
|
"time-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ members = [
|
||||||
"crates/wasm_module",
|
"crates/wasm_module",
|
||||||
"crates/wasm_interp",
|
"crates/wasm_interp",
|
||||||
"crates/language_server",
|
"crates/language_server",
|
||||||
|
"crates/roc_std_heap",
|
||||||
]
|
]
|
||||||
|
|
||||||
exclude = [
|
exclude = [
|
||||||
|
|
|
@ -19,12 +19,8 @@ You can 💜 **sponsor** 💜 Roc on:
|
||||||
- [GitHub](https://github.com/sponsors/roc-lang)
|
- [GitHub](https://github.com/sponsors/roc-lang)
|
||||||
- [Liberapay](https://liberapay.com/roc_lang)
|
- [Liberapay](https://liberapay.com/roc_lang)
|
||||||
|
|
||||||
We are very grateful for our corporate sponsors [Vendr](https://www.vendr.com/), [RWX](https://www.rwx.com), [Tweede golf](https://tweedegolf.nl/en), [ohne-makler](https://www.ohne-makler.net), and [Decem](https://www.decem.com.au):
|
We are very grateful for our corporate sponsors [Tweede golf](https://tweedegolf.nl/en), [ohne-makler](https://www.ohne-makler.net), and [Decem](https://www.decem.com.au):
|
||||||
|
|
||||||
[<img src="https://user-images.githubusercontent.com/1094080/223597445-81755626-a080-4299-a38c-3c92e7548489.png" height="60" alt="Vendr logo"/>](https://www.vendr.com)
|
|
||||||
|
|
||||||
[<img src="https://github.com/roc-lang/roc/assets/1094080/82c0868e-d23f-42a0-ac2d-c6e6b2e16575" height="60" alt="RWX logo"/>](https://www.rwx.com)
|
|
||||||
|
|
||||||
[<img src="https://user-images.githubusercontent.com/1094080/183123052-856815b1-8cc9-410a-83b0-589f03613188.svg" height="60" alt="tweede golf logo"/>](https://tweedegolf.nl/en)
|
[<img src="https://user-images.githubusercontent.com/1094080/183123052-856815b1-8cc9-410a-83b0-589f03613188.svg" height="60" alt="tweede golf logo"/>](https://tweedegolf.nl/en)
|
||||||
|
|
||||||
[<img src="https://www.ohne-makler.net/static/img/brand/logo.svg" height="60" alt="ohne-makler logo"/>](https://www.ohne-makler.net)
|
[<img src="https://www.ohne-makler.net/static/img/brand/logo.svg" height="60" alt="ohne-makler logo"/>](https://www.ohne-makler.net)
|
||||||
|
@ -35,6 +31,7 @@ If you would like your company to become a corporate sponsor of Roc's developmen
|
||||||
|
|
||||||
We'd also like to express our gratitude to our generous [individual sponsors](https://github.com/sponsors/roc-lang/)! A special thanks to those sponsoring $25/month or more:
|
We'd also like to express our gratitude to our generous [individual sponsors](https://github.com/sponsors/roc-lang/)! A special thanks to those sponsoring $25/month or more:
|
||||||
|
|
||||||
|
- [Peter Marreck](https://github.com/pmarreck)
|
||||||
- [Barry Moore](https://github.com/chiroptical)
|
- [Barry Moore](https://github.com/chiroptical)
|
||||||
- Eric Andresen
|
- Eric Andresen
|
||||||
- [Jackson Lucky](https://github.com/jluckyiv)
|
- [Jackson Lucky](https://github.com/jluckyiv)
|
||||||
|
|
|
@ -86,7 +86,7 @@ Surgical linker that links platforms to Roc applications. We created our own lin
|
||||||
|
|
||||||
## `repl_cli/` - `roc_repl_cli`
|
## `repl_cli/` - `roc_repl_cli`
|
||||||
|
|
||||||
Command Line Interface(CLI) functionality for the Read-Evaluate-Print-Loop (REPL).
|
Command Line Interface (CLI) functionality for the Read-Evaluate-Print-Loop (REPL).
|
||||||
|
|
||||||
## `repl_eval/` - `roc_repl_eval`
|
## `repl_eval/` - `roc_repl_eval`
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
name = "roc_cli"
|
name = "roc_cli"
|
||||||
description = "The Roc binary that brings together all functionality in the Roc toolset."
|
description = "The Roc binary that brings together all functionality in the Roc toolset."
|
||||||
default-run = "roc"
|
default-run = "roc"
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
|
@ -30,7 +31,13 @@ target-wasm32 = ["roc_build/target-wasm32"]
|
||||||
target-x86 = ["roc_build/target-x86", "roc_repl_cli/target-x86"]
|
target-x86 = ["roc_build/target-x86", "roc_repl_cli/target-x86"]
|
||||||
target-x86_64 = ["roc_build/target-x86_64", "roc_repl_cli/target-x86_64"]
|
target-x86_64 = ["roc_build/target-x86_64", "roc_repl_cli/target-x86_64"]
|
||||||
|
|
||||||
target-all = ["target-aarch64", "target-arm", "target-x86", "target-x86_64", "target-wasm32"]
|
target-all = [
|
||||||
|
"target-aarch64",
|
||||||
|
"target-arm",
|
||||||
|
"target-x86",
|
||||||
|
"target-x86_64",
|
||||||
|
"target-wasm32",
|
||||||
|
]
|
||||||
|
|
||||||
sanitizers = ["roc_build/sanitizers"]
|
sanitizers = ["roc_build/sanitizers"]
|
||||||
|
|
||||||
|
@ -90,6 +97,10 @@ criterion.workspace = true
|
||||||
indoc.workspace = true
|
indoc.workspace = true
|
||||||
parking_lot.workspace = true
|
parking_lot.workspace = true
|
||||||
pretty_assertions.workspace = true
|
pretty_assertions.workspace = true
|
||||||
|
insta.workspace = true
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
chrono.workspace = true
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "time_bench"
|
name = "time_bench"
|
||||||
|
|
71
crates/cli/build.rs
Normal file
71
crates/cli/build.rs
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
use chrono::prelude::*;
|
||||||
|
use std::fs;
|
||||||
|
use std::process::Command;
|
||||||
|
use std::str;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Rebuild if this build.rs file changes
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
|
||||||
|
// The version file is located at the root of the repository
|
||||||
|
let version_file_path = "../../version.txt";
|
||||||
|
|
||||||
|
// Rebuild if version file changes
|
||||||
|
println!("cargo:rerun-if-changed={}", version_file_path);
|
||||||
|
|
||||||
|
// Read the version file
|
||||||
|
let version_file_contents = fs::read_to_string(version_file_path).unwrap();
|
||||||
|
|
||||||
|
// If the version is "built-from-source", replace it with the git commit information
|
||||||
|
let version = match version_file_contents.trim() {
|
||||||
|
"built-from-source" => {
|
||||||
|
let git_head_file_path = "../../.git/HEAD";
|
||||||
|
// Rebuild if a new Git commit is made
|
||||||
|
println!("cargo:rerun-if-changed={}", git_head_file_path);
|
||||||
|
|
||||||
|
// Check if the .git/HEAD file exists
|
||||||
|
let git_head_exists = fs::metadata(git_head_file_path).is_ok();
|
||||||
|
if git_head_exists {
|
||||||
|
// Get the hash of the current commit
|
||||||
|
let git_describe_output = Command::new("git")
|
||||||
|
.arg("describe")
|
||||||
|
.arg("--always")
|
||||||
|
.arg("--dirty= with additional changes") // Add a suffix if the working directory is dirty
|
||||||
|
.output()
|
||||||
|
.expect("Failed to execute git describe command");
|
||||||
|
println!("git_describe_output: {:?}", git_describe_output);
|
||||||
|
let git_commit_hash = str::from_utf8(&git_describe_output.stdout)
|
||||||
|
.expect("Failed to parse git describe output")
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
// Get the datetime of the last commit
|
||||||
|
let git_show_output = Command::new("git")
|
||||||
|
.arg("show")
|
||||||
|
.arg("--no-patch")
|
||||||
|
.arg("--format=%ct") // Outputting a UNIX timestamp is the only way to always use UTC
|
||||||
|
.output()
|
||||||
|
.expect("Failed to execute git show command");
|
||||||
|
println!("git_show_output: {:?}", git_show_output);
|
||||||
|
let git_commit_timestamp = {
|
||||||
|
let timestamp = str::from_utf8(&git_show_output.stdout)
|
||||||
|
.expect("Failed to parse git show output as a string")
|
||||||
|
.trim()
|
||||||
|
.parse::<i64>()
|
||||||
|
.expect("Failed to parse timestamp as an integer");
|
||||||
|
DateTime::from_timestamp(timestamp, 0)
|
||||||
|
.expect("Failed to parse timestamp")
|
||||||
|
.format("%Y-%m-%d %H:%M:%S")
|
||||||
|
};
|
||||||
|
format!(
|
||||||
|
"built from commit {git_commit_hash}, committed at {git_commit_timestamp} UTC"
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// If the .git/HEAD file does not exist, e.g. in a Nix build, use a generic message
|
||||||
|
"built from source".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => version_file_contents.trim().to_string(),
|
||||||
|
};
|
||||||
|
// Emit the version to a build-time environment variable
|
||||||
|
println!("cargo:rustc-env=ROC_VERSION={}", version);
|
||||||
|
}
|
|
@ -266,20 +266,23 @@ mod tests {
|
||||||
const FORMATTED_ROC: &str = r#"app [main] { pf: platform "platform/main.roc" }
|
const FORMATTED_ROC: &str = r#"app [main] { pf: platform "platform/main.roc" }
|
||||||
|
|
||||||
import pf.Stdout
|
import pf.Stdout
|
||||||
import pf.Task
|
import pf.Stdin
|
||||||
|
|
||||||
main =
|
main =
|
||||||
Stdout.line! "I'm a Roc application!""#;
|
Stdout.line! "What's your name?"
|
||||||
|
name = Stdin.line!
|
||||||
|
Stdout.line! "Hi $(name)!""#;
|
||||||
|
|
||||||
const UNFORMATTED_ROC: &str = r#"app [main] { pf: platform "platform/main.roc" }
|
const UNFORMATTED_ROC: &str = r#"app [main] { pf: platform "platform/main.roc" }
|
||||||
|
|
||||||
|
|
||||||
import pf.Stdout
|
import pf.Stdout
|
||||||
|
import pf.Stdin
|
||||||
import pf.Task
|
|
||||||
|
|
||||||
main =
|
main =
|
||||||
Stdout.line! "I'm a Roc application!"
|
Stdout.line! "What's your name?"
|
||||||
|
name = Stdin.line!
|
||||||
|
Stdout.line! "Hi $(name)!"
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
fn setup_test_file(dir: &Path, file_name: &str, contents: &str) -> PathBuf {
|
fn setup_test_file(dir: &Path, file_name: &str, contents: &str) -> PathBuf {
|
||||||
|
|
|
@ -68,6 +68,8 @@ pub const FLAG_NO_LINK: &str = "no-link";
|
||||||
pub const FLAG_TARGET: &str = "target";
|
pub const FLAG_TARGET: &str = "target";
|
||||||
pub const FLAG_TIME: &str = "time";
|
pub const FLAG_TIME: &str = "time";
|
||||||
pub const FLAG_VERBOSE: &str = "verbose";
|
pub const FLAG_VERBOSE: &str = "verbose";
|
||||||
|
pub const FLAG_NO_COLOR: &str = "no-color";
|
||||||
|
pub const FLAG_NO_HEADER: &str = "no-header";
|
||||||
pub const FLAG_LINKER: &str = "linker";
|
pub const FLAG_LINKER: &str = "linker";
|
||||||
pub const FLAG_BUILD_HOST: &str = "build-host";
|
pub const FLAG_BUILD_HOST: &str = "build-host";
|
||||||
pub const FLAG_SUPPRESS_BUILD_HOST_WARNING: &str = "suppress-build-host-warning";
|
pub const FLAG_SUPPRESS_BUILD_HOST_WARNING: &str = "suppress-build-host-warning";
|
||||||
|
@ -88,7 +90,7 @@ pub const FLAG_PP_HOST: &str = "host";
|
||||||
pub const FLAG_PP_PLATFORM: &str = "platform";
|
pub const FLAG_PP_PLATFORM: &str = "platform";
|
||||||
pub const FLAG_PP_DYLIB: &str = "lib";
|
pub const FLAG_PP_DYLIB: &str = "lib";
|
||||||
|
|
||||||
const VERSION: &str = include_str!("../../../version.txt");
|
pub const VERSION: &str = env!("ROC_VERSION");
|
||||||
const DEFAULT_GENERATED_DOCS_DIR: &str = "generated-docs";
|
const DEFAULT_GENERATED_DOCS_DIR: &str = "generated-docs";
|
||||||
|
|
||||||
pub fn build_app() -> Command {
|
pub fn build_app() -> Command {
|
||||||
|
@ -186,7 +188,7 @@ pub fn build_app() -> Command {
|
||||||
PossibleValuesParser::new(Target::iter().map(Into::<&'static str>::into));
|
PossibleValuesParser::new(Target::iter().map(Into::<&'static str>::into));
|
||||||
|
|
||||||
Command::new("roc")
|
Command::new("roc")
|
||||||
.version(concatcp!(VERSION, "\n"))
|
.version(VERSION)
|
||||||
.about("Run the given .roc file, if there are no compilation errors.\nYou can use one of the SUBCOMMANDS below to do something else!")
|
.about("Run the given .roc file, if there are no compilation errors.\nYou can use one of the SUBCOMMANDS below to do something else!")
|
||||||
.args_conflicts_with_subcommands(true)
|
.args_conflicts_with_subcommands(true)
|
||||||
.subcommand(Command::new(CMD_BUILD)
|
.subcommand(Command::new(CMD_BUILD)
|
||||||
|
@ -279,6 +281,20 @@ pub fn build_app() -> Command {
|
||||||
)
|
)
|
||||||
.subcommand(Command::new(CMD_REPL)
|
.subcommand(Command::new(CMD_REPL)
|
||||||
.about("Launch the interactive Read Eval Print Loop (REPL)")
|
.about("Launch the interactive Read Eval Print Loop (REPL)")
|
||||||
|
.arg(
|
||||||
|
Arg::new(FLAG_NO_COLOR)
|
||||||
|
.long(FLAG_NO_COLOR)
|
||||||
|
.help("Do not use any ANSI color codes in the repl output")
|
||||||
|
.action(ArgAction::SetTrue)
|
||||||
|
.required(false)
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new(FLAG_NO_HEADER)
|
||||||
|
.long(FLAG_NO_HEADER)
|
||||||
|
.help("Do not print the repl header")
|
||||||
|
.action(ArgAction::SetTrue)
|
||||||
|
.required(false)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
.subcommand(Command::new(CMD_RUN)
|
.subcommand(Command::new(CMD_RUN)
|
||||||
.about("Run a .roc file even if it has build errors")
|
.about("Run a .roc file even if it has build errors")
|
||||||
|
@ -542,7 +558,7 @@ pub fn test(matches: &ArgMatches, target: Target) -> io::Result<i32> {
|
||||||
arena,
|
arena,
|
||||||
path.to_path_buf(),
|
path.to_path_buf(),
|
||||||
opt_main_path.cloned(),
|
opt_main_path.cloned(),
|
||||||
RocCacheDir::Persistent(cache::roc_cache_dir().as_path()),
|
RocCacheDir::Persistent(cache::roc_cache_packages_dir().as_path()),
|
||||||
load_config,
|
load_config,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1266,8 +1282,8 @@ fn roc_dev_native(
|
||||||
break if libc::WIFEXITED(status) {
|
break if libc::WIFEXITED(status) {
|
||||||
libc::WEXITSTATUS(status)
|
libc::WEXITSTATUS(status)
|
||||||
} else {
|
} else {
|
||||||
// we don't have an exit code, so we probably shouldn't make one up
|
// we don't have an exit code, but something went wrong if we're in this else
|
||||||
0
|
1
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
ChildProcessMsg::Expect => {
|
ChildProcessMsg::Expect => {
|
||||||
|
|
|
@ -5,9 +5,9 @@ use roc_build::program::{check_file, CodeGenBackend};
|
||||||
use roc_cli::{
|
use roc_cli::{
|
||||||
build_app, format_files, format_src, test, BuildConfig, FormatMode, CMD_BUILD, CMD_CHECK,
|
build_app, format_files, format_src, test, BuildConfig, FormatMode, CMD_BUILD, CMD_CHECK,
|
||||||
CMD_DEV, CMD_DOCS, CMD_FORMAT, CMD_GLUE, CMD_PREPROCESS_HOST, CMD_REPL, CMD_RUN, CMD_TEST,
|
CMD_DEV, CMD_DOCS, CMD_FORMAT, CMD_GLUE, CMD_PREPROCESS_HOST, CMD_REPL, CMD_RUN, CMD_TEST,
|
||||||
CMD_VERSION, DIRECTORY_OR_FILES, FLAG_CHECK, FLAG_DEV, FLAG_LIB, FLAG_MAIN, FLAG_NO_LINK,
|
CMD_VERSION, DIRECTORY_OR_FILES, FLAG_CHECK, FLAG_DEV, FLAG_LIB, FLAG_MAIN, FLAG_NO_COLOR,
|
||||||
FLAG_OUTPUT, FLAG_PP_DYLIB, FLAG_PP_HOST, FLAG_PP_PLATFORM, FLAG_STDIN, FLAG_STDOUT,
|
FLAG_NO_HEADER, FLAG_NO_LINK, FLAG_OUTPUT, FLAG_PP_DYLIB, FLAG_PP_HOST, FLAG_PP_PLATFORM,
|
||||||
FLAG_TARGET, FLAG_TIME, GLUE_DIR, GLUE_SPEC, ROC_FILE,
|
FLAG_STDIN, FLAG_STDOUT, FLAG_TARGET, FLAG_TIME, GLUE_DIR, GLUE_SPEC, ROC_FILE, VERSION,
|
||||||
};
|
};
|
||||||
use roc_docs::generate_docs_html;
|
use roc_docs::generate_docs_html;
|
||||||
use roc_error_macros::user_error;
|
use roc_error_macros::user_error;
|
||||||
|
@ -22,9 +22,6 @@ use std::path::{Path, PathBuf};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use target_lexicon::Triple;
|
use target_lexicon::Triple;
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate const_format;
|
|
||||||
|
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc;
|
static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc;
|
||||||
|
|
||||||
|
@ -51,7 +48,7 @@ fn main() -> io::Result<()> {
|
||||||
BuildConfig::BuildAndRunIfNoErrors,
|
BuildConfig::BuildAndRunIfNoErrors,
|
||||||
Triple::host().into(),
|
Triple::host().into(),
|
||||||
None,
|
None,
|
||||||
RocCacheDir::Persistent(cache::roc_cache_dir().as_path()),
|
RocCacheDir::Persistent(cache::roc_cache_packages_dir().as_path()),
|
||||||
LinkType::Executable,
|
LinkType::Executable,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -66,7 +63,7 @@ fn main() -> io::Result<()> {
|
||||||
BuildConfig::BuildAndRun,
|
BuildConfig::BuildAndRun,
|
||||||
Triple::host().into(),
|
Triple::host().into(),
|
||||||
None,
|
None,
|
||||||
RocCacheDir::Persistent(cache::roc_cache_dir().as_path()),
|
RocCacheDir::Persistent(cache::roc_cache_packages_dir().as_path()),
|
||||||
LinkType::Executable,
|
LinkType::Executable,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -92,7 +89,7 @@ fn main() -> io::Result<()> {
|
||||||
BuildConfig::BuildAndRunIfNoErrors,
|
BuildConfig::BuildAndRunIfNoErrors,
|
||||||
Triple::host().into(),
|
Triple::host().into(),
|
||||||
None,
|
None,
|
||||||
RocCacheDir::Persistent(cache::roc_cache_dir().as_path()),
|
RocCacheDir::Persistent(cache::roc_cache_packages_dir().as_path()),
|
||||||
LinkType::Executable,
|
LinkType::Executable,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -190,7 +187,7 @@ fn main() -> io::Result<()> {
|
||||||
BuildConfig::BuildOnly,
|
BuildConfig::BuildOnly,
|
||||||
target,
|
target,
|
||||||
out_path,
|
out_path,
|
||||||
RocCacheDir::Persistent(cache::roc_cache_dir().as_path()),
|
RocCacheDir::Persistent(cache::roc_cache_packages_dir().as_path()),
|
||||||
link_type,
|
link_type,
|
||||||
)?)
|
)?)
|
||||||
}
|
}
|
||||||
|
@ -213,7 +210,7 @@ fn main() -> io::Result<()> {
|
||||||
roc_file_path.to_owned(),
|
roc_file_path.to_owned(),
|
||||||
opt_main_path.cloned(),
|
opt_main_path.cloned(),
|
||||||
emit_timings,
|
emit_timings,
|
||||||
RocCacheDir::Persistent(cache::roc_cache_dir().as_path()),
|
RocCacheDir::Persistent(cache::roc_cache_packages_dir().as_path()),
|
||||||
threading,
|
threading,
|
||||||
) {
|
) {
|
||||||
Ok((problems, total_time)) => {
|
Ok((problems, total_time)) => {
|
||||||
|
@ -231,7 +228,12 @@ fn main() -> io::Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some((CMD_REPL, _)) => Ok(roc_repl_cli::main()),
|
Some((CMD_REPL, matches)) => {
|
||||||
|
let has_color = !matches.get_one::<bool>(FLAG_NO_COLOR).unwrap();
|
||||||
|
let has_header = !matches.get_one::<bool>(FLAG_NO_HEADER).unwrap();
|
||||||
|
|
||||||
|
Ok(roc_repl_cli::main(has_color, has_header))
|
||||||
|
}
|
||||||
Some((CMD_DOCS, matches)) => {
|
Some((CMD_DOCS, matches)) => {
|
||||||
let root_path = matches.get_one::<PathBuf>(ROC_FILE).unwrap();
|
let root_path = matches.get_one::<PathBuf>(ROC_FILE).unwrap();
|
||||||
let out_dir = matches.get_one::<OsString>(FLAG_OUTPUT).unwrap();
|
let out_dir = matches.get_one::<OsString>(FLAG_OUTPUT).unwrap();
|
||||||
|
@ -347,11 +349,7 @@ fn main() -> io::Result<()> {
|
||||||
Ok(format_exit_code)
|
Ok(format_exit_code)
|
||||||
}
|
}
|
||||||
Some((CMD_VERSION, _)) => {
|
Some((CMD_VERSION, _)) => {
|
||||||
print!(
|
println!("roc {}", VERSION);
|
||||||
"{}",
|
|
||||||
concatcp!("roc ", include_str!("../../../version.txt"))
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
|
|
@ -767,6 +767,66 @@ mod cli_run {
|
||||||
let out = runner.run();
|
let out = runner.run();
|
||||||
out.assert_stdout_and_stderr_ends_with(expected_ending);
|
out.assert_stdout_and_stderr_ends_with(expected_ending);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg_attr(windows, ignore)]
|
||||||
|
fn module_params() {
|
||||||
|
build_platform_host();
|
||||||
|
|
||||||
|
let expected_ending = indoc!(
|
||||||
|
r#"
|
||||||
|
App1.baseUrl: https://api.example.com/one
|
||||||
|
App2.baseUrl: http://api.example.com/two
|
||||||
|
App3.baseUrl: https://api.example.com/three
|
||||||
|
App1.getUser 1: https://api.example.com/one/users/1
|
||||||
|
App2.getUser 2: http://api.example.com/two/users/2
|
||||||
|
App3.getUser 3: https://api.example.com/three/users/3
|
||||||
|
App1.getPost 1: https://api.example.com/one/posts/1
|
||||||
|
App2.getPost 2: http://api.example.com/two/posts/2
|
||||||
|
App3.getPost 3: https://api.example.com/three/posts/3
|
||||||
|
App1.getPosts [1, 2]: ["https://api.example.com/one/posts/1", "https://api.example.com/one/posts/2"]
|
||||||
|
App2.getPosts [3, 4]: ["http://api.example.com/two/posts/3", "http://api.example.com/two/posts/4"]
|
||||||
|
App2.getPosts [5, 6]: ["http://api.example.com/two/posts/5", "http://api.example.com/two/posts/6"]
|
||||||
|
App1.getPostComments 1: https://api.example.com/one/posts/1/comments
|
||||||
|
App2.getPostComments 2: http://api.example.com/two/posts/2/comments
|
||||||
|
App2.getPostComments 3: http://api.example.com/two/posts/3/comments
|
||||||
|
App1.getCompanies [1, 2]: ["https://api.example.com/one/companies/1", "https://api.example.com/one/companies/2"]
|
||||||
|
App2.getCompanies [3, 4]: ["http://api.example.com/two/companies/3", "http://api.example.com/two/companies/4"]
|
||||||
|
App2.getCompanies [5, 6]: ["http://api.example.com/two/companies/5", "http://api.example.com/two/companies/6"]
|
||||||
|
App1.getPostAliased 1: https://api.example.com/one/posts/1
|
||||||
|
App2.getPostAliased 2: http://api.example.com/two/posts/2
|
||||||
|
App3.getPostAliased 3: https://api.example.com/three/posts/3
|
||||||
|
App1.baseUrlAliased: https://api.example.com/one
|
||||||
|
App2.baseUrlAliased: http://api.example.com/two
|
||||||
|
App3.baseUrlAliased: https://api.example.com/three
|
||||||
|
App1.getUserSafe 1: https://api.example.com/one/users/1
|
||||||
|
Prod.getUserSafe 2: http://api.example.com/prod_1/users/2?safe=true
|
||||||
|
usersApp1: ["https://api.example.com/one/users/1", "https://api.example.com/one/users/2", "https://api.example.com/one/users/3"]
|
||||||
|
getUserApp3Nested 3: https://api.example.com/three/users/3
|
||||||
|
usersApp3Passed: ["https://api.example.com/three/users/1", "https://api.example.com/three/users/2", "https://api.example.com/three/users/3"]
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
let runner = cli_utils::helpers::Run::new_roc()
|
||||||
|
.arg(CMD_RUN)
|
||||||
|
.arg(file_from_root("crates/cli/tests/module_params", "app.roc").as_path());
|
||||||
|
|
||||||
|
let out = runner.run();
|
||||||
|
out.assert_stdout_and_stderr_ends_with(expected_ending);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg_attr(windows, ignore)]
|
||||||
|
fn module_params_arity_mismatch() {
|
||||||
|
build_platform_host();
|
||||||
|
|
||||||
|
let runner = cli_utils::helpers::Run::new_roc().arg(CMD_DEV).arg(
|
||||||
|
file_from_root("crates/cli/tests/module_params", "arity_mismatch.roc").as_path(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let out = runner.run();
|
||||||
|
|
||||||
|
insta::assert_snapshot!(out.normalize_stdout_and_stderr());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO not sure if this cfg should still be here: #[cfg(not(debug_assertions))]
|
// TODO not sure if this cfg should still be here: #[cfg(not(debug_assertions))]
|
||||||
|
|
8
crates/cli/tests/module_params/MultilineParams.roc
Normal file
8
crates/cli/tests/module_params/MultilineParams.roc
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
module {
|
||||||
|
sendHttpReq,
|
||||||
|
getEnvVar
|
||||||
|
} -> [hi]
|
||||||
|
|
||||||
|
hi : Str
|
||||||
|
hi =
|
||||||
|
"hi"
|
|
@ -1,5 +1,5 @@
|
||||||
app [main] {
|
app [main] {
|
||||||
pf: platform "../fixtures/multi-dep-str/platform/main.roc",
|
pf: platform "../test-platform-simple-zig/main.roc",
|
||||||
}
|
}
|
||||||
|
|
||||||
import Api { appId: "one", protocol: https } as App1
|
import Api { appId: "one", protocol: https } as App1
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
app [main] {
|
app [main] {
|
||||||
pf: platform "../fixtures/multi-dep-str/platform/main.roc",
|
pf: platform "../test-platform-simple-zig/main.roc",
|
||||||
}
|
}
|
||||||
|
|
||||||
import Api { appId: "one", protocol: https }
|
import Api { appId: "one", protocol: https }
|
||||||
|
|
11
crates/cli/tests/module_params/multiline_params.roc
Normal file
11
crates/cli/tests/module_params/multiline_params.roc
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
app [main] {
|
||||||
|
pf: platform "../fixtures/multi-dep-str/platform/main.roc",
|
||||||
|
}
|
||||||
|
|
||||||
|
import MultilineParams {
|
||||||
|
sendHttpReq: \_ -> crash "todo",
|
||||||
|
getEnvVar: \_ -> crash "todo",
|
||||||
|
}
|
||||||
|
|
||||||
|
main =
|
||||||
|
MultilineParams.hi
|
|
@ -1,5 +1,5 @@
|
||||||
app [main] {
|
app [main] {
|
||||||
pf: platform "../fixtures/multi-dep-str/platform/main.roc",
|
pf: platform "../test-platform-simple-zig/main.roc",
|
||||||
}
|
}
|
||||||
|
|
||||||
import Api { appId: "one", protocol: https }
|
import Api { appId: "one", protocol: https }
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
---
|
||||||
|
source: crates/cli/tests/cli_run.rs
|
||||||
|
expression: out.normalize_stdout_and_stderr()
|
||||||
|
---
|
||||||
|
── TOO MANY ARGS in tests/module_params/arity_mismatch.roc ─────────────────────
|
||||||
|
|
||||||
|
The getUser function expects 1 argument, but it got 2 instead:
|
||||||
|
|
||||||
|
12│ $(Api.getUser 1 2)
|
||||||
|
^^^^^^^^^^^
|
||||||
|
|
||||||
|
Are there any missing commas? Or missing parentheses?
|
||||||
|
|
||||||
|
|
||||||
|
── TOO MANY ARGS in tests/module_params/arity_mismatch.roc ─────────────────────
|
||||||
|
|
||||||
|
This value is not a function, but it was given 1 argument:
|
||||||
|
|
||||||
|
13│ $(Api.baseUrl 1)
|
||||||
|
^^^^^^^^^^^
|
||||||
|
|
||||||
|
Are there any missing commas? Or missing parentheses?
|
||||||
|
|
||||||
|
|
||||||
|
── TOO FEW ARGS in tests/module_params/arity_mismatch.roc ──────────────────────
|
||||||
|
|
||||||
|
The getPostComment function expects 2 arguments, but it got only 1:
|
||||||
|
|
||||||
|
16│ $(Api.getPostComment 1)
|
||||||
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Roc does not allow functions to be partially applied. Use a closure to
|
||||||
|
make partial application explicit.
|
||||||
|
|
||||||
|
────────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
3 error and 0 warning found in <ignored for test> ms
|
||||||
|
.
|
||||||
|
|
||||||
|
You can run the program anyway <ignored for tests>
|
|
@ -101,9 +101,18 @@ impl Out {
|
||||||
Regex::new(r"(\d+) error(?:s)? and (\d+) warning(?:s)? found in \d+ ms")
|
Regex::new(r"(\d+) error(?:s)? and (\d+) warning(?:s)? found in \d+ ms")
|
||||||
.expect("Invalid error summary regex pattern");
|
.expect("Invalid error summary regex pattern");
|
||||||
let error_summary_replacement = "$1 error and $2 warning found in <ignored for test> ms";
|
let error_summary_replacement = "$1 error and $2 warning found in <ignored for test> ms";
|
||||||
error_summary_regex
|
let without_error_summary = error_summary_regex
|
||||||
.replace_all(&without_filepaths, error_summary_replacement)
|
.replace_all(&without_filepaths, error_summary_replacement)
|
||||||
.to_string()
|
.to_string();
|
||||||
|
|
||||||
|
// replace the entire line with the placeholder
|
||||||
|
let run_command_line_regex = Regex::new(r"(?m)^You can run the program anyway .*$")
|
||||||
|
.expect("Invalid run command line regex pattern");
|
||||||
|
let run_command_line_replacement = "You can run the program anyway <ignored for tests>";
|
||||||
|
let normalized_output = run_command_line_regex
|
||||||
|
.replace_all(&without_error_summary, run_command_line_replacement);
|
||||||
|
|
||||||
|
normalized_output.trim().to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Assert that the stdout ends with the expected string
|
/// Assert that the stdout ends with the expected string
|
||||||
|
@ -129,6 +138,14 @@ impl Out {
|
||||||
ANSI_STYLE_CODES.reset,
|
ANSI_STYLE_CODES.reset,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn normalize_stdout_and_stderr(&self) -> String {
|
||||||
|
format!(
|
||||||
|
"{}{}",
|
||||||
|
Out::normalize_for_tests(&self.stdout),
|
||||||
|
Out::normalize_for_tests(&self.stderr)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A builder for running a command.
|
/// A builder for running a command.
|
||||||
|
|
|
@ -618,6 +618,16 @@ pub fn listDropAt(
|
||||||
) callconv(.C) RocList {
|
) callconv(.C) RocList {
|
||||||
const size = list.len();
|
const size = list.len();
|
||||||
const size_u64 = @as(u64, @intCast(size));
|
const size_u64 = @as(u64, @intCast(size));
|
||||||
|
|
||||||
|
// NOTE
|
||||||
|
// we need to return an empty list explicitly,
|
||||||
|
// because we rely on the pointer field being null if the list is empty
|
||||||
|
// which also requires duplicating the utils.decref call to spend the RC token
|
||||||
|
if (size <= 1) {
|
||||||
|
list.decref(alignment, element_width, elements_refcounted, dec);
|
||||||
|
return RocList.empty();
|
||||||
|
}
|
||||||
|
|
||||||
// If droping the first or last element, return a seamless slice.
|
// If droping the first or last element, return a seamless slice.
|
||||||
// For simplicity, do this by calling listSublist.
|
// For simplicity, do this by calling listSublist.
|
||||||
// In the future, we can test if it is faster to manually inline the important parts here.
|
// In the future, we can test if it is faster to manually inline the important parts here.
|
||||||
|
@ -638,25 +648,16 @@ pub fn listDropAt(
|
||||||
// were >= than `size`, and we know `size` fits in usize.
|
// were >= than `size`, and we know `size` fits in usize.
|
||||||
const drop_index: usize = @intCast(drop_index_u64);
|
const drop_index: usize = @intCast(drop_index_u64);
|
||||||
|
|
||||||
if (elements_refcounted) {
|
|
||||||
const element = source_ptr + drop_index * element_width;
|
|
||||||
dec(element);
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE
|
|
||||||
// we need to return an empty list explicitly,
|
|
||||||
// because we rely on the pointer field being null if the list is empty
|
|
||||||
// which also requires duplicating the utils.decref call to spend the RC token
|
|
||||||
if (size < 2) {
|
|
||||||
list.decref(alignment, element_width, elements_refcounted, dec);
|
|
||||||
return RocList.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (list.isUnique()) {
|
if (list.isUnique()) {
|
||||||
var i = drop_index;
|
if (elements_refcounted) {
|
||||||
const copy_target = source_ptr;
|
const element = source_ptr + drop_index * element_width;
|
||||||
|
dec(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
const copy_target = source_ptr + (drop_index * element_width);
|
||||||
const copy_source = copy_target + element_width;
|
const copy_source = copy_target + element_width;
|
||||||
std.mem.copyForwards(u8, copy_target[i..size], copy_source[i..size]);
|
const copy_size = (size - drop_index - 1) * element_width;
|
||||||
|
std.mem.copyForwards(u8, copy_target[0..copy_size], copy_source[0..copy_size]);
|
||||||
|
|
||||||
var new_list = list;
|
var new_list = list;
|
||||||
|
|
||||||
|
|
|
@ -509,33 +509,33 @@ removeHelper = \buckets, bucketIndex, distAndFingerprint, data, key ->
|
||||||
## is missing. This is more efficient than doing both a `Dict.get` and then a
|
## is missing. This is more efficient than doing both a `Dict.get` and then a
|
||||||
## `Dict.insert` call, and supports being piped.
|
## `Dict.insert` call, and supports being piped.
|
||||||
## ```roc
|
## ```roc
|
||||||
## alterValue : [Present Bool, Missing] -> [Present Bool, Missing]
|
## alterValue : Result Bool [Missing] -> Result Bool [Missing]
|
||||||
## alterValue = \possibleValue ->
|
## alterValue = \possibleValue ->
|
||||||
## when possibleValue is
|
## when possibleValue is
|
||||||
## Missing -> Present Bool.false
|
## Err -> Ok Bool.false
|
||||||
## Present value -> if value then Missing else Present Bool.true
|
## Ok value -> if value then Err Missing else Ok Bool.true
|
||||||
##
|
##
|
||||||
## expect Dict.update (Dict.empty {}) "a" alterValue == Dict.single "a" Bool.false
|
## expect Dict.update (Dict.empty {}) "a" alterValue == Dict.single "a" Bool.false
|
||||||
## expect Dict.update (Dict.single "a" Bool.false) "a" alterValue == Dict.single "a" Bool.true
|
## expect Dict.update (Dict.single "a" Bool.false) "a" alterValue == Dict.single "a" Bool.true
|
||||||
## expect Dict.update (Dict.single "a" Bool.true) "a" alterValue == Dict.empty {}
|
## expect Dict.update (Dict.single "a" Bool.true) "a" alterValue == Dict.empty {}
|
||||||
## ```
|
## ```
|
||||||
update : Dict k v, k, ([Present v, Missing] -> [Present v, Missing]) -> Dict k v
|
update : Dict k v, k, (Result v [Missing] -> Result v [Missing]) -> Dict k v
|
||||||
update = \@Dict { buckets, data, maxBucketCapacity, maxLoadFactor, shifts }, key, alter ->
|
update = \@Dict { buckets, data, maxBucketCapacity, maxLoadFactor, shifts }, key, alter ->
|
||||||
{ bucketIndex, result } = find (@Dict { buckets, data, maxBucketCapacity, maxLoadFactor, shifts }) key
|
{ bucketIndex, result } = find (@Dict { buckets, data, maxBucketCapacity, maxLoadFactor, shifts }) key
|
||||||
when result is
|
when result is
|
||||||
Ok value ->
|
Ok value ->
|
||||||
when alter (Present value) is
|
when alter (Ok value) is
|
||||||
Present newValue ->
|
Ok newValue ->
|
||||||
bucket = listGetUnsafe buckets bucketIndex
|
bucket = listGetUnsafe buckets bucketIndex
|
||||||
newData = List.set data (Num.toU64 bucket.dataIndex) (key, newValue)
|
newData = List.set data (Num.toU64 bucket.dataIndex) (key, newValue)
|
||||||
@Dict { buckets, data: newData, maxBucketCapacity, maxLoadFactor, shifts }
|
@Dict { buckets, data: newData, maxBucketCapacity, maxLoadFactor, shifts }
|
||||||
|
|
||||||
Missing ->
|
Err Missing ->
|
||||||
removeBucket (@Dict { buckets, data, maxBucketCapacity, maxLoadFactor, shifts }) bucketIndex
|
removeBucket (@Dict { buckets, data, maxBucketCapacity, maxLoadFactor, shifts }) bucketIndex
|
||||||
|
|
||||||
Err KeyNotFound ->
|
Err KeyNotFound ->
|
||||||
when alter Missing is
|
when alter (Err Missing) is
|
||||||
Present newValue ->
|
Ok newValue ->
|
||||||
if List.len data >= maxBucketCapacity then
|
if List.len data >= maxBucketCapacity then
|
||||||
# Need to reallocate let regular insert handle that.
|
# Need to reallocate let regular insert handle that.
|
||||||
insert (@Dict { buckets, data, maxBucketCapacity, maxLoadFactor, shifts }) key newValue
|
insert (@Dict { buckets, data, maxBucketCapacity, maxLoadFactor, shifts }) key newValue
|
||||||
|
@ -556,7 +556,7 @@ update = \@Dict { buckets, data, maxBucketCapacity, maxLoadFactor, shifts }, key
|
||||||
distAndFingerprint = incrementDistN baseDistAndFingerprint (Num.toU32 dist)
|
distAndFingerprint = incrementDistN baseDistAndFingerprint (Num.toU32 dist)
|
||||||
insertHelper buckets data bucketIndex distAndFingerprint key newValue maxBucketCapacity maxLoadFactor shifts
|
insertHelper buckets data bucketIndex distAndFingerprint key newValue maxBucketCapacity maxLoadFactor shifts
|
||||||
|
|
||||||
Missing ->
|
Err Missing ->
|
||||||
@Dict { buckets, data, maxBucketCapacity, maxLoadFactor, shifts }
|
@Dict { buckets, data, maxBucketCapacity, maxLoadFactor, shifts }
|
||||||
|
|
||||||
circularDist = \start, end, size ->
|
circularDist = \start, end, size ->
|
||||||
|
@ -1216,8 +1216,8 @@ expect
|
||||||
List.walk badKeys (Dict.empty {}) \acc, k ->
|
List.walk badKeys (Dict.empty {}) \acc, k ->
|
||||||
Dict.update acc k \val ->
|
Dict.update acc k \val ->
|
||||||
when val is
|
when val is
|
||||||
Present p -> Present (p |> Num.addWrap 1)
|
Ok p -> Ok (p |> Num.addWrap 1)
|
||||||
Missing -> Present 0
|
Err Missing -> Ok 0
|
||||||
|
|
||||||
allInsertedCorrectly =
|
allInsertedCorrectly =
|
||||||
List.walk badKeys Bool.true \acc, k ->
|
List.walk badKeys Bool.true \acc, k ->
|
||||||
|
|
|
@ -548,6 +548,23 @@ tau = 2 * pi
|
||||||
## [F64] or [F32] value, the returned string will be `"NaN"`, `"∞"`, or `"-∞"`.
|
## [F64] or [F32] value, the returned string will be `"NaN"`, `"∞"`, or `"-∞"`.
|
||||||
##
|
##
|
||||||
toStr : Num * -> Str
|
toStr : Num * -> Str
|
||||||
|
|
||||||
|
## Convert an [Int] to a new [Int] of the expected type:
|
||||||
|
##
|
||||||
|
## ```roc
|
||||||
|
## # Casts a U8 to a U16
|
||||||
|
## x : U16
|
||||||
|
## x = Num.intCast 255u8
|
||||||
|
## ```
|
||||||
|
##
|
||||||
|
## In the case of downsizing, information is lost:
|
||||||
|
##
|
||||||
|
## ```roc
|
||||||
|
## # returns 0, as the bits were truncated.
|
||||||
|
## x : U8
|
||||||
|
## x = Num.intCast 256u16
|
||||||
|
## ```
|
||||||
|
##
|
||||||
intCast : Int a -> Int b
|
intCast : Int a -> Int b
|
||||||
|
|
||||||
compare : Num a, Num a -> [LT, EQ, GT]
|
compare : Num a, Num a -> [LT, EQ, GT]
|
||||||
|
|
|
@ -367,6 +367,8 @@ module [
|
||||||
withCapacity,
|
withCapacity,
|
||||||
withPrefix,
|
withPrefix,
|
||||||
contains,
|
contains,
|
||||||
|
dropPrefix,
|
||||||
|
dropSuffix,
|
||||||
]
|
]
|
||||||
|
|
||||||
import Bool exposing [Bool]
|
import Bool exposing [Bool]
|
||||||
|
@ -1052,3 +1054,37 @@ contains = \haystack, needle ->
|
||||||
when firstMatch haystack needle is
|
when firstMatch haystack needle is
|
||||||
Some _index -> Bool.true
|
Some _index -> Bool.true
|
||||||
None -> Bool.false
|
None -> Bool.false
|
||||||
|
|
||||||
|
## Drops the given prefix [Str] from the start of a [Str]
|
||||||
|
## If the prefix is not found, returns the original string.
|
||||||
|
##
|
||||||
|
## ```roc
|
||||||
|
## expect Str.dropPrefix "bar" "foo" == "bar"
|
||||||
|
## expect Str.dropPrefix "foobar" "foo" == "bar"
|
||||||
|
## ```
|
||||||
|
dropPrefix : Str, Str -> Str
|
||||||
|
dropPrefix = \haystack, prefix ->
|
||||||
|
if Str.startsWith haystack prefix then
|
||||||
|
start = Str.countUtf8Bytes prefix
|
||||||
|
len = Num.subWrap (Str.countUtf8Bytes haystack) start
|
||||||
|
|
||||||
|
substringUnsafe haystack start len
|
||||||
|
else
|
||||||
|
haystack
|
||||||
|
|
||||||
|
## Drops the given suffix [Str] from the end of a [Str]
|
||||||
|
## If the suffix is not found, returns the original string.
|
||||||
|
##
|
||||||
|
## ```roc
|
||||||
|
## expect Str.dropSuffix "bar" "foo" == "bar"
|
||||||
|
## expect Str.dropSuffix "barfoo" "foo" == "bar"
|
||||||
|
## ```
|
||||||
|
dropSuffix : Str, Str -> Str
|
||||||
|
dropSuffix = \haystack, suffix ->
|
||||||
|
if Str.endsWith haystack suffix then
|
||||||
|
start = 0
|
||||||
|
len = Num.subWrap (Str.countUtf8Bytes haystack) (Str.countUtf8Bytes suffix)
|
||||||
|
|
||||||
|
substringUnsafe haystack start len
|
||||||
|
else
|
||||||
|
haystack
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -7,7 +7,7 @@ use roc_collections::{MutMap, VecSet};
|
||||||
use roc_module::ident::{Ident, ModuleName};
|
use roc_module::ident::{Ident, ModuleName};
|
||||||
use roc_module::symbol::{IdentIdsByModule, ModuleId, PQModuleName, PackageModuleIds, Symbol};
|
use roc_module::symbol::{IdentIdsByModule, ModuleId, PQModuleName, PackageModuleIds, Symbol};
|
||||||
use roc_problem::can::{Problem, RuntimeError};
|
use roc_problem::can::{Problem, RuntimeError};
|
||||||
use roc_region::all::{Loc, Region};
|
use roc_region::all::{LineInfo, Loc, Region};
|
||||||
use roc_types::subs::Variable;
|
use roc_types::subs::Variable;
|
||||||
|
|
||||||
/// The canonicalization environment for a particular module.
|
/// The canonicalization environment for a particular module.
|
||||||
|
@ -44,11 +44,19 @@ pub struct Env<'a> {
|
||||||
pub arena: &'a Bump,
|
pub arena: &'a Bump,
|
||||||
|
|
||||||
pub opt_shorthand: Option<&'a str>,
|
pub opt_shorthand: Option<&'a str>,
|
||||||
|
|
||||||
|
pub src: &'a str,
|
||||||
|
|
||||||
|
/// Lazily calculated line info. This data is only needed if the code contains calls to `dbg`,
|
||||||
|
/// otherwise we can leave it as `None` and never pay the cost of scanning the source an extra
|
||||||
|
/// time.
|
||||||
|
line_info: &'a mut Option<LineInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Env<'a> {
|
impl<'a> Env<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
|
src: &'a str,
|
||||||
home: ModuleId,
|
home: ModuleId,
|
||||||
module_path: &'a Path,
|
module_path: &'a Path,
|
||||||
dep_idents: &'a IdentIdsByModule,
|
dep_idents: &'a IdentIdsByModule,
|
||||||
|
@ -57,6 +65,7 @@ impl<'a> Env<'a> {
|
||||||
) -> Env<'a> {
|
) -> Env<'a> {
|
||||||
Env {
|
Env {
|
||||||
arena,
|
arena,
|
||||||
|
src,
|
||||||
home,
|
home,
|
||||||
module_path,
|
module_path,
|
||||||
dep_idents,
|
dep_idents,
|
||||||
|
@ -69,6 +78,7 @@ impl<'a> Env<'a> {
|
||||||
top_level_symbols: VecSet::default(),
|
top_level_symbols: VecSet::default(),
|
||||||
home_params_record: None,
|
home_params_record: None,
|
||||||
opt_shorthand,
|
opt_shorthand,
|
||||||
|
line_info: arena.alloc(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,4 +229,11 @@ impl<'a> Env<'a> {
|
||||||
pub fn problem(&mut self, problem: Problem) {
|
pub fn problem(&mut self, problem: Problem) {
|
||||||
self.problems.push(problem)
|
self.problems.push(problem)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn line_info(&mut self) -> &LineInfo {
|
||||||
|
if self.line_info.is_none() {
|
||||||
|
*self.line_info = Some(LineInfo::new(self.src));
|
||||||
|
}
|
||||||
|
self.line_info.as_ref().unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1013,11 +1013,8 @@ pub fn canonicalize_expr<'a>(
|
||||||
can_defs_with_return(env, var_store, inner_scope, env.arena.alloc(defs), loc_ret)
|
can_defs_with_return(env, var_store, inner_scope, env.arena.alloc(defs), loc_ret)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ast::Expr::OldRecordBuilder(_) => {
|
|
||||||
internal_error!("Old record builder should have been desugared by now")
|
|
||||||
}
|
|
||||||
ast::Expr::RecordBuilder { .. } => {
|
ast::Expr::RecordBuilder { .. } => {
|
||||||
internal_error!("New record builder should have been desugared by now")
|
internal_error!("Record builder should have been desugared by now")
|
||||||
}
|
}
|
||||||
ast::Expr::Backpassing(_, _, _) => {
|
ast::Expr::Backpassing(_, _, _) => {
|
||||||
internal_error!("Backpassing should have been desugared by now")
|
internal_error!("Backpassing should have been desugared by now")
|
||||||
|
@ -1209,8 +1206,20 @@ pub fn canonicalize_expr<'a>(
|
||||||
output,
|
output,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ast::Expr::Dbg | ast::Expr::DbgStmt(_, _) => {
|
ast::Expr::Dbg => {
|
||||||
internal_error!("Dbg should have been desugared by now")
|
// Dbg was not desugared as either part of an `Apply` or a `Pizza` binop, so it's
|
||||||
|
// invalid.
|
||||||
|
env.problem(Problem::UnappliedDbg { region });
|
||||||
|
|
||||||
|
let invalid_dbg_expr = crate::desugar::desugar_invalid_dbg_expr(env, scope, region);
|
||||||
|
|
||||||
|
let (loc_expr, output) =
|
||||||
|
canonicalize_expr(env, var_store, scope, region, invalid_dbg_expr);
|
||||||
|
|
||||||
|
(loc_expr.value, output)
|
||||||
|
}
|
||||||
|
ast::Expr::DbgStmt(_, _) => {
|
||||||
|
internal_error!("DbgStmt should have been desugared by now")
|
||||||
}
|
}
|
||||||
ast::Expr::LowLevelDbg((source_location, source), message, continuation) => {
|
ast::Expr::LowLevelDbg((source_location, source), message, continuation) => {
|
||||||
let mut output = Output::default();
|
let mut output = Output::default();
|
||||||
|
@ -1249,7 +1258,11 @@ pub fn canonicalize_expr<'a>(
|
||||||
output,
|
output,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ast::Expr::If(if_thens, final_else_branch) => {
|
ast::Expr::If {
|
||||||
|
if_thens,
|
||||||
|
final_else: final_else_branch,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
let mut branches = Vec::with_capacity(if_thens.len());
|
let mut branches = Vec::with_capacity(if_thens.len());
|
||||||
let mut output = Output::default();
|
let mut output = Output::default();
|
||||||
|
|
||||||
|
@ -1340,22 +1353,6 @@ pub fn canonicalize_expr<'a>(
|
||||||
use roc_problem::can::RuntimeError::*;
|
use roc_problem::can::RuntimeError::*;
|
||||||
(RuntimeError(MalformedSuffixed(region)), Output::default())
|
(RuntimeError(MalformedSuffixed(region)), Output::default())
|
||||||
}
|
}
|
||||||
ast::Expr::MultipleOldRecordBuilders(sub_expr) => {
|
|
||||||
use roc_problem::can::RuntimeError::*;
|
|
||||||
|
|
||||||
let problem = MultipleOldRecordBuilders(sub_expr.region);
|
|
||||||
env.problem(Problem::RuntimeError(problem.clone()));
|
|
||||||
|
|
||||||
(RuntimeError(problem), Output::default())
|
|
||||||
}
|
|
||||||
ast::Expr::UnappliedOldRecordBuilder(sub_expr) => {
|
|
||||||
use roc_problem::can::RuntimeError::*;
|
|
||||||
|
|
||||||
let problem = UnappliedOldRecordBuilder(sub_expr.region);
|
|
||||||
env.problem(Problem::RuntimeError(problem.clone()));
|
|
||||||
|
|
||||||
(RuntimeError(problem), Output::default())
|
|
||||||
}
|
|
||||||
ast::Expr::EmptyRecordBuilder(sub_expr) => {
|
ast::Expr::EmptyRecordBuilder(sub_expr) => {
|
||||||
use roc_problem::can::RuntimeError::*;
|
use roc_problem::can::RuntimeError::*;
|
||||||
|
|
||||||
|
@ -2536,8 +2533,6 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
|
||||||
.iter()
|
.iter()
|
||||||
.all(|loc_field| is_valid_interpolation(&loc_field.value)),
|
.all(|loc_field| is_valid_interpolation(&loc_field.value)),
|
||||||
ast::Expr::MalformedSuffixed(loc_expr)
|
ast::Expr::MalformedSuffixed(loc_expr)
|
||||||
| ast::Expr::MultipleOldRecordBuilders(loc_expr)
|
|
||||||
| ast::Expr::UnappliedOldRecordBuilder(loc_expr)
|
|
||||||
| ast::Expr::EmptyRecordBuilder(loc_expr)
|
| ast::Expr::EmptyRecordBuilder(loc_expr)
|
||||||
| ast::Expr::SingleFieldRecordBuilder(loc_expr)
|
| ast::Expr::SingleFieldRecordBuilder(loc_expr)
|
||||||
| ast::Expr::OptionalFieldInRecordBuilder(_, loc_expr)
|
| ast::Expr::OptionalFieldInRecordBuilder(_, loc_expr)
|
||||||
|
@ -2560,7 +2555,11 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
|
||||||
.iter()
|
.iter()
|
||||||
.all(|(loc_expr, _binop)| is_valid_interpolation(&loc_expr.value))
|
.all(|(loc_expr, _binop)| is_valid_interpolation(&loc_expr.value))
|
||||||
}
|
}
|
||||||
ast::Expr::If(branches, final_branch) => {
|
ast::Expr::If {
|
||||||
|
if_thens: branches,
|
||||||
|
final_else: final_branch,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
is_valid_interpolation(&final_branch.value)
|
is_valid_interpolation(&final_branch.value)
|
||||||
&& branches.iter().all(|(loc_before, loc_after)| {
|
&& branches.iter().all(|(loc_before, loc_after)| {
|
||||||
is_valid_interpolation(&loc_before.value)
|
is_valid_interpolation(&loc_before.value)
|
||||||
|
@ -2583,27 +2582,6 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
|
||||||
| ast::AssignedField::SpaceAfter(_, _) => false,
|
| ast::AssignedField::SpaceAfter(_, _) => false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ast::Expr::OldRecordBuilder(fields) => {
|
|
||||||
fields.iter().all(|loc_field| match loc_field.value {
|
|
||||||
ast::OldRecordBuilderField::Value(_label, comments, loc_expr) => {
|
|
||||||
comments.is_empty() && is_valid_interpolation(&loc_expr.value)
|
|
||||||
}
|
|
||||||
ast::OldRecordBuilderField::ApplyValue(
|
|
||||||
_label,
|
|
||||||
comments_before,
|
|
||||||
comments_after,
|
|
||||||
loc_expr,
|
|
||||||
) => {
|
|
||||||
comments_before.is_empty()
|
|
||||||
&& comments_after.is_empty()
|
|
||||||
&& is_valid_interpolation(&loc_expr.value)
|
|
||||||
}
|
|
||||||
ast::OldRecordBuilderField::Malformed(_)
|
|
||||||
| ast::OldRecordBuilderField::LabelOnly(_) => true,
|
|
||||||
ast::OldRecordBuilderField::SpaceBefore(_, _)
|
|
||||||
| ast::OldRecordBuilderField::SpaceAfter(_, _) => false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
ast::Expr::RecordBuilder { mapper, fields } => {
|
ast::Expr::RecordBuilder { mapper, fields } => {
|
||||||
is_valid_interpolation(&mapper.value)
|
is_valid_interpolation(&mapper.value)
|
||||||
&& fields.iter().all(|loc_field| match loc_field.value {
|
&& fields.iter().all(|loc_field| match loc_field.value {
|
||||||
|
|
|
@ -3,6 +3,7 @@ use std::path::Path;
|
||||||
use crate::abilities::{AbilitiesStore, ImplKey, PendingAbilitiesStore, ResolvedImpl};
|
use crate::abilities::{AbilitiesStore, ImplKey, PendingAbilitiesStore, ResolvedImpl};
|
||||||
use crate::annotation::{canonicalize_annotation, AnnotationFor};
|
use crate::annotation::{canonicalize_annotation, AnnotationFor};
|
||||||
use crate::def::{canonicalize_defs, report_unused_imports, Def};
|
use crate::def::{canonicalize_defs, report_unused_imports, Def};
|
||||||
|
use crate::desugar::desugar_record_destructures;
|
||||||
use crate::env::Env;
|
use crate::env::Env;
|
||||||
use crate::expr::{
|
use crate::expr::{
|
||||||
ClosureData, DbgLookup, Declarations, ExpectLookup, Expr, Output, PendingDerives,
|
ClosureData, DbgLookup, Declarations, ExpectLookup, Expr, Output, PendingDerives,
|
||||||
|
@ -240,6 +241,7 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
);
|
);
|
||||||
let mut env = Env::new(
|
let mut env = Env::new(
|
||||||
arena,
|
arena,
|
||||||
|
src,
|
||||||
home,
|
home,
|
||||||
arena.alloc(Path::new(module_path)),
|
arena.alloc(Path::new(module_path)),
|
||||||
dep_idents,
|
dep_idents,
|
||||||
|
@ -266,16 +268,7 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
// operators, and then again on *their* nested operators, ultimately applying the
|
// operators, and then again on *their* nested operators, ultimately applying the
|
||||||
// rules multiple times unnecessarily.
|
// rules multiple times unnecessarily.
|
||||||
|
|
||||||
crate::desugar::desugar_defs_node_values(
|
crate::desugar::desugar_defs_node_values(&mut env, &mut scope, loc_defs, true);
|
||||||
arena,
|
|
||||||
var_store,
|
|
||||||
loc_defs,
|
|
||||||
src,
|
|
||||||
&mut None,
|
|
||||||
module_path,
|
|
||||||
true,
|
|
||||||
&mut env.problems,
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut rigid_variables = RigidVariables::default();
|
let mut rigid_variables = RigidVariables::default();
|
||||||
|
|
||||||
|
@ -334,13 +327,16 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
before_arrow: _,
|
before_arrow: _,
|
||||||
after_arrow: _,
|
after_arrow: _,
|
||||||
}| {
|
}| {
|
||||||
|
let desugared_patterns =
|
||||||
|
desugar_record_destructures(&mut env, &mut scope, pattern.value);
|
||||||
|
|
||||||
let (destructs, _) = canonicalize_record_destructs(
|
let (destructs, _) = canonicalize_record_destructs(
|
||||||
&mut env,
|
&mut env,
|
||||||
var_store,
|
var_store,
|
||||||
&mut scope,
|
&mut scope,
|
||||||
&mut output,
|
&mut output,
|
||||||
PatternType::ModuleParams,
|
PatternType::ModuleParams,
|
||||||
&pattern.value,
|
&desugared_patterns,
|
||||||
pattern.region,
|
pattern.region,
|
||||||
PermitShadows(false),
|
PermitShadows(false),
|
||||||
);
|
);
|
||||||
|
|
|
@ -914,7 +914,10 @@ pub fn canonicalize_record_destructs<'a>(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
_ => unreachable!("Any other pattern should have given a parse error"),
|
_ => unreachable!(
|
||||||
|
"Any other pattern should have given a parse error: {:?}",
|
||||||
|
loc_pattern.value
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -466,7 +466,7 @@ impl Scope {
|
||||||
self.home.register_debug_idents(&self.locals.ident_ids)
|
self.home.register_debug_idents(&self.locals.ident_ids)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a unique, new symbol like "$1" or "$5",
|
/// Generates a unique, new symbol like "1" or "5",
|
||||||
/// using the home module as the module_id.
|
/// using the home module as the module_id.
|
||||||
///
|
///
|
||||||
/// This is used, for example, during canonicalization of an Expr::Closure
|
/// This is used, for example, during canonicalization of an Expr::Closure
|
||||||
|
@ -475,6 +475,12 @@ impl Scope {
|
||||||
Symbol::new(self.home, self.locals.gen_unique())
|
Symbol::new(self.home, self.locals.gen_unique())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generates a unique new symbol and return the symbol's unqualified identifier name.
|
||||||
|
pub fn gen_unique_symbol_name(&mut self) -> &str {
|
||||||
|
let ident_id = self.locals.gen_unique();
|
||||||
|
self.locals.ident_ids.get_name(ident_id).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
/// Introduce a new ignored variable (variable starting with an underscore).
|
/// Introduce a new ignored variable (variable starting with an underscore).
|
||||||
/// The underscore itself should not be included in `ident`.
|
/// The underscore itself should not be included in `ident`.
|
||||||
pub fn introduce_ignored_local(&mut self, ident: &str, region: Region) {
|
pub fn introduce_ignored_local(&mut self, ident: &str, region: Region) {
|
||||||
|
|
|
@ -131,7 +131,7 @@ pub fn unwrap_suffixed_expression<'a>(
|
||||||
|
|
||||||
Expr::When(..) => unwrap_suffixed_expression_when_help(arena, loc_expr, maybe_def_pat),
|
Expr::When(..) => unwrap_suffixed_expression_when_help(arena, loc_expr, maybe_def_pat),
|
||||||
|
|
||||||
Expr::If(..) => {
|
Expr::If { .. } => {
|
||||||
unwrap_suffixed_expression_if_then_else_help(arena, loc_expr, maybe_def_pat)
|
unwrap_suffixed_expression_if_then_else_help(arena, loc_expr, maybe_def_pat)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,7 +325,14 @@ pub fn unwrap_suffixed_expression_apply_help<'a>(
|
||||||
|
|
||||||
let new_apply = arena.alloc(Loc::at(loc_expr.region, Expr::Apply(unwrapped_function, local_args, called_via)));
|
let new_apply = arena.alloc(Loc::at(loc_expr.region, Expr::Apply(unwrapped_function, local_args, called_via)));
|
||||||
|
|
||||||
return init_unwrapped_err(arena, new_apply, maybe_def_pat, target);
|
match maybe_def_pat {
|
||||||
|
Some(..) => {
|
||||||
|
return Err(EUnwrapped::UnwrappedDefExpr { loc_expr: new_apply, target });
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return init_unwrapped_err(arena, new_apply, maybe_def_pat, target);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// function is another expression
|
// function is another expression
|
||||||
|
@ -357,7 +364,11 @@ pub fn unwrap_suffixed_expression_if_then_else_help<'a>(
|
||||||
maybe_def_pat: Option<&'a Loc<Pattern<'a>>>,
|
maybe_def_pat: Option<&'a Loc<Pattern<'a>>>,
|
||||||
) -> Result<&'a Loc<Expr<'a>>, EUnwrapped<'a>> {
|
) -> Result<&'a Loc<Expr<'a>>, EUnwrapped<'a>> {
|
||||||
match loc_expr.value {
|
match loc_expr.value {
|
||||||
Expr::If(if_thens, final_else_branch) => {
|
Expr::If {
|
||||||
|
if_thens,
|
||||||
|
final_else: final_else_branch,
|
||||||
|
indented_else,
|
||||||
|
} => {
|
||||||
for (index, if_then) in if_thens.iter().enumerate() {
|
for (index, if_then) in if_thens.iter().enumerate() {
|
||||||
let (current_if_then_statement, current_if_then_expression) = if_then;
|
let (current_if_then_statement, current_if_then_expression) = if_then;
|
||||||
|
|
||||||
|
@ -376,10 +387,11 @@ pub fn unwrap_suffixed_expression_if_then_else_help<'a>(
|
||||||
|
|
||||||
let new_if = arena.alloc(Loc::at(
|
let new_if = arena.alloc(Loc::at(
|
||||||
loc_expr.region,
|
loc_expr.region,
|
||||||
Expr::If(
|
Expr::If {
|
||||||
arena.alloc_slice_copy(new_if_thens.as_slice()),
|
if_thens: arena.alloc_slice_copy(new_if_thens.as_slice()),
|
||||||
final_else_branch,
|
final_else: final_else_branch,
|
||||||
),
|
indented_else,
|
||||||
|
},
|
||||||
));
|
));
|
||||||
|
|
||||||
return unwrap_suffixed_expression(arena, new_if, maybe_def_pat);
|
return unwrap_suffixed_expression(arena, new_if, maybe_def_pat);
|
||||||
|
@ -411,10 +423,11 @@ pub fn unwrap_suffixed_expression_if_then_else_help<'a>(
|
||||||
|
|
||||||
let new_if = arena.alloc(Loc::at(
|
let new_if = arena.alloc(Loc::at(
|
||||||
loc_expr.region,
|
loc_expr.region,
|
||||||
Expr::If(
|
Expr::If {
|
||||||
arena.alloc_slice_copy(new_if_thens.as_slice()),
|
if_thens: arena.alloc_slice_copy(new_if_thens.as_slice()),
|
||||||
final_else_branch,
|
final_else: final_else_branch,
|
||||||
),
|
indented_else,
|
||||||
|
},
|
||||||
));
|
));
|
||||||
|
|
||||||
return unwrap_suffixed_expression(arena, new_if, maybe_def_pat);
|
return unwrap_suffixed_expression(arena, new_if, maybe_def_pat);
|
||||||
|
@ -439,10 +452,11 @@ pub fn unwrap_suffixed_expression_if_then_else_help<'a>(
|
||||||
|
|
||||||
let new_if = arena.alloc(Loc::at(
|
let new_if = arena.alloc(Loc::at(
|
||||||
loc_expr.region,
|
loc_expr.region,
|
||||||
Expr::If(
|
Expr::If {
|
||||||
arena.alloc_slice_copy(new_if_thens.as_slice()),
|
if_thens: arena.alloc_slice_copy(new_if_thens.as_slice()),
|
||||||
final_else_branch,
|
final_else: final_else_branch,
|
||||||
),
|
indented_else,
|
||||||
|
},
|
||||||
));
|
));
|
||||||
|
|
||||||
return unwrap_suffixed_expression(arena, new_if, maybe_def_pat);
|
return unwrap_suffixed_expression(arena, new_if, maybe_def_pat);
|
||||||
|
@ -465,10 +479,11 @@ pub fn unwrap_suffixed_expression_if_then_else_help<'a>(
|
||||||
|
|
||||||
let new_if = arena.alloc(Loc::at(
|
let new_if = arena.alloc(Loc::at(
|
||||||
loc_expr.region,
|
loc_expr.region,
|
||||||
Expr::If(
|
Expr::If {
|
||||||
arena.alloc_slice_copy(new_if_thens.as_slice()),
|
if_thens: arena.alloc_slice_copy(new_if_thens.as_slice()),
|
||||||
final_else_branch,
|
final_else: final_else_branch,
|
||||||
),
|
indented_else,
|
||||||
|
},
|
||||||
));
|
));
|
||||||
|
|
||||||
let unwrapped_if_then = apply_try_function(
|
let unwrapped_if_then = apply_try_function(
|
||||||
|
@ -494,10 +509,11 @@ pub fn unwrap_suffixed_expression_if_then_else_help<'a>(
|
||||||
|
|
||||||
let after_if = arena.alloc(Loc::at(
|
let after_if = arena.alloc(Loc::at(
|
||||||
loc_expr.region,
|
loc_expr.region,
|
||||||
Expr::If(
|
Expr::If {
|
||||||
arena.alloc_slice_copy(after_if_thens.as_slice()),
|
if_thens: arena.alloc_slice_copy(after_if_thens.as_slice()),
|
||||||
final_else_branch,
|
final_else: final_else_branch,
|
||||||
),
|
indented_else,
|
||||||
|
},
|
||||||
));
|
));
|
||||||
|
|
||||||
let after_if_then = apply_try_function(
|
let after_if_then = apply_try_function(
|
||||||
|
@ -512,7 +528,11 @@ pub fn unwrap_suffixed_expression_if_then_else_help<'a>(
|
||||||
|
|
||||||
let before_if_then = arena.alloc(Loc::at(
|
let before_if_then = arena.alloc(Loc::at(
|
||||||
loc_expr.region,
|
loc_expr.region,
|
||||||
Expr::If(before, after_if_then),
|
Expr::If {
|
||||||
|
if_thens: before,
|
||||||
|
final_else: after_if_then,
|
||||||
|
indented_else: false,
|
||||||
|
},
|
||||||
));
|
));
|
||||||
|
|
||||||
return unwrap_suffixed_expression(
|
return unwrap_suffixed_expression(
|
||||||
|
@ -532,7 +552,11 @@ pub fn unwrap_suffixed_expression_if_then_else_help<'a>(
|
||||||
Ok(unwrapped_final_else) => {
|
Ok(unwrapped_final_else) => {
|
||||||
return Ok(arena.alloc(Loc::at(
|
return Ok(arena.alloc(Loc::at(
|
||||||
loc_expr.region,
|
loc_expr.region,
|
||||||
Expr::If(if_thens, unwrapped_final_else),
|
Expr::If {
|
||||||
|
if_thens,
|
||||||
|
final_else: unwrapped_final_else,
|
||||||
|
indented_else,
|
||||||
|
},
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
Err(EUnwrapped::UnwrappedDefExpr { .. }) => {
|
Err(EUnwrapped::UnwrappedDefExpr { .. }) => {
|
||||||
|
@ -556,7 +580,11 @@ pub fn unwrap_suffixed_expression_if_then_else_help<'a>(
|
||||||
|
|
||||||
let new_if = arena.alloc(Loc::at(
|
let new_if = arena.alloc(Loc::at(
|
||||||
loc_expr.region,
|
loc_expr.region,
|
||||||
Expr::If(if_thens, unwrapped_final_else),
|
Expr::If {
|
||||||
|
if_thens,
|
||||||
|
final_else: unwrapped_final_else,
|
||||||
|
indented_else,
|
||||||
|
},
|
||||||
));
|
));
|
||||||
|
|
||||||
return unwrap_suffixed_expression(arena, new_if, maybe_def_pat);
|
return unwrap_suffixed_expression(arena, new_if, maybe_def_pat);
|
||||||
|
|
|
@ -46,6 +46,24 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
|
||||||
let var = var_store.fresh();
|
let var = var_store.fresh();
|
||||||
let qualified_module_ids = PackageModuleIds::default();
|
let qualified_module_ids = PackageModuleIds::default();
|
||||||
|
|
||||||
|
let mut scope = Scope::new(
|
||||||
|
home,
|
||||||
|
"TestPath".into(),
|
||||||
|
IdentIds::default(),
|
||||||
|
Default::default(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let dep_idents = IdentIds::exposed_builtins(0);
|
||||||
|
let mut env = Env::new(
|
||||||
|
arena,
|
||||||
|
expr_str,
|
||||||
|
home,
|
||||||
|
Path::new("Test.roc"),
|
||||||
|
&dep_idents,
|
||||||
|
&qualified_module_ids,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
// Desugar operators (convert them to Apply calls, taking into account
|
// Desugar operators (convert them to Apply calls, taking into account
|
||||||
// operator precedence and associativity rules), before doing other canonicalization.
|
// operator precedence and associativity rules), before doing other canonicalization.
|
||||||
//
|
//
|
||||||
|
@ -53,22 +71,8 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
|
||||||
// visited a BinOp node we'd recursively try to apply this to each of its nested
|
// visited a BinOp node we'd recursively try to apply this to each of its nested
|
||||||
// operators, and then again on *their* nested operators, ultimately applying the
|
// operators, and then again on *their* nested operators, ultimately applying the
|
||||||
// rules multiple times unnecessarily.
|
// rules multiple times unnecessarily.
|
||||||
let loc_expr = desugar::desugar_expr(
|
let loc_expr = desugar::desugar_expr(&mut env, &mut scope, &loc_expr);
|
||||||
arena,
|
|
||||||
&mut var_store,
|
|
||||||
&loc_expr,
|
|
||||||
expr_str,
|
|
||||||
&mut None,
|
|
||||||
arena.alloc("TestPath"),
|
|
||||||
&mut Default::default(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut scope = Scope::new(
|
|
||||||
home,
|
|
||||||
"TestPath".into(),
|
|
||||||
IdentIds::default(),
|
|
||||||
Default::default(),
|
|
||||||
);
|
|
||||||
scope.add_alias(
|
scope.add_alias(
|
||||||
Symbol::NUM_INT,
|
Symbol::NUM_INT,
|
||||||
Region::zero(),
|
Region::zero(),
|
||||||
|
@ -81,15 +85,6 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
|
||||||
roc_types::types::AliasKind::Structural,
|
roc_types::types::AliasKind::Structural,
|
||||||
);
|
);
|
||||||
|
|
||||||
let dep_idents = IdentIds::exposed_builtins(0);
|
|
||||||
let mut env = Env::new(
|
|
||||||
arena,
|
|
||||||
home,
|
|
||||||
Path::new("Test.roc"),
|
|
||||||
&dep_idents,
|
|
||||||
&qualified_module_ids,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
let (loc_expr, output) = canonicalize_expr(
|
let (loc_expr, output) = canonicalize_expr(
|
||||||
&mut env,
|
&mut env,
|
||||||
&mut var_store,
|
&mut var_store,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
source: crates/compiler/can/tests/test_suffixed.rs
|
source: crates/compiler/can/tests/test_suffixed.rs
|
||||||
assertion_line: 449
|
assertion_line: 463
|
||||||
expression: snapshot
|
expression: snapshot
|
||||||
---
|
---
|
||||||
Defs {
|
Defs {
|
||||||
|
@ -44,7 +44,7 @@ Defs {
|
||||||
value_defs: [
|
value_defs: [
|
||||||
Body(
|
Body(
|
||||||
@15-26 Identifier {
|
@15-26 Identifier {
|
||||||
ident: "64",
|
ident: "1",
|
||||||
},
|
},
|
||||||
@15-26 ParensAround(
|
@15-26 ParensAround(
|
||||||
Defs(
|
Defs(
|
||||||
|
@ -66,7 +66,7 @@ Defs {
|
||||||
value_defs: [
|
value_defs: [
|
||||||
Body(
|
Body(
|
||||||
@20-25 Identifier {
|
@20-25 Identifier {
|
||||||
ident: "63",
|
ident: "0",
|
||||||
},
|
},
|
||||||
@20-25 Apply(
|
@20-25 Apply(
|
||||||
@22-23 Var {
|
@22-23 Var {
|
||||||
|
@ -101,14 +101,14 @@ Defs {
|
||||||
[
|
[
|
||||||
@20-25 Var {
|
@20-25 Var {
|
||||||
module_name: "",
|
module_name: "",
|
||||||
ident: "63",
|
ident: "0",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
Space,
|
Space,
|
||||||
),
|
),
|
||||||
@20-25 Var {
|
@20-25 Var {
|
||||||
module_name: "",
|
module_name: "",
|
||||||
ident: "63",
|
ident: "0",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -129,14 +129,14 @@ Defs {
|
||||||
[
|
[
|
||||||
@15-26 Var {
|
@15-26 Var {
|
||||||
module_name: "",
|
module_name: "",
|
||||||
ident: "64",
|
ident: "1",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
Space,
|
Space,
|
||||||
),
|
),
|
||||||
@15-26 Var {
|
@15-26 Var {
|
||||||
module_name: "",
|
module_name: "",
|
||||||
ident: "64",
|
ident: "1",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -63,8 +63,8 @@ Defs {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@66-130 If(
|
@66-130 If {
|
||||||
[
|
if_thens: [
|
||||||
(
|
(
|
||||||
@69-70 Var {
|
@69-70 Var {
|
||||||
module_name: "",
|
module_name: "",
|
||||||
|
@ -76,11 +76,12 @@ Defs {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@128-130 Var {
|
final_else: @128-130 Var {
|
||||||
module_name: "",
|
module_name: "",
|
||||||
ident: "c",
|
ident: "c",
|
||||||
},
|
},
|
||||||
),
|
indented_else: false,
|
||||||
|
},
|
||||||
),
|
),
|
||||||
guard: None,
|
guard: None,
|
||||||
},
|
},
|
||||||
|
|
|
@ -136,8 +136,8 @@ Defs {
|
||||||
ident: "#!1_arg",
|
ident: "#!1_arg",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@109-298 If(
|
@109-298 If {
|
||||||
[
|
if_thens: [
|
||||||
(
|
(
|
||||||
@112-122 Apply(
|
@112-122 Apply(
|
||||||
@112-113 Var {
|
@112-113 Var {
|
||||||
|
@ -244,7 +244,7 @@ Defs {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
Apply(
|
final_else: Apply(
|
||||||
Var {
|
Var {
|
||||||
module_name: "Task",
|
module_name: "Task",
|
||||||
ident: "await",
|
ident: "await",
|
||||||
|
@ -269,8 +269,8 @@ Defs {
|
||||||
ident: "#!3_arg",
|
ident: "#!3_arg",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@109-298 If(
|
@109-298 If {
|
||||||
[
|
if_thens: [
|
||||||
(
|
(
|
||||||
@187-209 ParensAround(
|
@187-209 ParensAround(
|
||||||
Var {
|
Var {
|
||||||
|
@ -366,7 +366,7 @@ Defs {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@283-298 Apply(
|
final_else: @283-298 Apply(
|
||||||
@283-298 Var {
|
@283-298 Var {
|
||||||
module_name: "",
|
module_name: "",
|
||||||
ident: "line",
|
ident: "line",
|
||||||
|
@ -380,12 +380,14 @@ Defs {
|
||||||
],
|
],
|
||||||
Space,
|
Space,
|
||||||
),
|
),
|
||||||
),
|
indented_else: false,
|
||||||
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
BangSuffix,
|
BangSuffix,
|
||||||
),
|
),
|
||||||
),
|
indented_else: false,
|
||||||
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
BangSuffix,
|
BangSuffix,
|
||||||
|
|
|
@ -101,8 +101,8 @@ Defs {
|
||||||
ident: "#!0_arg",
|
ident: "#!0_arg",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@76-189 If(
|
@76-189 If {
|
||||||
[
|
if_thens: [
|
||||||
(
|
(
|
||||||
@79-87 Var {
|
@79-87 Var {
|
||||||
module_name: "",
|
module_name: "",
|
||||||
|
@ -124,7 +124,7 @@ Defs {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@125-132 Apply(
|
final_else: @125-132 Apply(
|
||||||
@125-132 Var {
|
@125-132 Var {
|
||||||
module_name: "Task",
|
module_name: "Task",
|
||||||
ident: "await",
|
ident: "await",
|
||||||
|
@ -140,8 +140,8 @@ Defs {
|
||||||
ident: "#!1_arg",
|
ident: "#!1_arg",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@76-189 If(
|
@76-189 If {
|
||||||
[
|
if_thens: [
|
||||||
(
|
(
|
||||||
@125-132 Var {
|
@125-132 Var {
|
||||||
module_name: "",
|
module_name: "",
|
||||||
|
@ -163,7 +163,7 @@ Defs {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@178-189 Apply(
|
final_else: @178-189 Apply(
|
||||||
@178-182 Var {
|
@178-182 Var {
|
||||||
module_name: "",
|
module_name: "",
|
||||||
ident: "line",
|
ident: "line",
|
||||||
|
@ -177,12 +177,14 @@ Defs {
|
||||||
],
|
],
|
||||||
Space,
|
Space,
|
||||||
),
|
),
|
||||||
),
|
indented_else: false,
|
||||||
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
BangSuffix,
|
BangSuffix,
|
||||||
),
|
),
|
||||||
),
|
indented_else: false,
|
||||||
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
BangSuffix,
|
BangSuffix,
|
||||||
|
|
|
@ -0,0 +1,289 @@
|
||||||
|
---
|
||||||
|
source: crates/compiler/can/tests/test_suffixed.rs
|
||||||
|
expression: snapshot
|
||||||
|
---
|
||||||
|
Defs {
|
||||||
|
tags: [
|
||||||
|
Index(2147483648),
|
||||||
|
Index(2147483649),
|
||||||
|
Index(2147483650),
|
||||||
|
],
|
||||||
|
regions: [
|
||||||
|
@0-80,
|
||||||
|
@82-227,
|
||||||
|
@229-266,
|
||||||
|
],
|
||||||
|
space_before: [
|
||||||
|
Slice(start = 0, length = 0),
|
||||||
|
Slice(start = 0, length = 2),
|
||||||
|
Slice(start = 2, length = 2),
|
||||||
|
],
|
||||||
|
space_after: [
|
||||||
|
Slice(start = 0, length = 0),
|
||||||
|
Slice(start = 2, length = 0),
|
||||||
|
Slice(start = 4, length = 1),
|
||||||
|
],
|
||||||
|
spaces: [
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
type_defs: [],
|
||||||
|
value_defs: [
|
||||||
|
Body(
|
||||||
|
@0-3 Identifier {
|
||||||
|
ident: "inc",
|
||||||
|
},
|
||||||
|
@6-80 Closure(
|
||||||
|
[
|
||||||
|
@7-8 Identifier {
|
||||||
|
ident: "i",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
@16-80 If {
|
||||||
|
if_thens: [
|
||||||
|
(
|
||||||
|
@19-24 Apply(
|
||||||
|
@21-22 Var {
|
||||||
|
module_name: "Num",
|
||||||
|
ident: "isGt",
|
||||||
|
},
|
||||||
|
[
|
||||||
|
@19-20 Var {
|
||||||
|
module_name: "",
|
||||||
|
ident: "i",
|
||||||
|
},
|
||||||
|
@23-24 Num(
|
||||||
|
"2",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
BinOp(
|
||||||
|
GreaterThan,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
@38-52 Apply(
|
||||||
|
@38-41 Tag(
|
||||||
|
"Err",
|
||||||
|
),
|
||||||
|
[
|
||||||
|
@42-52 Tag(
|
||||||
|
"MaxReached",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
Space,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
final_else: @70-80 Apply(
|
||||||
|
@70-72 Tag(
|
||||||
|
"Ok",
|
||||||
|
),
|
||||||
|
[
|
||||||
|
@74-79 ParensAround(
|
||||||
|
Apply(
|
||||||
|
@76-77 Var {
|
||||||
|
module_name: "Num",
|
||||||
|
ident: "add",
|
||||||
|
},
|
||||||
|
[
|
||||||
|
@74-75 Var {
|
||||||
|
module_name: "",
|
||||||
|
ident: "i",
|
||||||
|
},
|
||||||
|
@78-79 Num(
|
||||||
|
"1",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
BinOp(
|
||||||
|
Plus,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
Space,
|
||||||
|
),
|
||||||
|
indented_else: false,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expect {
|
||||||
|
condition: @93-227 Defs(
|
||||||
|
Defs {
|
||||||
|
tags: [
|
||||||
|
Index(2147483648),
|
||||||
|
Index(2147483649),
|
||||||
|
],
|
||||||
|
regions: [
|
||||||
|
@99-189,
|
||||||
|
@203-208,
|
||||||
|
],
|
||||||
|
space_before: [
|
||||||
|
Slice(start = 0, length = 0),
|
||||||
|
Slice(start = 0, length = 1),
|
||||||
|
],
|
||||||
|
space_after: [
|
||||||
|
Slice(start = 0, length = 0),
|
||||||
|
Slice(start = 1, length = 0),
|
||||||
|
],
|
||||||
|
spaces: [
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
type_defs: [],
|
||||||
|
value_defs: [
|
||||||
|
Body(
|
||||||
|
@93-96 Identifier {
|
||||||
|
ident: "run",
|
||||||
|
},
|
||||||
|
@99-189 Closure(
|
||||||
|
[
|
||||||
|
@100-101 Identifier {
|
||||||
|
ident: "i",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
@132-172 Apply(
|
||||||
|
@132-172 Var {
|
||||||
|
module_name: "Result",
|
||||||
|
ident: "try",
|
||||||
|
},
|
||||||
|
[
|
||||||
|
@132-152 Apply(
|
||||||
|
@132-152 Var {
|
||||||
|
module_name: "",
|
||||||
|
ident: "inc",
|
||||||
|
},
|
||||||
|
[
|
||||||
|
@132-133 Var {
|
||||||
|
module_name: "",
|
||||||
|
ident: "i",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
BinOp(
|
||||||
|
Pizza,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
@132-172 Closure(
|
||||||
|
[
|
||||||
|
@132-152 Identifier {
|
||||||
|
ident: "#!0_arg",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
@132-172 Apply(
|
||||||
|
@132-172 Var {
|
||||||
|
module_name: "Result",
|
||||||
|
ident: "try",
|
||||||
|
},
|
||||||
|
[
|
||||||
|
@132-172 Apply(
|
||||||
|
@132-172 Var {
|
||||||
|
module_name: "",
|
||||||
|
ident: "inc",
|
||||||
|
},
|
||||||
|
[
|
||||||
|
@132-152 Var {
|
||||||
|
module_name: "",
|
||||||
|
ident: "#!0_arg",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
BinOp(
|
||||||
|
Pizza,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
@132-172 Closure(
|
||||||
|
[
|
||||||
|
@113-117 Identifier {
|
||||||
|
ident: "newi",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
@182-189 Apply(
|
||||||
|
@182-184 Tag(
|
||||||
|
"Ok",
|
||||||
|
),
|
||||||
|
[
|
||||||
|
@185-189 Var {
|
||||||
|
module_name: "",
|
||||||
|
ident: "newi",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
Space,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
QuestionSuffix,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
QuestionSuffix,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Body(
|
||||||
|
@194-200 Identifier {
|
||||||
|
ident: "result",
|
||||||
|
},
|
||||||
|
@203-208 Apply(
|
||||||
|
@203-206 Var {
|
||||||
|
module_name: "",
|
||||||
|
ident: "run",
|
||||||
|
},
|
||||||
|
[
|
||||||
|
@207-208 Num(
|
||||||
|
"0",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
Space,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
@213-227 Apply(
|
||||||
|
@220-222 Var {
|
||||||
|
module_name: "Bool",
|
||||||
|
ident: "isEq",
|
||||||
|
},
|
||||||
|
[
|
||||||
|
@213-219 Var {
|
||||||
|
module_name: "",
|
||||||
|
ident: "result",
|
||||||
|
},
|
||||||
|
@223-227 Apply(
|
||||||
|
@223-225 Tag(
|
||||||
|
"Ok",
|
||||||
|
),
|
||||||
|
[
|
||||||
|
@226-227 Num(
|
||||||
|
"2",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
Space,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
BinOp(
|
||||||
|
Equals,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
preceding_comment: @82-82,
|
||||||
|
},
|
||||||
|
Body(
|
||||||
|
@229-233 Identifier {
|
||||||
|
ident: "main",
|
||||||
|
},
|
||||||
|
@240-266 Apply(
|
||||||
|
@240-266 Var {
|
||||||
|
module_name: "Stdout",
|
||||||
|
ident: "line",
|
||||||
|
},
|
||||||
|
[
|
||||||
|
@253-266 Str(
|
||||||
|
PlainLine(
|
||||||
|
"Hello world",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
Space,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
---
|
||||||
|
source: crates/compiler/can/tests/test_suffixed.rs
|
||||||
|
expression: snapshot
|
||||||
|
---
|
||||||
|
Defs {
|
||||||
|
tags: [
|
||||||
|
Index(2147483648),
|
||||||
|
Index(2147483649),
|
||||||
|
],
|
||||||
|
regions: [
|
||||||
|
@0-33,
|
||||||
|
@35-45,
|
||||||
|
],
|
||||||
|
space_before: [
|
||||||
|
Slice(start = 0, length = 0),
|
||||||
|
Slice(start = 0, length = 2),
|
||||||
|
],
|
||||||
|
space_after: [
|
||||||
|
Slice(start = 0, length = 0),
|
||||||
|
Slice(start = 2, length = 1),
|
||||||
|
],
|
||||||
|
spaces: [
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
type_defs: [],
|
||||||
|
value_defs: [
|
||||||
|
AnnotatedBody {
|
||||||
|
ann_pattern: @0-3 Identifier {
|
||||||
|
ident: "run",
|
||||||
|
},
|
||||||
|
ann_type: @6-15 Apply(
|
||||||
|
"",
|
||||||
|
"Task",
|
||||||
|
[
|
||||||
|
@11-13 Record {
|
||||||
|
fields: [],
|
||||||
|
ext: None,
|
||||||
|
},
|
||||||
|
@14-15 Inferred,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
lines_between: [
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
body_pattern: @16-19 Identifier {
|
||||||
|
ident: "run",
|
||||||
|
},
|
||||||
|
body_expr: @22-33 Apply(
|
||||||
|
@22-33 Var {
|
||||||
|
module_name: "",
|
||||||
|
ident: "line",
|
||||||
|
},
|
||||||
|
[
|
||||||
|
@28-33 Str(
|
||||||
|
PlainLine(
|
||||||
|
"foo",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
Space,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
Body(
|
||||||
|
@35-39 Identifier {
|
||||||
|
ident: "main",
|
||||||
|
},
|
||||||
|
@42-45 Var {
|
||||||
|
module_name: "",
|
||||||
|
ident: "run",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
source: crates/compiler/can/tests/test_suffixed.rs
|
source: crates/compiler/can/tests/test_suffixed.rs
|
||||||
assertion_line: 459
|
assertion_line: 473
|
||||||
expression: snapshot
|
expression: snapshot
|
||||||
---
|
---
|
||||||
Defs {
|
Defs {
|
||||||
|
@ -8,7 +8,7 @@ Defs {
|
||||||
Index(2147483648),
|
Index(2147483648),
|
||||||
],
|
],
|
||||||
regions: [
|
regions: [
|
||||||
@0-19,
|
@0-51,
|
||||||
],
|
],
|
||||||
space_before: [
|
space_before: [
|
||||||
Slice(start = 0, length = 0),
|
Slice(start = 0, length = 0),
|
||||||
|
@ -25,13 +25,13 @@ Defs {
|
||||||
@0-4 Identifier {
|
@0-4 Identifier {
|
||||||
ident: "main",
|
ident: "main",
|
||||||
},
|
},
|
||||||
@11-19 Defs(
|
@11-51 Defs(
|
||||||
Defs {
|
Defs {
|
||||||
tags: [
|
tags: [
|
||||||
Index(2147483648),
|
Index(2147483648),
|
||||||
],
|
],
|
||||||
regions: [
|
regions: [
|
||||||
@11-12,
|
@11-40,
|
||||||
],
|
],
|
||||||
space_before: [
|
space_before: [
|
||||||
Slice(start = 0, length = 0),
|
Slice(start = 0, length = 0),
|
||||||
|
@ -43,36 +43,98 @@ Defs {
|
||||||
type_defs: [],
|
type_defs: [],
|
||||||
value_defs: [
|
value_defs: [
|
||||||
Body(
|
Body(
|
||||||
@11-12 Identifier {
|
@11-40 Identifier {
|
||||||
ident: "63",
|
ident: "1",
|
||||||
},
|
},
|
||||||
@11-12 Num(
|
@11-40 Apply(
|
||||||
"1",
|
@31-38 Var {
|
||||||
|
module_name: "Num",
|
||||||
|
ident: "add",
|
||||||
|
},
|
||||||
|
[
|
||||||
|
@11-23 Defs(
|
||||||
|
Defs {
|
||||||
|
tags: [
|
||||||
|
Index(2147483648),
|
||||||
|
],
|
||||||
|
regions: [
|
||||||
|
@11-12,
|
||||||
|
],
|
||||||
|
space_before: [
|
||||||
|
Slice(start = 0, length = 0),
|
||||||
|
],
|
||||||
|
space_after: [
|
||||||
|
Slice(start = 0, length = 0),
|
||||||
|
],
|
||||||
|
spaces: [],
|
||||||
|
type_defs: [],
|
||||||
|
value_defs: [
|
||||||
|
Body(
|
||||||
|
@11-12 Identifier {
|
||||||
|
ident: "0",
|
||||||
|
},
|
||||||
|
@11-12 Num(
|
||||||
|
"1",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
@11-23 LowLevelDbg(
|
||||||
|
(
|
||||||
|
"test.roc:2",
|
||||||
|
" ",
|
||||||
|
),
|
||||||
|
@11-12 Apply(
|
||||||
|
@11-12 Var {
|
||||||
|
module_name: "Inspect",
|
||||||
|
ident: "toStr",
|
||||||
|
},
|
||||||
|
[
|
||||||
|
@11-12 Var {
|
||||||
|
module_name: "",
|
||||||
|
ident: "0",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
Space,
|
||||||
|
),
|
||||||
|
@11-12 Var {
|
||||||
|
module_name: "",
|
||||||
|
ident: "0",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
@39-40 Num(
|
||||||
|
"2",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
BinOp(
|
||||||
|
Pizza,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@11-19 LowLevelDbg(
|
@11-51 LowLevelDbg(
|
||||||
(
|
(
|
||||||
"test.roc:2",
|
"test.roc:2",
|
||||||
" ",
|
" main =\n 1\n ",
|
||||||
),
|
),
|
||||||
@11-12 Apply(
|
@11-40 Apply(
|
||||||
@11-12 Var {
|
@11-40 Var {
|
||||||
module_name: "Inspect",
|
module_name: "Inspect",
|
||||||
ident: "toStr",
|
ident: "toStr",
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
@11-12 Var {
|
@11-40 Var {
|
||||||
module_name: "",
|
module_name: "",
|
||||||
ident: "63",
|
ident: "1",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
Space,
|
Space,
|
||||||
),
|
),
|
||||||
@11-12 Var {
|
@11-40 Var {
|
||||||
module_name: "",
|
module_name: "",
|
||||||
ident: "63",
|
ident: "1",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -19,7 +19,6 @@ mod test_can {
|
||||||
use roc_can::expr::{ClosureData, IntValue, Recursive};
|
use roc_can::expr::{ClosureData, IntValue, Recursive};
|
||||||
use roc_can::pattern::Pattern;
|
use roc_can::pattern::Pattern;
|
||||||
use roc_module::called_via::CalledVia;
|
use roc_module::called_via::CalledVia;
|
||||||
use roc_module::symbol::Symbol;
|
|
||||||
use roc_problem::can::{CycleEntry, FloatErrorKind, IntErrorKind, Problem, RuntimeError};
|
use roc_problem::can::{CycleEntry, FloatErrorKind, IntErrorKind, Problem, RuntimeError};
|
||||||
use roc_region::all::{Loc, Position, Region};
|
use roc_region::all::{Loc, Position, Region};
|
||||||
use roc_types::subs::Variable;
|
use roc_types::subs::Variable;
|
||||||
|
@ -653,101 +652,6 @@ mod test_can {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RECORD BUILDERS
|
// RECORD BUILDERS
|
||||||
#[test]
|
|
||||||
fn old_record_builder_desugar() {
|
|
||||||
let src = indoc!(
|
|
||||||
r#"
|
|
||||||
succeed = \_ -> crash "succeed"
|
|
||||||
apply = \_ -> crash "get"
|
|
||||||
|
|
||||||
d = 3
|
|
||||||
|
|
||||||
succeed {
|
|
||||||
a: 1,
|
|
||||||
b: <- apply "b",
|
|
||||||
c: <- apply "c",
|
|
||||||
d
|
|
||||||
}
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
let arena = Bump::new();
|
|
||||||
let out = can_expr_with(&arena, test_home(), src);
|
|
||||||
|
|
||||||
assert_eq!(out.problems.len(), 0);
|
|
||||||
|
|
||||||
// Assert that we desugar to:
|
|
||||||
//
|
|
||||||
// (apply "c") ((apply "b") (succeed \b -> \c -> { a: 1, b, c, d }))
|
|
||||||
|
|
||||||
// (apply "c") ..
|
|
||||||
let (apply_c, c_to_b) = simplify_curried_call(&out.loc_expr.value);
|
|
||||||
assert_apply_call(apply_c, "c", &out.interns);
|
|
||||||
|
|
||||||
// (apply "b") ..
|
|
||||||
let (apply_b, b_to_succeed) = simplify_curried_call(c_to_b);
|
|
||||||
assert_apply_call(apply_b, "b", &out.interns);
|
|
||||||
|
|
||||||
// (succeed ..)
|
|
||||||
let (succeed, b_closure) = simplify_curried_call(b_to_succeed);
|
|
||||||
|
|
||||||
match succeed {
|
|
||||||
Var(sym, _) => assert_eq!(sym.as_str(&out.interns), "succeed"),
|
|
||||||
_ => panic!("Not calling succeed: {:?}", succeed),
|
|
||||||
}
|
|
||||||
|
|
||||||
// \b -> ..
|
|
||||||
let (b_sym, c_closure) = simplify_builder_closure(b_closure);
|
|
||||||
|
|
||||||
// \c -> ..
|
|
||||||
let (c_sym, c_body) = simplify_builder_closure(c_closure);
|
|
||||||
|
|
||||||
// { a: 1, b, c, d }
|
|
||||||
match c_body {
|
|
||||||
Record { fields, .. } => {
|
|
||||||
match get_field_expr(fields, "a") {
|
|
||||||
Num(_, num_str, _, _) => {
|
|
||||||
assert_eq!(num_str.to_string(), "1");
|
|
||||||
}
|
|
||||||
expr => panic!("a is not a Num: {:?}", expr),
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(get_field_var_sym(fields, "b"), b_sym);
|
|
||||||
assert_eq!(get_field_var_sym(fields, "c"), c_sym);
|
|
||||||
assert_eq!(get_field_var_sym(fields, "d").as_str(&out.interns), "d");
|
|
||||||
}
|
|
||||||
_ => panic!("Closure body wasn't a Record: {:?}", c_body),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn simplify_curried_call(expr: &Expr) -> (&Expr, &Expr) {
|
|
||||||
match expr {
|
|
||||||
LetNonRec(_, loc_expr) => simplify_curried_call(&loc_expr.value),
|
|
||||||
Call(fun, args, _) => (&fun.1.value, &args[0].1.value),
|
|
||||||
_ => panic!("Final Expr is not a Call: {:?}", expr),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_apply_call(expr: &Expr, expected: &str, interns: &roc_module::symbol::Interns) {
|
|
||||||
match simplify_curried_call(expr) {
|
|
||||||
(Var(sym, _), Str(val)) => {
|
|
||||||
assert_eq!(sym.as_str(interns), "apply");
|
|
||||||
assert_eq!(val.to_string(), expected);
|
|
||||||
}
|
|
||||||
call => panic!("Not a valid (get {}) call: {:?}", expected, call),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn simplify_builder_closure(expr: &Expr) -> (Symbol, &Expr) {
|
|
||||||
use roc_can::pattern::Pattern::*;
|
|
||||||
|
|
||||||
match expr {
|
|
||||||
Closure(closure) => match &closure.arguments[0].2.value {
|
|
||||||
Identifier(sym) => (*sym, &closure.loc_body.value),
|
|
||||||
pattern => panic!("Not an identifier pattern: {:?}", pattern),
|
|
||||||
},
|
|
||||||
_ => panic!("Not a closure: {:?}", expr),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_field_expr<'a>(
|
fn get_field_expr<'a>(
|
||||||
fields: &'a roc_collections::SendMap<roc_module::ident::Lowercase, roc_can::expr::Field>,
|
fields: &'a roc_collections::SendMap<roc_module::ident::Lowercase, roc_can::expr::Field>,
|
||||||
|
@ -769,97 +673,7 @@ mod test_can {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn old_record_builder_field_names_do_not_shadow() {
|
fn record_builder_desugar() {
|
||||||
let src = indoc!(
|
|
||||||
r#"
|
|
||||||
succeed = \_ -> crash "succeed"
|
|
||||||
parse = \_ -> crash "parse"
|
|
||||||
|
|
||||||
number = "42"
|
|
||||||
|
|
||||||
succeed {
|
|
||||||
number: <- parse number,
|
|
||||||
raw: number,
|
|
||||||
}
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
let arena = Bump::new();
|
|
||||||
let out = can_expr_with(&arena, test_home(), src);
|
|
||||||
|
|
||||||
assert_eq!(out.problems.len(), 0);
|
|
||||||
|
|
||||||
let (_, number_to_succeed) = simplify_curried_call(&out.loc_expr.value);
|
|
||||||
let (_, number_closure) = simplify_curried_call(number_to_succeed);
|
|
||||||
let (apply_number_sym, record) = simplify_builder_closure(number_closure);
|
|
||||||
|
|
||||||
match record {
|
|
||||||
Record { fields, .. } => {
|
|
||||||
assert_eq!(get_field_var_sym(fields, "number"), apply_number_sym);
|
|
||||||
|
|
||||||
match get_field_expr(fields, "raw") {
|
|
||||||
Var(number_sym, _) => {
|
|
||||||
assert_ne!(number_sym.ident_id(), apply_number_sym.ident_id());
|
|
||||||
assert_eq!(number_sym.as_str(&out.interns), "number")
|
|
||||||
}
|
|
||||||
expr => panic!("a is not a Num: {:?}", expr),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => panic!("Closure body wasn't a Record: {:?}", record),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn multiple_old_record_builders_error() {
|
|
||||||
let src = indoc!(
|
|
||||||
r#"
|
|
||||||
succeed
|
|
||||||
{ a: <- apply "a" }
|
|
||||||
{ b: <- apply "b" }
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
let arena = Bump::new();
|
|
||||||
let CanExprOut {
|
|
||||||
problems, loc_expr, ..
|
|
||||||
} = can_expr_with(&arena, test_home(), src);
|
|
||||||
|
|
||||||
assert_eq!(problems.len(), 1);
|
|
||||||
assert!(problems.iter().all(|problem| matches!(
|
|
||||||
problem,
|
|
||||||
Problem::RuntimeError(roc_problem::can::RuntimeError::MultipleOldRecordBuilders { .. })
|
|
||||||
)));
|
|
||||||
|
|
||||||
assert!(matches!(
|
|
||||||
loc_expr.value,
|
|
||||||
Expr::RuntimeError(roc_problem::can::RuntimeError::MultipleOldRecordBuilders { .. })
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn hanging_old_record_builder() {
|
|
||||||
let src = indoc!(
|
|
||||||
r#"
|
|
||||||
{ a: <- apply "a" }
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
let arena = Bump::new();
|
|
||||||
let CanExprOut {
|
|
||||||
problems, loc_expr, ..
|
|
||||||
} = can_expr_with(&arena, test_home(), src);
|
|
||||||
|
|
||||||
assert_eq!(problems.len(), 1);
|
|
||||||
assert!(problems.iter().all(|problem| matches!(
|
|
||||||
problem,
|
|
||||||
Problem::RuntimeError(roc_problem::can::RuntimeError::UnappliedOldRecordBuilder { .. })
|
|
||||||
)));
|
|
||||||
|
|
||||||
assert!(matches!(
|
|
||||||
loc_expr.value,
|
|
||||||
Expr::RuntimeError(roc_problem::can::RuntimeError::UnappliedOldRecordBuilder { .. })
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn new_record_builder_desugar() {
|
|
||||||
let src = indoc!(
|
let src = indoc!(
|
||||||
r#"
|
r#"
|
||||||
map2 = \a, b, combine -> combine a b
|
map2 = \a, b, combine -> combine a b
|
||||||
|
|
|
@ -6,25 +6,39 @@ mod suffixed_tests {
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use insta::assert_snapshot;
|
use insta::assert_snapshot;
|
||||||
use roc_can::desugar::desugar_defs_node_values;
|
use roc_can::desugar::desugar_defs_node_values;
|
||||||
|
use roc_can::env::Env;
|
||||||
|
use roc_can::scope::Scope;
|
||||||
|
use roc_module::symbol::{IdentIds, ModuleIds, PackageModuleIds};
|
||||||
use roc_parse::test_helpers::parse_defs_with;
|
use roc_parse::test_helpers::parse_defs_with;
|
||||||
use roc_types::subs::VarStore;
|
use std::path::Path;
|
||||||
|
|
||||||
macro_rules! run_test {
|
macro_rules! run_test {
|
||||||
($src:expr) => {{
|
($src:expr) => {{
|
||||||
let arena = &Bump::new();
|
let arena = &Bump::new();
|
||||||
let mut var_store = VarStore::default();
|
let home = ModuleIds::default().get_or_insert(&"Test".into());
|
||||||
let mut defs = parse_defs_with(arena, indoc!($src)).unwrap();
|
|
||||||
desugar_defs_node_values(
|
let mut scope = Scope::new(
|
||||||
arena,
|
home,
|
||||||
&mut var_store,
|
"TestPath".into(),
|
||||||
&mut defs,
|
IdentIds::default(),
|
||||||
$src,
|
Default::default(),
|
||||||
&mut None,
|
|
||||||
"test.roc",
|
|
||||||
true,
|
|
||||||
&mut Default::default(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let dep_idents = IdentIds::exposed_builtins(0);
|
||||||
|
let qualified_module_ids = PackageModuleIds::default();
|
||||||
|
let mut env = Env::new(
|
||||||
|
arena,
|
||||||
|
$src,
|
||||||
|
home,
|
||||||
|
Path::new("test.roc"),
|
||||||
|
&dep_idents,
|
||||||
|
&qualified_module_ids,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut defs = parse_defs_with(arena, indoc!($src)).unwrap();
|
||||||
|
desugar_defs_node_values(&mut env, &mut scope, &mut defs, true);
|
||||||
|
|
||||||
let snapshot = format!("{:#?}", &defs);
|
let snapshot = format!("{:#?}", &defs);
|
||||||
println!("{}", snapshot);
|
println!("{}", snapshot);
|
||||||
assert_snapshot!(snapshot);
|
assert_snapshot!(snapshot);
|
||||||
|
@ -454,6 +468,19 @@ mod suffixed_tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pizza_dbg() {
|
||||||
|
run_test!(
|
||||||
|
r#"
|
||||||
|
main =
|
||||||
|
1
|
||||||
|
|> dbg
|
||||||
|
|> Num.add 2
|
||||||
|
|> dbg
|
||||||
|
"#
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn apply_argument_single() {
|
fn apply_argument_single() {
|
||||||
run_test!(
|
run_test!(
|
||||||
|
@ -579,6 +606,44 @@ mod suffixed_tests {
|
||||||
"##
|
"##
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn issue_7081() {
|
||||||
|
run_test!(
|
||||||
|
r##"
|
||||||
|
inc = \i ->
|
||||||
|
if i > 2 then
|
||||||
|
Err MaxReached
|
||||||
|
else
|
||||||
|
Ok (i + 1)
|
||||||
|
|
||||||
|
expect
|
||||||
|
run = \i ->
|
||||||
|
newi =
|
||||||
|
i
|
||||||
|
|> inc?
|
||||||
|
|> inc?
|
||||||
|
Ok newi
|
||||||
|
result = run 0
|
||||||
|
result == Ok 2
|
||||||
|
|
||||||
|
main =
|
||||||
|
Stdout.line! "Hello world"
|
||||||
|
"##
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn issue_7103() {
|
||||||
|
run_test!(
|
||||||
|
r##"
|
||||||
|
run : Task {} _
|
||||||
|
run = line! "foo"
|
||||||
|
|
||||||
|
main = run
|
||||||
|
"##
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
243
crates/compiler/checkmate/www/package-lock.json
generated
243
crates/compiler/checkmate/www/package-lock.json
generated
|
@ -5917,9 +5917,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/body-parser": {
|
"node_modules/body-parser": {
|
||||||
"version": "1.20.2",
|
"version": "1.20.3",
|
||||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
|
||||||
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
|
"integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bytes": "3.1.2",
|
"bytes": "3.1.2",
|
||||||
|
@ -5930,7 +5930,7 @@
|
||||||
"http-errors": "2.0.0",
|
"http-errors": "2.0.0",
|
||||||
"iconv-lite": "0.4.24",
|
"iconv-lite": "0.4.24",
|
||||||
"on-finished": "2.4.1",
|
"on-finished": "2.4.1",
|
||||||
"qs": "6.11.0",
|
"qs": "6.13.0",
|
||||||
"raw-body": "2.5.2",
|
"raw-body": "2.5.2",
|
||||||
"type-is": "~1.6.18",
|
"type-is": "~1.6.18",
|
||||||
"unpipe": "1.0.0"
|
"unpipe": "1.0.0"
|
||||||
|
@ -6091,13 +6091,19 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/call-bind": {
|
"node_modules/call-bind": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
|
||||||
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
|
"integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"function-bind": "^1.1.1",
|
"es-define-property": "^1.0.0",
|
||||||
"get-intrinsic": "^1.0.2"
|
"es-errors": "^1.3.0",
|
||||||
|
"function-bind": "^1.1.2",
|
||||||
|
"get-intrinsic": "^1.2.4",
|
||||||
|
"set-function-length": "^1.2.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
@ -7249,6 +7255,23 @@
|
||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/define-data-property": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"es-define-property": "^1.0.0",
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"gopd": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/define-lazy-prop": {
|
"node_modules/define-lazy-prop": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
|
||||||
|
@ -7597,9 +7620,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/encodeurl": {
|
"node_modules/encodeurl": {
|
||||||
"version": "1.0.2",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
|
||||||
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
|
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
|
@ -7704,6 +7727,27 @@
|
||||||
"integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==",
|
"integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/es-define-property": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"get-intrinsic": "^1.2.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/es-errors": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/es-module-lexer": {
|
"node_modules/es-module-lexer": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz",
|
||||||
|
@ -8646,37 +8690,37 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/express": {
|
"node_modules/express": {
|
||||||
"version": "4.19.2",
|
"version": "4.21.0",
|
||||||
"resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz",
|
||||||
"integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
|
"integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"accepts": "~1.3.8",
|
"accepts": "~1.3.8",
|
||||||
"array-flatten": "1.1.1",
|
"array-flatten": "1.1.1",
|
||||||
"body-parser": "1.20.2",
|
"body-parser": "1.20.3",
|
||||||
"content-disposition": "0.5.4",
|
"content-disposition": "0.5.4",
|
||||||
"content-type": "~1.0.4",
|
"content-type": "~1.0.4",
|
||||||
"cookie": "0.6.0",
|
"cookie": "0.6.0",
|
||||||
"cookie-signature": "1.0.6",
|
"cookie-signature": "1.0.6",
|
||||||
"debug": "2.6.9",
|
"debug": "2.6.9",
|
||||||
"depd": "2.0.0",
|
"depd": "2.0.0",
|
||||||
"encodeurl": "~1.0.2",
|
"encodeurl": "~2.0.0",
|
||||||
"escape-html": "~1.0.3",
|
"escape-html": "~1.0.3",
|
||||||
"etag": "~1.8.1",
|
"etag": "~1.8.1",
|
||||||
"finalhandler": "1.2.0",
|
"finalhandler": "1.3.1",
|
||||||
"fresh": "0.5.2",
|
"fresh": "0.5.2",
|
||||||
"http-errors": "2.0.0",
|
"http-errors": "2.0.0",
|
||||||
"merge-descriptors": "1.0.1",
|
"merge-descriptors": "1.0.3",
|
||||||
"methods": "~1.1.2",
|
"methods": "~1.1.2",
|
||||||
"on-finished": "2.4.1",
|
"on-finished": "2.4.1",
|
||||||
"parseurl": "~1.3.3",
|
"parseurl": "~1.3.3",
|
||||||
"path-to-regexp": "0.1.7",
|
"path-to-regexp": "0.1.10",
|
||||||
"proxy-addr": "~2.0.7",
|
"proxy-addr": "~2.0.7",
|
||||||
"qs": "6.11.0",
|
"qs": "6.13.0",
|
||||||
"range-parser": "~1.2.1",
|
"range-parser": "~1.2.1",
|
||||||
"safe-buffer": "5.2.1",
|
"safe-buffer": "5.2.1",
|
||||||
"send": "0.18.0",
|
"send": "0.19.0",
|
||||||
"serve-static": "1.15.0",
|
"serve-static": "1.16.2",
|
||||||
"setprototypeof": "1.2.0",
|
"setprototypeof": "1.2.0",
|
||||||
"statuses": "2.0.1",
|
"statuses": "2.0.1",
|
||||||
"type-is": "~1.6.18",
|
"type-is": "~1.6.18",
|
||||||
|
@ -8883,13 +8927,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/finalhandler": {
|
"node_modules/finalhandler": {
|
||||||
"version": "1.2.0",
|
"version": "1.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
|
||||||
"integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
|
"integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": "2.6.9",
|
"debug": "2.6.9",
|
||||||
"encodeurl": "~1.0.2",
|
"encodeurl": "~2.0.0",
|
||||||
"escape-html": "~1.0.3",
|
"escape-html": "~1.0.3",
|
||||||
"on-finished": "2.4.1",
|
"on-finished": "2.4.1",
|
||||||
"parseurl": "~1.3.3",
|
"parseurl": "~1.3.3",
|
||||||
|
@ -9249,10 +9293,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/function-bind": {
|
"node_modules/function-bind": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
|
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/function.prototype.name": {
|
"node_modules/function.prototype.name": {
|
||||||
"version": "1.1.5",
|
"version": "1.1.5",
|
||||||
|
@ -9300,15 +9347,19 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/get-intrinsic": {
|
"node_modules/get-intrinsic": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
|
||||||
"integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==",
|
"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"function-bind": "^1.1.1",
|
"es-errors": "^1.3.0",
|
||||||
"has": "^1.0.3",
|
"function-bind": "^1.1.2",
|
||||||
"has-proto": "^1.0.1",
|
"has-proto": "^1.0.1",
|
||||||
"has-symbols": "^1.0.3"
|
"has-symbols": "^1.0.3",
|
||||||
|
"hasown": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
@ -9590,12 +9641,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/has-property-descriptors": {
|
"node_modules/has-property-descriptors": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
|
||||||
"integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
|
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"get-intrinsic": "^1.1.1"
|
"es-define-property": "^1.0.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
@ -9640,6 +9691,18 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/hasown": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"function-bind": "^1.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/he": {
|
"node_modules/he": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||||
|
@ -13153,10 +13216,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/merge-descriptors": {
|
"node_modules/merge-descriptors": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
|
||||||
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==",
|
"integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/merge-stream": {
|
"node_modules/merge-stream": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
|
@ -13538,10 +13604,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/object-inspect": {
|
"node_modules/object-inspect": {
|
||||||
"version": "1.12.3",
|
"version": "1.13.2",
|
||||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
|
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz",
|
||||||
"integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
|
"integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
|
@ -13889,9 +13958,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/path-to-regexp": {
|
"node_modules/path-to-regexp": {
|
||||||
"version": "0.1.7",
|
"version": "0.1.10",
|
||||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
|
||||||
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==",
|
"integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/path-type": {
|
"node_modules/path-type": {
|
||||||
|
@ -15501,12 +15570,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/qs": {
|
"node_modules/qs": {
|
||||||
"version": "6.11.0",
|
"version": "6.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
|
||||||
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
|
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"side-channel": "^1.0.4"
|
"side-channel": "^1.0.6"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.6"
|
"node": ">=0.6"
|
||||||
|
@ -16265,9 +16334,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "2.79.1",
|
"version": "2.79.2",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz",
|
||||||
"integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==",
|
"integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"rollup": "dist/bin/rollup"
|
"rollup": "dist/bin/rollup"
|
||||||
|
@ -16560,9 +16629,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/send": {
|
"node_modules/send": {
|
||||||
"version": "0.18.0",
|
"version": "0.19.0",
|
||||||
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
|
||||||
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
|
"integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": "2.6.9",
|
"debug": "2.6.9",
|
||||||
|
@ -16598,6 +16667,15 @@
|
||||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/send/node_modules/encodeurl": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/send/node_modules/ms": {
|
"node_modules/send/node_modules/ms": {
|
||||||
"version": "2.1.3",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
|
@ -16692,20 +16770,37 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/serve-static": {
|
"node_modules/serve-static": {
|
||||||
"version": "1.15.0",
|
"version": "1.16.2",
|
||||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
|
||||||
"integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
|
"integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"encodeurl": "~1.0.2",
|
"encodeurl": "~2.0.0",
|
||||||
"escape-html": "~1.0.3",
|
"escape-html": "~1.0.3",
|
||||||
"parseurl": "~1.3.3",
|
"parseurl": "~1.3.3",
|
||||||
"send": "0.18.0"
|
"send": "0.19.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/set-function-length": {
|
||||||
|
"version": "1.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
|
||||||
|
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"define-data-property": "^1.1.4",
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"function-bind": "^1.1.2",
|
||||||
|
"get-intrinsic": "^1.2.4",
|
||||||
|
"gopd": "^1.0.1",
|
||||||
|
"has-property-descriptors": "^1.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/setprototypeof": {
|
"node_modules/setprototypeof": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||||
|
@ -16743,14 +16838,18 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/side-channel": {
|
"node_modules/side-channel": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
|
||||||
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
|
"integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"call-bind": "^1.0.0",
|
"call-bind": "^1.0.7",
|
||||||
"get-intrinsic": "^1.0.2",
|
"es-errors": "^1.3.0",
|
||||||
"object-inspect": "^1.9.0"
|
"get-intrinsic": "^1.2.4",
|
||||||
|
"object-inspect": "^1.13.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use roc_parse::ast::{
|
use roc_parse::ast::{
|
||||||
AbilityImpls, AssignedField, Collection, Expr, ExtractSpaces, ImplementsAbilities,
|
AbilityImpls, AssignedField, Collection, Expr, ExtractSpaces, ImplementsAbilities,
|
||||||
ImplementsAbility, ImplementsClause, OldRecordBuilderField, Tag, TypeAnnotation, TypeHeader,
|
ImplementsAbility, ImplementsClause, Tag, TypeAnnotation, TypeHeader,
|
||||||
};
|
};
|
||||||
use roc_parse::ident::UppercaseIdent;
|
use roc_parse::ident::UppercaseIdent;
|
||||||
use roc_region::all::Loc;
|
use roc_region::all::Loc;
|
||||||
|
@ -524,101 +524,6 @@ fn format_assigned_field_help<T>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Formattable for OldRecordBuilderField<'a> {
|
|
||||||
fn is_multiline(&self) -> bool {
|
|
||||||
is_multiline_record_builder_field_help(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn format_with_options(&self, buf: &mut Buf, _parens: Parens, newlines: Newlines, indent: u16) {
|
|
||||||
// we abuse the `Newlines` type to decide between multiline or single-line layout
|
|
||||||
format_record_builder_field_help(self, buf, indent, newlines == Newlines::Yes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_multiline_record_builder_field_help(afield: &OldRecordBuilderField<'_>) -> bool {
|
|
||||||
use self::OldRecordBuilderField::*;
|
|
||||||
|
|
||||||
match afield {
|
|
||||||
Value(_, spaces, ann) => !spaces.is_empty() || ann.value.is_multiline(),
|
|
||||||
ApplyValue(_, colon_spaces, arrow_spaces, ann) => {
|
|
||||||
!colon_spaces.is_empty() || !arrow_spaces.is_empty() || ann.value.is_multiline()
|
|
||||||
}
|
|
||||||
LabelOnly(_) => false,
|
|
||||||
SpaceBefore(_, _) | SpaceAfter(_, _) => true,
|
|
||||||
Malformed(text) => text.chars().any(|c| c == '\n'),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn format_record_builder_field_help(
|
|
||||||
zelf: &OldRecordBuilderField,
|
|
||||||
buf: &mut Buf,
|
|
||||||
indent: u16,
|
|
||||||
is_multiline: bool,
|
|
||||||
) {
|
|
||||||
use self::OldRecordBuilderField::*;
|
|
||||||
|
|
||||||
match zelf {
|
|
||||||
Value(name, spaces, ann) => {
|
|
||||||
if is_multiline {
|
|
||||||
buf.newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.indent(indent);
|
|
||||||
buf.push_str(name.value);
|
|
||||||
|
|
||||||
if !spaces.is_empty() {
|
|
||||||
fmt_spaces(buf, spaces.iter(), indent);
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.push(':');
|
|
||||||
buf.spaces(1);
|
|
||||||
ann.value.format(buf, indent);
|
|
||||||
}
|
|
||||||
ApplyValue(name, colon_spaces, arrow_spaces, ann) => {
|
|
||||||
if is_multiline {
|
|
||||||
buf.newline();
|
|
||||||
buf.indent(indent);
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.push_str(name.value);
|
|
||||||
|
|
||||||
if !colon_spaces.is_empty() {
|
|
||||||
fmt_spaces(buf, colon_spaces.iter(), indent);
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.push(':');
|
|
||||||
buf.spaces(1);
|
|
||||||
|
|
||||||
if !arrow_spaces.is_empty() {
|
|
||||||
fmt_spaces(buf, arrow_spaces.iter(), indent);
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.push_str("<-");
|
|
||||||
buf.spaces(1);
|
|
||||||
ann.value.format(buf, indent);
|
|
||||||
}
|
|
||||||
LabelOnly(name) => {
|
|
||||||
if is_multiline {
|
|
||||||
buf.newline();
|
|
||||||
buf.indent(indent);
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.push_str(name.value);
|
|
||||||
}
|
|
||||||
SpaceBefore(sub_field, spaces) => {
|
|
||||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
|
||||||
format_record_builder_field_help(sub_field, buf, indent, is_multiline);
|
|
||||||
}
|
|
||||||
SpaceAfter(sub_field, spaces) => {
|
|
||||||
format_record_builder_field_help(sub_field, buf, indent, is_multiline);
|
|
||||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
|
||||||
}
|
|
||||||
Malformed(raw) => {
|
|
||||||
buf.push_str(raw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Formattable for Tag<'a> {
|
impl<'a> Formattable for Tag<'a> {
|
||||||
fn is_multiline(&self) -> bool {
|
fn is_multiline(&self) -> bool {
|
||||||
use self::Tag::*;
|
use self::Tag::*;
|
||||||
|
|
|
@ -10,7 +10,7 @@ use crate::Buf;
|
||||||
use roc_module::called_via::{self, BinOp};
|
use roc_module::called_via::{self, BinOp};
|
||||||
use roc_parse::ast::{
|
use roc_parse::ast::{
|
||||||
is_expr_suffixed, AssignedField, Base, Collection, CommentOrNewline, Expr, ExtractSpaces,
|
is_expr_suffixed, AssignedField, Base, Collection, CommentOrNewline, Expr, ExtractSpaces,
|
||||||
OldRecordBuilderField, Pattern, TryTarget, WhenBranch,
|
Pattern, TryTarget, WhenBranch,
|
||||||
};
|
};
|
||||||
use roc_parse::ast::{StrLiteral, StrSegment};
|
use roc_parse::ast::{StrLiteral, StrSegment};
|
||||||
use roc_parse::ident::Accessor;
|
use roc_parse::ident::Accessor;
|
||||||
|
@ -71,7 +71,11 @@ impl<'a> Formattable for Expr<'a> {
|
||||||
"LowLevelDbg should only exist after desugaring, not during formatting"
|
"LowLevelDbg should only exist after desugaring, not during formatting"
|
||||||
),
|
),
|
||||||
|
|
||||||
If(branches, final_else) => {
|
If {
|
||||||
|
if_thens: branches,
|
||||||
|
final_else,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
final_else.is_multiline()
|
final_else.is_multiline()
|
||||||
|| branches
|
|| branches
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -87,8 +91,6 @@ impl<'a> Formattable for Expr<'a> {
|
||||||
| PrecedenceConflict(roc_parse::ast::PrecedenceConflict {
|
| PrecedenceConflict(roc_parse::ast::PrecedenceConflict {
|
||||||
expr: loc_subexpr, ..
|
expr: loc_subexpr, ..
|
||||||
})
|
})
|
||||||
| MultipleOldRecordBuilders(loc_subexpr)
|
|
||||||
| UnappliedOldRecordBuilder(loc_subexpr)
|
|
||||||
| EmptyRecordBuilder(loc_subexpr)
|
| EmptyRecordBuilder(loc_subexpr)
|
||||||
| SingleFieldRecordBuilder(loc_subexpr)
|
| SingleFieldRecordBuilder(loc_subexpr)
|
||||||
| OptionalFieldInRecordBuilder(_, loc_subexpr) => loc_subexpr.is_multiline(),
|
| OptionalFieldInRecordBuilder(_, loc_subexpr) => loc_subexpr.is_multiline(),
|
||||||
|
@ -114,7 +116,6 @@ impl<'a> Formattable for Expr<'a> {
|
||||||
Record(fields) => is_collection_multiline(fields),
|
Record(fields) => is_collection_multiline(fields),
|
||||||
Tuple(fields) => is_collection_multiline(fields),
|
Tuple(fields) => is_collection_multiline(fields),
|
||||||
RecordUpdate { fields, .. } => is_collection_multiline(fields),
|
RecordUpdate { fields, .. } => is_collection_multiline(fields),
|
||||||
OldRecordBuilder(fields) => is_collection_multiline(fields),
|
|
||||||
RecordBuilder { fields, .. } => is_collection_multiline(fields),
|
RecordBuilder { fields, .. } => is_collection_multiline(fields),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -240,10 +241,7 @@ impl<'a> Formattable for Expr<'a> {
|
||||||
a.extract_spaces().item.is_multiline()
|
a.extract_spaces().item.is_multiline()
|
||||||
&& matches!(
|
&& matches!(
|
||||||
a.value.extract_spaces().item,
|
a.value.extract_spaces().item,
|
||||||
Expr::Tuple(_)
|
Expr::Tuple(_) | Expr::List(_) | Expr::Record(_)
|
||||||
| Expr::List(_)
|
|
||||||
| Expr::Record(_)
|
|
||||||
| Expr::OldRecordBuilder(_)
|
|
||||||
)
|
)
|
||||||
&& a.extract_spaces().before == [CommentOrNewline::Newline]
|
&& a.extract_spaces().before == [CommentOrNewline::Newline]
|
||||||
})
|
})
|
||||||
|
@ -388,16 +386,6 @@ impl<'a> Formattable for Expr<'a> {
|
||||||
assigned_field_to_space_before,
|
assigned_field_to_space_before,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
OldRecordBuilder(fields) => {
|
|
||||||
fmt_record_like(
|
|
||||||
buf,
|
|
||||||
None,
|
|
||||||
*fields,
|
|
||||||
indent,
|
|
||||||
format_record_builder_field_multiline,
|
|
||||||
record_builder_field_to_space_before,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Closure(loc_patterns, loc_ret) => {
|
Closure(loc_patterns, loc_ret) => {
|
||||||
fmt_closure(buf, loc_patterns, loc_ret, indent);
|
fmt_closure(buf, loc_patterns, loc_ret, indent);
|
||||||
}
|
}
|
||||||
|
@ -464,8 +452,19 @@ impl<'a> Formattable for Expr<'a> {
|
||||||
LowLevelDbg(_, _, _) => unreachable!(
|
LowLevelDbg(_, _, _) => unreachable!(
|
||||||
"LowLevelDbg should only exist after desugaring, not during formatting"
|
"LowLevelDbg should only exist after desugaring, not during formatting"
|
||||||
),
|
),
|
||||||
If(branches, final_else) => {
|
If {
|
||||||
fmt_if(buf, branches, final_else, self.is_multiline(), indent);
|
if_thens: branches,
|
||||||
|
final_else,
|
||||||
|
indented_else,
|
||||||
|
} => {
|
||||||
|
fmt_if(
|
||||||
|
buf,
|
||||||
|
branches,
|
||||||
|
final_else,
|
||||||
|
self.is_multiline(),
|
||||||
|
*indented_else,
|
||||||
|
indent,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
When(loc_condition, branches) => fmt_when(buf, loc_condition, branches, indent),
|
When(loc_condition, branches) => fmt_when(buf, loc_condition, branches, indent),
|
||||||
Tuple(items) => fmt_collection(buf, indent, Braces::Round, *items, Newlines::No),
|
Tuple(items) => fmt_collection(buf, indent, Braces::Round, *items, Newlines::No),
|
||||||
|
@ -548,8 +547,6 @@ impl<'a> Formattable for Expr<'a> {
|
||||||
}
|
}
|
||||||
MalformedClosure => {}
|
MalformedClosure => {}
|
||||||
PrecedenceConflict { .. } => {}
|
PrecedenceConflict { .. } => {}
|
||||||
MultipleOldRecordBuilders { .. } => {}
|
|
||||||
UnappliedOldRecordBuilder { .. } => {}
|
|
||||||
EmptyRecordBuilder { .. } => {}
|
EmptyRecordBuilder { .. } => {}
|
||||||
SingleFieldRecordBuilder { .. } => {}
|
SingleFieldRecordBuilder { .. } => {}
|
||||||
OptionalFieldInRecordBuilder(_, _) => {}
|
OptionalFieldInRecordBuilder(_, _) => {}
|
||||||
|
@ -610,11 +607,7 @@ pub(crate) fn format_sq_literal(buf: &mut Buf, s: &str) {
|
||||||
fn is_outdentable(expr: &Expr) -> bool {
|
fn is_outdentable(expr: &Expr) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
expr.extract_spaces().item,
|
expr.extract_spaces().item,
|
||||||
Expr::Tuple(_)
|
Expr::Tuple(_) | Expr::List(_) | Expr::Record(_) | Expr::Closure(..)
|
||||||
| Expr::List(_)
|
|
||||||
| Expr::Record(_)
|
|
||||||
| Expr::OldRecordBuilder(_)
|
|
||||||
| Expr::Closure(..)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1076,6 +1069,7 @@ fn fmt_if<'a>(
|
||||||
branches: &'a [(Loc<Expr<'a>>, Loc<Expr<'a>>)],
|
branches: &'a [(Loc<Expr<'a>>, Loc<Expr<'a>>)],
|
||||||
final_else: &'a Loc<Expr<'a>>,
|
final_else: &'a Loc<Expr<'a>>,
|
||||||
is_multiline: bool,
|
is_multiline: bool,
|
||||||
|
indented_else: bool,
|
||||||
indent: u16,
|
indent: u16,
|
||||||
) {
|
) {
|
||||||
// let is_multiline_then = loc_then.is_multiline();
|
// let is_multiline_then = loc_then.is_multiline();
|
||||||
|
@ -1208,16 +1202,22 @@ fn fmt_if<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.indent(indent);
|
if indented_else {
|
||||||
if is_multiline {
|
buf.indent(indent + INDENT);
|
||||||
|
buf.push_str("else");
|
||||||
|
buf.newline();
|
||||||
|
buf.newline();
|
||||||
|
} else if is_multiline {
|
||||||
|
buf.indent(indent);
|
||||||
buf.push_str("else");
|
buf.push_str("else");
|
||||||
buf.newline();
|
buf.newline();
|
||||||
} else {
|
} else {
|
||||||
|
buf.indent(indent);
|
||||||
buf.push_str(" else");
|
buf.push_str(" else");
|
||||||
buf.spaces(1);
|
buf.spaces(1);
|
||||||
}
|
}
|
||||||
|
let indent = if indented_else { indent } else { return_indent };
|
||||||
final_else.format(buf, return_indent);
|
final_else.format(buf, indent);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fmt_closure<'a>(
|
fn fmt_closure<'a>(
|
||||||
|
@ -1622,113 +1622,6 @@ fn assigned_field_to_space_before<'a, T>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_record_builder_field_multiline(
|
|
||||||
buf: &mut Buf,
|
|
||||||
field: &OldRecordBuilderField,
|
|
||||||
indent: u16,
|
|
||||||
separator_prefix: &str,
|
|
||||||
) {
|
|
||||||
use self::OldRecordBuilderField::*;
|
|
||||||
match field {
|
|
||||||
Value(name, spaces, ann) => {
|
|
||||||
buf.newline();
|
|
||||||
buf.indent(indent);
|
|
||||||
buf.push_str(name.value);
|
|
||||||
|
|
||||||
if !spaces.is_empty() {
|
|
||||||
fmt_spaces(buf, spaces.iter(), indent);
|
|
||||||
buf.indent(indent);
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.push_str(separator_prefix);
|
|
||||||
buf.push_str(":");
|
|
||||||
|
|
||||||
if ann.value.is_multiline() {
|
|
||||||
buf.newline();
|
|
||||||
ann.value.format(buf, indent + INDENT);
|
|
||||||
} else {
|
|
||||||
buf.spaces(1);
|
|
||||||
ann.value.format(buf, indent);
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.push(',');
|
|
||||||
}
|
|
||||||
ApplyValue(name, colon_spaces, arrow_spaces, ann) => {
|
|
||||||
buf.newline();
|
|
||||||
buf.indent(indent);
|
|
||||||
buf.push_str(name.value);
|
|
||||||
|
|
||||||
if !colon_spaces.is_empty() {
|
|
||||||
fmt_spaces(buf, colon_spaces.iter(), indent);
|
|
||||||
buf.indent(indent);
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.push_str(separator_prefix);
|
|
||||||
buf.push(':');
|
|
||||||
buf.spaces(1);
|
|
||||||
|
|
||||||
if !arrow_spaces.is_empty() {
|
|
||||||
fmt_spaces(buf, arrow_spaces.iter(), indent);
|
|
||||||
buf.indent(indent + INDENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.push_str("<-");
|
|
||||||
|
|
||||||
if ann.value.is_multiline() {
|
|
||||||
buf.newline();
|
|
||||||
ann.value.format(buf, indent + INDENT);
|
|
||||||
} else {
|
|
||||||
buf.spaces(1);
|
|
||||||
ann.value.format(buf, indent);
|
|
||||||
}
|
|
||||||
buf.push(',');
|
|
||||||
}
|
|
||||||
LabelOnly(name) => {
|
|
||||||
buf.newline();
|
|
||||||
buf.indent(indent);
|
|
||||||
buf.push_str(name.value);
|
|
||||||
buf.push(',');
|
|
||||||
}
|
|
||||||
SpaceBefore(sub_field, _spaces) => {
|
|
||||||
// We have something like that:
|
|
||||||
// ```
|
|
||||||
// # comment
|
|
||||||
// field,
|
|
||||||
// ```
|
|
||||||
// we'd like to preserve this
|
|
||||||
|
|
||||||
format_record_builder_field_multiline(buf, sub_field, indent, separator_prefix);
|
|
||||||
}
|
|
||||||
SpaceAfter(sub_field, spaces) => {
|
|
||||||
// We have something like that:
|
|
||||||
// ```
|
|
||||||
// field # comment
|
|
||||||
// , otherfield
|
|
||||||
// ```
|
|
||||||
// we'd like to transform it into:
|
|
||||||
// ```
|
|
||||||
// field,
|
|
||||||
// # comment
|
|
||||||
// otherfield
|
|
||||||
// ```
|
|
||||||
format_record_builder_field_multiline(buf, sub_field, indent, separator_prefix);
|
|
||||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Top, indent);
|
|
||||||
}
|
|
||||||
Malformed(raw) => {
|
|
||||||
buf.push_str(raw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn record_builder_field_to_space_before<'a>(
|
|
||||||
field: &'a OldRecordBuilderField<'a>,
|
|
||||||
) -> Option<(&OldRecordBuilderField<'a>, &'a [CommentOrNewline<'a>])> {
|
|
||||||
match field {
|
|
||||||
OldRecordBuilderField::SpaceBefore(sub_field, spaces) => Some((sub_field, spaces)),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sub_expr_requests_parens(expr: &Expr<'_>) -> bool {
|
fn sub_expr_requests_parens(expr: &Expr<'_>) -> bool {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::BinOps(left_side, _) => {
|
Expr::BinOps(left_side, _) => {
|
||||||
|
@ -1753,7 +1646,7 @@ fn sub_expr_requests_parens(expr: &Expr<'_>) -> bool {
|
||||||
| BinOp::Pizza => true,
|
| BinOp::Pizza => true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Expr::If(_, _) => true,
|
Expr::If { .. } => true,
|
||||||
Expr::SpaceBefore(e, _) => sub_expr_requests_parens(e),
|
Expr::SpaceBefore(e, _) => sub_expr_requests_parens(e),
|
||||||
Expr::SpaceAfter(e, _) => sub_expr_requests_parens(e),
|
Expr::SpaceAfter(e, _) => sub_expr_requests_parens(e),
|
||||||
_ => false,
|
_ => false,
|
||||||
|
|
|
@ -2915,130 +2915,108 @@ fn list_literal<'a, 'ctx>(
|
||||||
let list_length = elems.len();
|
let list_length = elems.len();
|
||||||
let list_length_intval = env.ptr_int().const_int(list_length as _, false);
|
let list_length_intval = env.ptr_int().const_int(list_length as _, false);
|
||||||
|
|
||||||
// TODO re-enable, currently causes morphic segfaults because it tries to update
|
let is_refcounted = layout_interner.contains_refcounted(element_layout);
|
||||||
// constants in-place...
|
let is_all_constant = elems.iter().all(|e| e.is_literal());
|
||||||
// if element_type.is_int_type() {
|
|
||||||
if false {
|
if is_all_constant && !is_refcounted {
|
||||||
let element_type = element_type.into_int_type();
|
// Build a global literal in-place instead of GEPing and storing individual elements.
|
||||||
|
// Exceptions:
|
||||||
|
// - Anything that is refcounted has nested pointers,
|
||||||
|
// and nested pointers in globals will break the surgical linker.
|
||||||
|
// Ignore such cases for now.
|
||||||
|
|
||||||
let element_width = layout_interner.stack_size(element_layout);
|
let element_width = layout_interner.stack_size(element_layout);
|
||||||
let size = list_length * element_width as usize;
|
|
||||||
let alignment = layout_interner
|
let alignment = layout_interner
|
||||||
.alignment_bytes(element_layout)
|
.alignment_bytes(element_layout)
|
||||||
.max(env.target.ptr_width() as u32);
|
.max(env.target.ptr_width() as u32);
|
||||||
|
|
||||||
let mut is_all_constant = true;
|
let refcount_slot_bytes = alignment as usize;
|
||||||
let zero_elements =
|
|
||||||
(env.target.ptr_width() as u8 as f64 / element_width as f64).ceil() as usize;
|
|
||||||
|
|
||||||
// runtime-evaluated elements
|
let refcount_slot_elements =
|
||||||
let mut runtime_evaluated_elements = Vec::with_capacity_in(list_length, env.arena);
|
(refcount_slot_bytes as f64 / element_width as f64).ceil() as usize;
|
||||||
|
|
||||||
// set up a global that contains all the literal elements of the array
|
let data_bytes = list_length * element_width as usize;
|
||||||
// any variables or expressions are represented as `undef`
|
|
||||||
let global = {
|
|
||||||
let mut global_elements = Vec::with_capacity_in(list_length, env.arena);
|
|
||||||
|
|
||||||
// Add zero bytes that represent the refcount
|
assert!(refcount_slot_elements > 0);
|
||||||
//
|
|
||||||
// - if all elements are const, then we store the whole list as a constant.
|
let global = if element_type.is_int_type() {
|
||||||
// It then needs a refcount before the first element.
|
let element_type = element_type.into_int_type();
|
||||||
// - but if the list is not all constants, then we will just copy the constant values,
|
let mut bytes = Vec::with_capacity_in(refcount_slot_elements + data_bytes, env.arena);
|
||||||
// and we do not need that refcount at the start
|
|
||||||
//
|
// Fill the refcount slot with nulls
|
||||||
// In the latter case, we won't store the zeros in the globals
|
for _ in 0..(refcount_slot_elements) {
|
||||||
// (we slice them off again below)
|
bytes.push(element_type.const_zero());
|
||||||
for _ in 0..zero_elements {
|
|
||||||
global_elements.push(element_type.const_zero());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the elements from the list literal into the array
|
// Copy the elements from the list literal into the array
|
||||||
for (index, element) in elems.iter().enumerate() {
|
for element in elems.iter() {
|
||||||
match element {
|
let literal = element.get_literal().expect("is_all_constant is true");
|
||||||
ListLiteralElement::Literal(literal) => {
|
let val = build_exp_literal(env, layout_interner, element_layout, &literal);
|
||||||
let val = build_exp_literal(env, layout_interner, element_layout, literal);
|
bytes.push(val.into_int_value());
|
||||||
global_elements.push(val.into_int_value());
|
|
||||||
}
|
|
||||||
ListLiteralElement::Symbol(symbol) => {
|
|
||||||
let val = scope.load_symbol(symbol);
|
|
||||||
|
|
||||||
// here we'd like to furthermore check for intval.is_const().
|
|
||||||
// if all elements are const for LLVM, we could make the array a constant.
|
|
||||||
// BUT morphic does not know about this, and could allow us to modify that
|
|
||||||
// array in-place. That would cause a segfault. So, we'll have to find
|
|
||||||
// constants ourselves and cannot lean on LLVM here.
|
|
||||||
|
|
||||||
is_all_constant = false;
|
|
||||||
|
|
||||||
runtime_evaluated_elements.push((index, val));
|
|
||||||
|
|
||||||
global_elements.push(element_type.get_undef());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let const_elements = if is_all_constant {
|
let typ = element_type.array_type(bytes.len() as u32);
|
||||||
global_elements.into_bump_slice()
|
|
||||||
} else {
|
|
||||||
&global_elements[zero_elements..]
|
|
||||||
};
|
|
||||||
|
|
||||||
// use None for the address space (e.g. Const does not work)
|
|
||||||
let typ = element_type.array_type(const_elements.len() as u32);
|
|
||||||
let global = env.module.add_global(typ, None, "roc__list_literal");
|
let global = env.module.add_global(typ, None, "roc__list_literal");
|
||||||
|
|
||||||
global.set_constant(true);
|
global.set_initializer(&element_type.const_array(bytes.into_bump_slice()));
|
||||||
global.set_alignment(alignment);
|
global
|
||||||
global.set_unnamed_addr(true);
|
} else if element_type.is_float_type() {
|
||||||
global.set_linkage(inkwell::module::Linkage::Private);
|
let element_type = element_type.into_float_type();
|
||||||
|
let mut bytes = Vec::with_capacity_in(refcount_slot_elements + data_bytes, env.arena);
|
||||||
|
|
||||||
global.set_initializer(&element_type.const_array(const_elements));
|
// Fill the refcount slot with nulls
|
||||||
global.as_pointer_value()
|
for _ in 0..(refcount_slot_elements) {
|
||||||
};
|
bytes.push(element_type.const_zero());
|
||||||
|
|
||||||
if is_all_constant {
|
|
||||||
// all elements are constants, so we can use the memory in the constants section directly
|
|
||||||
// here we make a pointer to the first actual element (skipping the 0 bytes that
|
|
||||||
// represent the refcount)
|
|
||||||
let zero = env.ptr_int().const_zero();
|
|
||||||
let offset = env.ptr_int().const_int(zero_elements as _, false);
|
|
||||||
|
|
||||||
let ptr = unsafe {
|
|
||||||
env.builder.new_build_in_bounds_gep(
|
|
||||||
element_type,
|
|
||||||
global,
|
|
||||||
&[zero, offset],
|
|
||||||
"first_element_pointer",
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
super::build_list::store_list(env, ptr, list_length_intval).into()
|
|
||||||
} else {
|
|
||||||
// some of our elements are non-constant, so we must allocate space on the heap
|
|
||||||
let ptr = allocate_list(env, layout_interner, element_layout, list_length_intval);
|
|
||||||
|
|
||||||
// then, copy the relevant segment from the constant section into the heap
|
|
||||||
env.builder
|
|
||||||
.build_memcpy(
|
|
||||||
ptr,
|
|
||||||
alignment,
|
|
||||||
global,
|
|
||||||
alignment,
|
|
||||||
env.ptr_int().const_int(size as _, false),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// then replace the `undef`s with the values that we evaluate at runtime
|
|
||||||
for (index, val) in runtime_evaluated_elements {
|
|
||||||
let index_val = ctx.i64_type().const_int(index as u64, false);
|
|
||||||
let elem_ptr = unsafe {
|
|
||||||
builder.new_build_in_bounds_gep(element_type, ptr, &[index_val], "index")
|
|
||||||
};
|
|
||||||
|
|
||||||
builder.new_build_store(elem_ptr, val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
super::build_list::store_list(env, ptr, list_length_intval).into()
|
// Copy the elements from the list literal into the array
|
||||||
}
|
for element in elems.iter() {
|
||||||
|
let literal = element.get_literal().expect("is_all_constant is true");
|
||||||
|
let val = build_exp_literal(env, layout_interner, element_layout, &literal);
|
||||||
|
bytes.push(val.into_float_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
let typ = element_type.array_type(bytes.len() as u32);
|
||||||
|
let global = env.module.add_global(typ, None, "roc__list_literal");
|
||||||
|
|
||||||
|
global.set_initializer(&element_type.const_array(bytes.into_bump_slice()));
|
||||||
|
global
|
||||||
|
} else {
|
||||||
|
internal_error!("unexpected element type: {:?}", element_type);
|
||||||
|
};
|
||||||
|
|
||||||
|
global.set_constant(true);
|
||||||
|
global.set_alignment(alignment);
|
||||||
|
global.set_unnamed_addr(true);
|
||||||
|
global.set_linkage(inkwell::module::Linkage::Private);
|
||||||
|
|
||||||
|
// Refcount the global itself in a new allocation.
|
||||||
|
// Necessary because morphic MAY attempt to update the global in-place, which is
|
||||||
|
// illegal if the global is in the read-only section.
|
||||||
|
let with_rc_ptr = global.as_pointer_value();
|
||||||
|
|
||||||
|
let const_data_ptr = unsafe {
|
||||||
|
env.builder.new_build_in_bounds_gep(
|
||||||
|
element_type,
|
||||||
|
with_rc_ptr,
|
||||||
|
&[env
|
||||||
|
.ptr_int()
|
||||||
|
.const_int(refcount_slot_elements as u64, false)],
|
||||||
|
"get_data_ptr",
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let data_ptr = allocate_list(env, layout_interner, element_layout, list_length_intval);
|
||||||
|
|
||||||
|
let byte_size = env
|
||||||
|
.ptr_int()
|
||||||
|
.const_int(list_length as u64 * element_width as u64, false);
|
||||||
|
builder
|
||||||
|
.build_memcpy(data_ptr, alignment, const_data_ptr, alignment, byte_size)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
super::build_list::store_list(env, data_ptr, list_length_intval).into()
|
||||||
} else {
|
} else {
|
||||||
let ptr = allocate_list(env, layout_interner, element_layout, list_length_intval);
|
let ptr = allocate_list(env, layout_interner, element_layout, list_length_intval);
|
||||||
|
|
||||||
|
|
|
@ -282,16 +282,9 @@ pub(crate) struct RocUnion<'ctx> {
|
||||||
tag_type: Option<TagType>,
|
tag_type: Option<TagType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_multiple_of(big: u32, small: u32) -> bool {
|
|
||||||
match small {
|
|
||||||
0 => true, // 0 is a multiple of all n, because n * 0 = 0
|
|
||||||
n => big % n == 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> RocUnion<'ctx> {
|
impl<'ctx> RocUnion<'ctx> {
|
||||||
pub const TAG_ID_INDEX: u32 = 2;
|
pub const TAG_ID_INDEX: u32 = 1;
|
||||||
pub const TAG_DATA_INDEX: u32 = 1;
|
pub const TAG_DATA_INDEX: u32 = 0;
|
||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
context: &'ctx Context,
|
context: &'ctx Context,
|
||||||
|
@ -301,45 +294,24 @@ impl<'ctx> RocUnion<'ctx> {
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let bytes = round_up_to_alignment(data_width, data_align);
|
let bytes = round_up_to_alignment(data_width, data_align);
|
||||||
|
|
||||||
let byte_array_type = if is_multiple_of(bytes, 8) && is_multiple_of(data_align, 8) {
|
let align_type = alignment_type(context, data_align);
|
||||||
context
|
let byte_array_type = align_type
|
||||||
.i64_type()
|
.array_type(bytes / data_align)
|
||||||
.array_type(bytes / 8)
|
|
||||||
.as_basic_type_enum()
|
|
||||||
} else {
|
|
||||||
context.i8_type().array_type(bytes).as_basic_type_enum()
|
|
||||||
};
|
|
||||||
|
|
||||||
let alignment_array_type = alignment_type(context, data_align)
|
|
||||||
.array_type(0)
|
|
||||||
.as_basic_type_enum();
|
.as_basic_type_enum();
|
||||||
|
|
||||||
let struct_type = if let Some(tag_type) = tag_type {
|
let struct_type = if let Some(tag_type) = tag_type {
|
||||||
let tag_width = match tag_type {
|
|
||||||
TagType::I8 => 1,
|
|
||||||
TagType::I16 => 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
let tag_padding = round_up_to_alignment(tag_width, data_align) - tag_width;
|
|
||||||
let tag_padding_type = context
|
|
||||||
.i8_type()
|
|
||||||
.array_type(tag_padding)
|
|
||||||
.as_basic_type_enum();
|
|
||||||
|
|
||||||
context.struct_type(
|
context.struct_type(
|
||||||
&[
|
&[
|
||||||
alignment_array_type,
|
|
||||||
byte_array_type,
|
byte_array_type,
|
||||||
match tag_type {
|
match tag_type {
|
||||||
TagType::I8 => context.i8_type().into(),
|
TagType::I8 => context.i8_type().into(),
|
||||||
TagType::I16 => context.i16_type().into(),
|
TagType::I16 => context.i16_type().into(),
|
||||||
},
|
},
|
||||||
tag_padding_type,
|
|
||||||
],
|
],
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
context.struct_type(&[alignment_array_type, byte_array_type], false)
|
context.struct_type(&[byte_array_type], false)
|
||||||
};
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
|
|
@ -161,23 +161,6 @@ pub fn can_expr_with<'a>(
|
||||||
// ensure the Test module is accessible in our tests
|
// ensure the Test module is accessible in our tests
|
||||||
module_ids.get_or_insert(&PQModuleName::Unqualified("Test".into()));
|
module_ids.get_or_insert(&PQModuleName::Unqualified("Test".into()));
|
||||||
|
|
||||||
// Desugar operators (convert them to Apply calls, taking into account
|
|
||||||
// operator precedence and associativity rules), before doing other canonicalization.
|
|
||||||
//
|
|
||||||
// If we did this *during* canonicalization, then each time we
|
|
||||||
// visited a BinOp node we'd recursively try to apply this to each of its nested
|
|
||||||
// operators, and then again on *their* nested operators, ultimately applying the
|
|
||||||
// rules multiple times unnecessarily.
|
|
||||||
let loc_expr = desugar::desugar_expr(
|
|
||||||
arena,
|
|
||||||
&mut var_store,
|
|
||||||
&loc_expr,
|
|
||||||
expr_str,
|
|
||||||
&mut None,
|
|
||||||
arena.alloc("TestPath"),
|
|
||||||
&mut Default::default(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut scope = Scope::new(
|
let mut scope = Scope::new(
|
||||||
home,
|
home,
|
||||||
"TestPath".into(),
|
"TestPath".into(),
|
||||||
|
@ -188,12 +171,23 @@ pub fn can_expr_with<'a>(
|
||||||
let dep_idents = IdentIds::exposed_builtins(0);
|
let dep_idents = IdentIds::exposed_builtins(0);
|
||||||
let mut env = Env::new(
|
let mut env = Env::new(
|
||||||
arena,
|
arena,
|
||||||
|
expr_str,
|
||||||
home,
|
home,
|
||||||
Path::new("Test.roc"),
|
Path::new("Test.roc"),
|
||||||
&dep_idents,
|
&dep_idents,
|
||||||
&module_ids,
|
&module_ids,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Desugar operators (convert them to Apply calls, taking into account
|
||||||
|
// operator precedence and associativity rules), before doing other canonicalization.
|
||||||
|
//
|
||||||
|
// If we did this *during* canonicalization, then each time we
|
||||||
|
// visited a BinOp node we'd recursively try to apply this to each of its nested
|
||||||
|
// operators, and then again on *their* nested operators, ultimately applying the
|
||||||
|
// rules multiple times unnecessarily.
|
||||||
|
let loc_expr = desugar::desugar_expr(&mut env, &mut scope, &loc_expr);
|
||||||
|
|
||||||
let (loc_expr, output) = canonicalize_expr(
|
let (loc_expr, output) = canonicalize_expr(
|
||||||
&mut env,
|
&mut env,
|
||||||
&mut var_store,
|
&mut var_store,
|
||||||
|
|
|
@ -4299,8 +4299,9 @@ mod test_reporting {
|
||||||
4│ f :: I64
|
4│ f :: I64
|
||||||
^^
|
^^
|
||||||
|
|
||||||
I have no specific suggestion for this operator, see TODO for the full
|
I have no specific suggestion for this operator, see
|
||||||
list of operators in Roc.
|
https://www.roc-lang.org/tutorial#operator-desugaring-table for the
|
||||||
|
full list of operators in Roc.
|
||||||
"#
|
"#
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -4339,6 +4340,14 @@ mod test_reporting {
|
||||||
|
|
||||||
However, I already saw the final expression in that series of
|
However, I already saw the final expression in that series of
|
||||||
definitions.
|
definitions.
|
||||||
|
|
||||||
|
Tip: An expression like `4`, `"hello"`, or `functionCall MyThing` is
|
||||||
|
like `return 4` in other programming languages. To me, it seems like
|
||||||
|
you did `return 4` followed by more code in the lines after, that code
|
||||||
|
would never be executed!
|
||||||
|
|
||||||
|
Tip: If you are working with `Task`, this error can happen if you
|
||||||
|
forgot a `!` somewhere.
|
||||||
"###
|
"###
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -4972,30 +4981,6 @@ mod test_reporting {
|
||||||
"###
|
"###
|
||||||
);
|
);
|
||||||
|
|
||||||
test_report!(
|
|
||||||
record_builder_in_module_params,
|
|
||||||
indoc!(
|
|
||||||
r"
|
|
||||||
import Menu {
|
|
||||||
echo,
|
|
||||||
name: <- applyName
|
|
||||||
}
|
|
||||||
"
|
|
||||||
),@r###"
|
|
||||||
── OLD-STYLE RECORD BUILDER IN MODULE PARAMS in ...r_in_module_params/Test.roc ─
|
|
||||||
|
|
||||||
I was partway through parsing module params, but I got stuck here:
|
|
||||||
|
|
||||||
4│ import Menu {
|
|
||||||
5│ echo,
|
|
||||||
6│ name: <- applyName
|
|
||||||
^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
This looks like an old-style record builder field, but those are not
|
|
||||||
allowed in module params.
|
|
||||||
"###
|
|
||||||
);
|
|
||||||
|
|
||||||
test_report!(
|
test_report!(
|
||||||
record_update_in_module_params,
|
record_update_in_module_params,
|
||||||
indoc!(
|
indoc!(
|
||||||
|
@ -6068,8 +6053,9 @@ All branches in an `if` must have the same type!
|
||||||
5│ 5 ** 3
|
5│ 5 ** 3
|
||||||
^^
|
^^
|
||||||
|
|
||||||
I have no specific suggestion for this operator, see TODO for the full
|
I have no specific suggestion for this operator, see
|
||||||
list of operators in Roc.
|
https://www.roc-lang.org/tutorial#operator-desugaring-table for the
|
||||||
|
full list of operators in Roc.
|
||||||
"#
|
"#
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -10661,163 +10647,6 @@ All branches in an `if` must have the same type!
|
||||||
|
|
||||||
// Record Builders
|
// Record Builders
|
||||||
|
|
||||||
test_report!(
|
|
||||||
optional_field_in_old_record_builder,
|
|
||||||
indoc!(
|
|
||||||
r#"
|
|
||||||
{
|
|
||||||
a: <- apply "a",
|
|
||||||
b,
|
|
||||||
c ? "optional"
|
|
||||||
}
|
|
||||||
"#
|
|
||||||
),
|
|
||||||
@r#"
|
|
||||||
── BAD OLD-STYLE RECORD BUILDER in ...nal_field_in_old_record_builder/Test.roc ─
|
|
||||||
|
|
||||||
I am partway through parsing a record builder, and I found an optional
|
|
||||||
field:
|
|
||||||
|
|
||||||
1│ app "test" provides [main] to "./platform"
|
|
||||||
2│
|
|
||||||
3│ main =
|
|
||||||
4│ {
|
|
||||||
5│ a: <- apply "a",
|
|
||||||
6│ b,
|
|
||||||
7│ c ? "optional"
|
|
||||||
^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
Optional fields can only appear when you destructure a record.
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
test_report!(
|
|
||||||
record_update_old_builder,
|
|
||||||
indoc!(
|
|
||||||
r#"
|
|
||||||
{ rec &
|
|
||||||
a: <- apply "a",
|
|
||||||
b: 3
|
|
||||||
}
|
|
||||||
"#
|
|
||||||
),
|
|
||||||
@r#"
|
|
||||||
── BAD RECORD UPDATE in tmp/record_update_old_builder/Test.roc ─────────────────
|
|
||||||
|
|
||||||
I am partway through parsing a record update, and I found an old-style
|
|
||||||
record builder field:
|
|
||||||
|
|
||||||
1│ app "test" provides [main] to "./platform"
|
|
||||||
2│
|
|
||||||
3│ main =
|
|
||||||
4│ { rec &
|
|
||||||
5│ a: <- apply "a",
|
|
||||||
^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
Old-style record builders cannot be updated like records.
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
test_report!(
|
|
||||||
multiple_old_record_builders,
|
|
||||||
indoc!(
|
|
||||||
r#"
|
|
||||||
succeed
|
|
||||||
{ a: <- apply "a" }
|
|
||||||
{ b: <- apply "b" }
|
|
||||||
"#
|
|
||||||
),
|
|
||||||
@r#"
|
|
||||||
── MULTIPLE OLD-STYLE RECORD BUILDERS in /code/proj/Main.roc ───────────────────
|
|
||||||
|
|
||||||
This function is applied to multiple old-style record builders:
|
|
||||||
|
|
||||||
4│> succeed
|
|
||||||
5│> { a: <- apply "a" }
|
|
||||||
6│> { b: <- apply "b" }
|
|
||||||
|
|
||||||
Note: Functions can only take at most one old-style record builder!
|
|
||||||
|
|
||||||
Tip: You can combine them or apply them separately.
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
test_report!(
|
|
||||||
unapplied_old_record_builder,
|
|
||||||
indoc!(
|
|
||||||
r#"
|
|
||||||
{ a: <- apply "a" }
|
|
||||||
"#
|
|
||||||
),
|
|
||||||
@r#"
|
|
||||||
── UNAPPLIED OLD-STYLE RECORD BUILDER in /code/proj/Main.roc ───────────────────
|
|
||||||
|
|
||||||
This old-style record builder was not applied to a function:
|
|
||||||
|
|
||||||
4│ { a: <- apply "a" }
|
|
||||||
^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
However, we need a function to construct the record.
|
|
||||||
|
|
||||||
Note: Functions must be applied directly. The pipe operator (|>) cannot be used.
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
test_report!(
|
|
||||||
old_record_builder_apply_non_function,
|
|
||||||
indoc!(
|
|
||||||
r#"
|
|
||||||
succeed = \_ -> crash ""
|
|
||||||
|
|
||||||
succeed {
|
|
||||||
a: <- "a",
|
|
||||||
}
|
|
||||||
"#
|
|
||||||
),
|
|
||||||
@r#"
|
|
||||||
── TOO MANY ARGS in /code/proj/Main.roc ────────────────────────────────────────
|
|
||||||
|
|
||||||
This value is not a function, but it was given 1 argument:
|
|
||||||
|
|
||||||
7│ a: <- "a",
|
|
||||||
^^^
|
|
||||||
|
|
||||||
Tip: Remove <- to assign the field directly.
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
// Skipping test because opaque types defined in the same module
|
|
||||||
// do not fail with the special opaque type error
|
|
||||||
//
|
|
||||||
// test_report!(
|
|
||||||
// record_builder_apply_opaque,
|
|
||||||
// indoc!(
|
|
||||||
// r#"
|
|
||||||
// succeed = \_ -> crash ""
|
|
||||||
|
|
||||||
// Decode := {}
|
|
||||||
|
|
||||||
// get : Str -> Decode
|
|
||||||
// get = \_ -> @Decode {}
|
|
||||||
|
|
||||||
// succeed {
|
|
||||||
// a: <- get "a",
|
|
||||||
// # missing |> apply ^
|
|
||||||
// }
|
|
||||||
// "#
|
|
||||||
// ),
|
|
||||||
// @r#"
|
|
||||||
// ── TOO MANY ARGS in /code/proj/Main.roc ────────────────────────────────────────
|
|
||||||
|
|
||||||
// This value is an opaque type, so it cannot be called with an argument:
|
|
||||||
|
|
||||||
// 12│ a: <- get "a",
|
|
||||||
// ^^^^^^^
|
|
||||||
|
|
||||||
// Hint: Did you mean to apply it to a function first?
|
|
||||||
// "#
|
|
||||||
// );
|
|
||||||
|
|
||||||
test_report!(
|
test_report!(
|
||||||
empty_record_builder,
|
empty_record_builder,
|
||||||
indoc!(
|
indoc!(
|
||||||
|
@ -14521,7 +14350,7 @@ All branches in an `if` must have the same type!
|
||||||
4│ 1 + dbg + 2
|
4│ 1 + dbg + 2
|
||||||
^^^
|
^^^
|
||||||
|
|
||||||
This `63` value is a:
|
This value is a:
|
||||||
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
@ -14555,7 +14384,7 @@ All branches in an `if` must have the same type!
|
||||||
4│ 1 + dbg "" "" + 2
|
4│ 1 + dbg "" "" + 2
|
||||||
^^^^^^^^^
|
^^^^^^^^^
|
||||||
|
|
||||||
This `63` value is a:
|
This value is a:
|
||||||
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
|
@ -784,7 +784,7 @@ impl<'a> State<'a> {
|
||||||
number_of_workers: usize,
|
number_of_workers: usize,
|
||||||
exec_mode: ExecutionMode,
|
exec_mode: ExecutionMode,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let cache_dir = roc_packaging::cache::roc_cache_dir();
|
let cache_dir = roc_packaging::cache::roc_cache_packages_dir();
|
||||||
let dependencies = Dependencies::new(exec_mode.goal_phase());
|
let dependencies = Dependencies::new(exec_mode.goal_phase());
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
@ -1665,7 +1665,7 @@ fn state_thread_step<'a>(
|
||||||
Ok(ControlFlow::Break(LoadResult::Monomorphized(monomorphized)))
|
Ok(ControlFlow::Break(LoadResult::Monomorphized(monomorphized)))
|
||||||
}
|
}
|
||||||
Msg::FailedToReadFile { filename, error } => {
|
Msg::FailedToReadFile { filename, error } => {
|
||||||
let buf = to_file_problem_report_string(filename, error);
|
let buf = to_file_problem_report_string(filename, error, true);
|
||||||
Err(LoadingProblem::FormattedReport(buf))
|
Err(LoadingProblem::FormattedReport(buf))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1839,7 +1839,7 @@ pub fn report_loading_problem(
|
||||||
}
|
}
|
||||||
LoadingProblem::FormattedReport(report) => report,
|
LoadingProblem::FormattedReport(report) => report,
|
||||||
LoadingProblem::FileProblem { filename, error } => {
|
LoadingProblem::FileProblem { filename, error } => {
|
||||||
to_file_problem_report_string(filename, error)
|
to_file_problem_report_string(filename, error, true)
|
||||||
}
|
}
|
||||||
LoadingProblem::NoPlatformPackage {
|
LoadingProblem::NoPlatformPackage {
|
||||||
filename,
|
filename,
|
||||||
|
|
|
@ -75,10 +75,6 @@ pub enum CalledVia {
|
||||||
/// e.g. "$(first) $(last)" is transformed into Str.concat (Str.concat first " ") last.
|
/// e.g. "$(first) $(last)" is transformed into Str.concat (Str.concat first " ") last.
|
||||||
StringInterpolation,
|
StringInterpolation,
|
||||||
|
|
||||||
/// This call is the result of desugaring an old style Record Builder field.
|
|
||||||
/// e.g. succeed { a <- get "a" } is transformed into (get "a") (succeed \a -> { a })
|
|
||||||
OldRecordBuilder,
|
|
||||||
|
|
||||||
/// This call is the result of desugaring a map2-based Record Builder field. e.g.
|
/// This call is the result of desugaring a map2-based Record Builder field. e.g.
|
||||||
/// ```roc
|
/// ```roc
|
||||||
/// { Task.parallel <-
|
/// { Task.parallel <-
|
||||||
|
|
|
@ -123,6 +123,10 @@ impl Symbol {
|
||||||
.any(|(_, (s, _))| *s == self)
|
.any(|(_, (s, _))| *s == self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_generated(self, interns: &Interns) -> bool {
|
||||||
|
self.ident_ids(interns).is_generated_id(self.ident_id())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn module_string<'a>(&self, interns: &'a Interns) -> &'a ModuleName {
|
pub fn module_string<'a>(&self, interns: &'a Interns) -> &'a ModuleName {
|
||||||
interns
|
interns
|
||||||
.module_ids
|
.module_ids
|
||||||
|
@ -137,24 +141,15 @@ impl Symbol {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_str(self, interns: &Interns) -> &str {
|
pub fn as_str(self, interns: &Interns) -> &str {
|
||||||
let ident_ids = interns
|
self.ident_ids(interns)
|
||||||
.all_ident_ids
|
.get_name(self.ident_id())
|
||||||
.get(&self.module_id())
|
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
internal_error!(
|
internal_error!(
|
||||||
"ident_string could not find IdentIds for module {:?} in {:?}",
|
"ident_string's IdentIds did not contain an entry for {} in module {:?}",
|
||||||
self.module_id(),
|
self.ident_id().0,
|
||||||
interns
|
self.module_id()
|
||||||
)
|
)
|
||||||
});
|
})
|
||||||
|
|
||||||
ident_ids.get_name(self.ident_id()).unwrap_or_else(|| {
|
|
||||||
internal_error!(
|
|
||||||
"ident_string's IdentIds did not contain an entry for {} in module {:?}",
|
|
||||||
self.ident_id().0,
|
|
||||||
self.module_id()
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn as_u64(self) -> u64 {
|
pub const fn as_u64(self) -> u64 {
|
||||||
|
@ -186,6 +181,19 @@ impl Symbol {
|
||||||
pub fn contains(self, needle: &str) -> bool {
|
pub fn contains(self, needle: &str) -> bool {
|
||||||
format!("{self:?}").contains(needle)
|
format!("{self:?}").contains(needle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ident_ids(self, interns: &Interns) -> &IdentIds {
|
||||||
|
interns
|
||||||
|
.all_ident_ids
|
||||||
|
.get(&self.module_id())
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
internal_error!(
|
||||||
|
"ident_string could not find IdentIds for module {:?} in {:?}",
|
||||||
|
self.module_id(),
|
||||||
|
interns
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rather than displaying as this:
|
/// Rather than displaying as this:
|
||||||
|
@ -438,13 +446,6 @@ impl fmt::Debug for ModuleId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// pf.Task
|
|
||||||
/// 1. build mapping from short name to package
|
|
||||||
/// 2. when adding new modules from package we need to register them in some other map (this module id goes with short name) (shortname, module-name) -> moduleId
|
|
||||||
/// 3. pass this around to other modules getting headers parsed. when parsing interfaces we need to use this map to reference shortnames
|
|
||||||
/// 4. throw away short names. stash the module id in the can env under the resolved module name
|
|
||||||
/// 5. test:
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub enum PackageQualified<'a, T> {
|
pub enum PackageQualified<'a, T> {
|
||||||
Unqualified(T),
|
Unqualified(T),
|
||||||
|
@ -707,6 +708,12 @@ impl IdentIds {
|
||||||
IdentId(self.interner.insert_index_str() as u32)
|
IdentId(self.interner.insert_index_str() as u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_generated_id(&self, id: IdentId) -> bool {
|
||||||
|
self.interner
|
||||||
|
.try_get(id.0 as usize)
|
||||||
|
.map_or(false, |str| str.starts_with(|c: char| c.is_ascii_digit()))
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn get_id(&self, ident_name: &str) -> Option<IdentId> {
|
pub fn get_id(&self, ident_name: &str) -> Option<IdentId> {
|
||||||
self.interner
|
self.interner
|
||||||
|
@ -1373,6 +1380,8 @@ define_builtins! {
|
||||||
46 STR_REPLACE_FIRST: "replaceFirst"
|
46 STR_REPLACE_FIRST: "replaceFirst"
|
||||||
47 STR_REPLACE_LAST: "replaceLast"
|
47 STR_REPLACE_LAST: "replaceLast"
|
||||||
48 STR_RELEASE_EXCESS_CAPACITY: "releaseExcessCapacity"
|
48 STR_RELEASE_EXCESS_CAPACITY: "releaseExcessCapacity"
|
||||||
|
49 STR_DROP_PREFIX: "dropPrefix"
|
||||||
|
50 STR_DROP_SUFFIX: "dropSuffix"
|
||||||
}
|
}
|
||||||
6 LIST: "List" => {
|
6 LIST: "List" => {
|
||||||
0 LIST_LIST: "List" exposed_apply_type=true // the List.List type alias
|
0 LIST_LIST: "List" exposed_apply_type=true // the List.List type alias
|
||||||
|
|
|
@ -396,7 +396,7 @@ impl<'state, 'a> State<'state, 'a> {
|
||||||
None => unreachable!(
|
None => unreachable!(
|
||||||
"\n\tNo borrow signature for {name:?} layout.\n\n\t\
|
"\n\tNo borrow signature for {name:?} layout.\n\n\t\
|
||||||
Tip 1: This can happen when you call a function with less arguments than it expects.\n\t\
|
Tip 1: This can happen when you call a function with less arguments than it expects.\n\t\
|
||||||
Like `Arg.list!` instead of `Arg.list! {{}}`.\n\t
|
Like `Arg.list!` instead of `Arg.list! {{}}`.\n\t\
|
||||||
Tip 2: `roc check yourfile.roc` can sometimes give you a helpful error.
|
Tip 2: `roc check yourfile.roc` can sometimes give you a helpful error.
|
||||||
"
|
"
|
||||||
)
|
)
|
||||||
|
|
|
@ -49,6 +49,17 @@ impl<'a> ListLiteralElement<'a> {
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_literal(&self) -> Option<Literal<'a>> {
|
||||||
|
match self {
|
||||||
|
Self::Literal(l) => Some(*l),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_literal(&self) -> bool {
|
||||||
|
matches!(self, Self::Literal(_))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum NumLiteral {
|
pub enum NumLiteral {
|
||||||
|
|
|
@ -456,13 +456,6 @@ pub enum Expr<'a> {
|
||||||
|
|
||||||
Tuple(Collection<'a, &'a Loc<Expr<'a>>>),
|
Tuple(Collection<'a, &'a Loc<Expr<'a>>>),
|
||||||
|
|
||||||
// Record Builders
|
|
||||||
/// Applicative record builders, e.g.
|
|
||||||
/// build {
|
|
||||||
/// foo: <- getData Foo,
|
|
||||||
/// bar: <- getData Bar,
|
|
||||||
/// }
|
|
||||||
OldRecordBuilder(Collection<'a, Loc<OldRecordBuilderField<'a>>>),
|
|
||||||
/// Mapper-based record builders, e.g.
|
/// Mapper-based record builders, e.g.
|
||||||
/// { Task.parallel <-
|
/// { Task.parallel <-
|
||||||
/// foo: Task.getData Foo,
|
/// foo: Task.getData Foo,
|
||||||
|
@ -512,7 +505,11 @@ pub enum Expr<'a> {
|
||||||
UnaryOp(&'a Loc<Expr<'a>>, Loc<UnaryOp>),
|
UnaryOp(&'a Loc<Expr<'a>>, Loc<UnaryOp>),
|
||||||
|
|
||||||
// Conditionals
|
// Conditionals
|
||||||
If(&'a [(Loc<Expr<'a>>, Loc<Expr<'a>>)], &'a Loc<Expr<'a>>),
|
If {
|
||||||
|
if_thens: &'a [(Loc<Expr<'a>>, Loc<Expr<'a>>)],
|
||||||
|
final_else: &'a Loc<Expr<'a>>,
|
||||||
|
indented_else: bool,
|
||||||
|
},
|
||||||
When(
|
When(
|
||||||
/// The condition
|
/// The condition
|
||||||
&'a Loc<Expr<'a>>,
|
&'a Loc<Expr<'a>>,
|
||||||
|
@ -537,8 +534,6 @@ pub enum Expr<'a> {
|
||||||
// Both operators were non-associative, e.g. (True == False == False).
|
// Both operators were non-associative, e.g. (True == False == False).
|
||||||
// We should tell the author to disambiguate by grouping them with parens.
|
// We should tell the author to disambiguate by grouping them with parens.
|
||||||
PrecedenceConflict(&'a PrecedenceConflict<'a>),
|
PrecedenceConflict(&'a PrecedenceConflict<'a>),
|
||||||
MultipleOldRecordBuilders(&'a Loc<Expr<'a>>),
|
|
||||||
UnappliedOldRecordBuilder(&'a Loc<Expr<'a>>),
|
|
||||||
EmptyRecordBuilder(&'a Loc<Expr<'a>>),
|
EmptyRecordBuilder(&'a Loc<Expr<'a>>),
|
||||||
SingleFieldRecordBuilder(&'a Loc<Expr<'a>>),
|
SingleFieldRecordBuilder(&'a Loc<Expr<'a>>),
|
||||||
OptionalFieldInRecordBuilder(&'a Loc<&'a str>, &'a Loc<Expr<'a>>),
|
OptionalFieldInRecordBuilder(&'a Loc<&'a str>, &'a Loc<Expr<'a>>),
|
||||||
|
@ -608,7 +603,11 @@ pub fn is_expr_suffixed(expr: &Expr) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// expression in a if-then-else, `if isOk! then "ok" else doSomething!`
|
// expression in a if-then-else, `if isOk! then "ok" else doSomething!`
|
||||||
Expr::If(if_thens, final_else) => {
|
Expr::If {
|
||||||
|
if_thens,
|
||||||
|
final_else,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
let any_if_thens_suffixed = if_thens.iter().any(|(if_then, else_expr)| {
|
let any_if_thens_suffixed = if_thens.iter().any(|(if_then, else_expr)| {
|
||||||
is_expr_suffixed(&if_then.value) || is_expr_suffixed(&else_expr.value)
|
is_expr_suffixed(&if_then.value) || is_expr_suffixed(&else_expr.value)
|
||||||
});
|
});
|
||||||
|
@ -655,9 +654,6 @@ pub fn is_expr_suffixed(expr: &Expr) -> bool {
|
||||||
.iter()
|
.iter()
|
||||||
.any(|field| is_assigned_value_suffixed(&field.value)),
|
.any(|field| is_assigned_value_suffixed(&field.value)),
|
||||||
Expr::Tuple(items) => items.iter().any(|x| is_expr_suffixed(&x.value)),
|
Expr::Tuple(items) => items.iter().any(|x| is_expr_suffixed(&x.value)),
|
||||||
Expr::OldRecordBuilder(items) => items
|
|
||||||
.iter()
|
|
||||||
.any(|rbf| is_record_builder_field_suffixed(&rbf.value)),
|
|
||||||
Expr::RecordBuilder { mapper: _, fields } => fields
|
Expr::RecordBuilder { mapper: _, fields } => fields
|
||||||
.iter()
|
.iter()
|
||||||
.any(|field| is_assigned_value_suffixed(&field.value)),
|
.any(|field| is_assigned_value_suffixed(&field.value)),
|
||||||
|
@ -680,8 +676,6 @@ pub fn is_expr_suffixed(expr: &Expr) -> bool {
|
||||||
Expr::MalformedClosure => false,
|
Expr::MalformedClosure => false,
|
||||||
Expr::MalformedSuffixed(_) => false,
|
Expr::MalformedSuffixed(_) => false,
|
||||||
Expr::PrecedenceConflict(_) => false,
|
Expr::PrecedenceConflict(_) => false,
|
||||||
Expr::MultipleOldRecordBuilders(_) => false,
|
|
||||||
Expr::UnappliedOldRecordBuilder(_) => false,
|
|
||||||
Expr::EmptyRecordBuilder(_) => false,
|
Expr::EmptyRecordBuilder(_) => false,
|
||||||
Expr::SingleFieldRecordBuilder(_) => false,
|
Expr::SingleFieldRecordBuilder(_) => false,
|
||||||
Expr::OptionalFieldInRecordBuilder(_, _) => false,
|
Expr::OptionalFieldInRecordBuilder(_, _) => false,
|
||||||
|
@ -709,17 +703,6 @@ fn is_assigned_value_suffixed<'a>(value: &AssignedField<'a, Expr<'a>>) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_record_builder_field_suffixed(field: &OldRecordBuilderField<'_>) -> bool {
|
|
||||||
match field {
|
|
||||||
OldRecordBuilderField::Value(_, _, a) => is_expr_suffixed(&a.value),
|
|
||||||
OldRecordBuilderField::ApplyValue(_, _, _, a) => is_expr_suffixed(&a.value),
|
|
||||||
OldRecordBuilderField::LabelOnly(_) => false,
|
|
||||||
OldRecordBuilderField::SpaceBefore(a, _) => is_record_builder_field_suffixed(a),
|
|
||||||
OldRecordBuilderField::SpaceAfter(a, _) => is_record_builder_field_suffixed(a),
|
|
||||||
OldRecordBuilderField::Malformed(_) => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn split_around<T>(items: &[T], target: usize) -> (&[T], &[T]) {
|
pub fn split_around<T>(items: &[T], target: usize) -> (&[T], &[T]) {
|
||||||
let (before, rest) = items.split_at(target);
|
let (before, rest) = items.split_at(target);
|
||||||
let after = &rest[1..];
|
let after = &rest[1..];
|
||||||
|
@ -927,26 +910,6 @@ impl<'a, 'b> RecursiveValueDefIter<'a, 'b> {
|
||||||
expr_stack.push(&loc_expr.value);
|
expr_stack.push(&loc_expr.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OldRecordBuilder(fields) => {
|
|
||||||
expr_stack.reserve(fields.len());
|
|
||||||
for loc_record_builder_field in fields.items {
|
|
||||||
let mut current_field = loc_record_builder_field.value;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
use OldRecordBuilderField::*;
|
|
||||||
|
|
||||||
match current_field {
|
|
||||||
Value(_, _, loc_val) => break expr_stack.push(&loc_val.value),
|
|
||||||
ApplyValue(_, _, _, loc_val) => {
|
|
||||||
break expr_stack.push(&loc_val.value)
|
|
||||||
}
|
|
||||||
SpaceBefore(next_field, _) => current_field = *next_field,
|
|
||||||
SpaceAfter(next_field, _) => current_field = *next_field,
|
|
||||||
LabelOnly(_) | Malformed(_) => break,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RecordBuilder {
|
RecordBuilder {
|
||||||
mapper: map2,
|
mapper: map2,
|
||||||
fields,
|
fields,
|
||||||
|
@ -993,14 +956,18 @@ impl<'a, 'b> RecursiveValueDefIter<'a, 'b> {
|
||||||
expr_stack.push(&expr.value);
|
expr_stack.push(&expr.value);
|
||||||
}
|
}
|
||||||
UnaryOp(expr, _) => expr_stack.push(&expr.value),
|
UnaryOp(expr, _) => expr_stack.push(&expr.value),
|
||||||
If(ifs, alternate) => {
|
If {
|
||||||
expr_stack.reserve(ifs.len() * 2 + 1);
|
if_thens,
|
||||||
|
final_else,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
expr_stack.reserve(if_thens.len() * 2 + 1);
|
||||||
|
|
||||||
for (condition, consequent) in ifs.iter() {
|
for (condition, consequent) in if_thens.iter() {
|
||||||
expr_stack.push(&condition.value);
|
expr_stack.push(&condition.value);
|
||||||
expr_stack.push(&consequent.value);
|
expr_stack.push(&consequent.value);
|
||||||
}
|
}
|
||||||
expr_stack.push(&alternate.value);
|
expr_stack.push(&final_else.value);
|
||||||
}
|
}
|
||||||
When(condition, branches) => {
|
When(condition, branches) => {
|
||||||
expr_stack.reserve(branches.len() + 1);
|
expr_stack.reserve(branches.len() + 1);
|
||||||
|
@ -1027,9 +994,7 @@ impl<'a, 'b> RecursiveValueDefIter<'a, 'b> {
|
||||||
| SpaceAfter(expr, _)
|
| SpaceAfter(expr, _)
|
||||||
| ParensAround(expr) => expr_stack.push(expr),
|
| ParensAround(expr) => expr_stack.push(expr),
|
||||||
|
|
||||||
MultipleOldRecordBuilders(loc_expr)
|
EmptyRecordBuilder(loc_expr)
|
||||||
| UnappliedOldRecordBuilder(loc_expr)
|
|
||||||
| EmptyRecordBuilder(loc_expr)
|
|
||||||
| SingleFieldRecordBuilder(loc_expr)
|
| SingleFieldRecordBuilder(loc_expr)
|
||||||
| OptionalFieldInRecordBuilder(_, loc_expr) => expr_stack.push(&loc_expr.value),
|
| OptionalFieldInRecordBuilder(_, loc_expr) => expr_stack.push(&loc_expr.value),
|
||||||
|
|
||||||
|
@ -1655,30 +1620,6 @@ impl<'a, Val> AssignedField<'a, Val> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
||||||
pub enum OldRecordBuilderField<'a> {
|
|
||||||
// A field with a value, e.g. `{ name: "blah" }`
|
|
||||||
Value(Loc<&'a str>, &'a [CommentOrNewline<'a>], &'a Loc<Expr<'a>>),
|
|
||||||
|
|
||||||
// A field with a function we can apply to build part of the record, e.g. `{ name: <- apply getName }`
|
|
||||||
ApplyValue(
|
|
||||||
Loc<&'a str>,
|
|
||||||
&'a [CommentOrNewline<'a>],
|
|
||||||
&'a [CommentOrNewline<'a>],
|
|
||||||
&'a Loc<Expr<'a>>,
|
|
||||||
),
|
|
||||||
|
|
||||||
// A label with no value, e.g. `{ name }` (this is sugar for { name: name })
|
|
||||||
LabelOnly(Loc<&'a str>),
|
|
||||||
|
|
||||||
// We preserve this for the formatter; canonicalization ignores it.
|
|
||||||
SpaceBefore(&'a OldRecordBuilderField<'a>, &'a [CommentOrNewline<'a>]),
|
|
||||||
SpaceAfter(&'a OldRecordBuilderField<'a>, &'a [CommentOrNewline<'a>]),
|
|
||||||
|
|
||||||
/// A malformed assigned field, which will code gen to a runtime error
|
|
||||||
Malformed(&'a str),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub enum CommentOrNewline<'a> {
|
pub enum CommentOrNewline<'a> {
|
||||||
Newline,
|
Newline,
|
||||||
|
@ -2213,15 +2154,6 @@ impl<'a, Val> Spaceable<'a> for AssignedField<'a, Val> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Spaceable<'a> for OldRecordBuilderField<'a> {
|
|
||||||
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
|
||||||
OldRecordBuilderField::SpaceBefore(self, spaces)
|
|
||||||
}
|
|
||||||
fn after(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
|
||||||
OldRecordBuilderField::SpaceAfter(self, spaces)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Spaceable<'a> for Tag<'a> {
|
impl<'a> Spaceable<'a> for Tag<'a> {
|
||||||
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||||
Tag::SpaceBefore(self, spaces)
|
Tag::SpaceBefore(self, spaces)
|
||||||
|
@ -2524,7 +2456,6 @@ impl<'a> Malformed for Expr<'a> {
|
||||||
Record(items) => items.is_malformed(),
|
Record(items) => items.is_malformed(),
|
||||||
Tuple(items) => items.is_malformed(),
|
Tuple(items) => items.is_malformed(),
|
||||||
|
|
||||||
OldRecordBuilder(items) => items.is_malformed(),
|
|
||||||
RecordBuilder { mapper: map2, fields } => map2.is_malformed() || fields.is_malformed(),
|
RecordBuilder { mapper: map2, fields } => map2.is_malformed() || fields.is_malformed(),
|
||||||
|
|
||||||
Closure(args, body) => args.iter().any(|arg| arg.is_malformed()) || body.is_malformed(),
|
Closure(args, body) => args.iter().any(|arg| arg.is_malformed()) || body.is_malformed(),
|
||||||
|
@ -2537,7 +2468,7 @@ impl<'a> Malformed for Expr<'a> {
|
||||||
Apply(func, args, _) => func.is_malformed() || args.iter().any(|arg| arg.is_malformed()),
|
Apply(func, args, _) => func.is_malformed() || args.iter().any(|arg| arg.is_malformed()),
|
||||||
BinOps(firsts, last) => firsts.iter().any(|(expr, _)| expr.is_malformed()) || last.is_malformed(),
|
BinOps(firsts, last) => firsts.iter().any(|(expr, _)| expr.is_malformed()) || last.is_malformed(),
|
||||||
UnaryOp(expr, _) => expr.is_malformed(),
|
UnaryOp(expr, _) => expr.is_malformed(),
|
||||||
If(chain, els) => chain.iter().any(|(cond, body)| cond.is_malformed() || body.is_malformed()) || els.is_malformed(),
|
If { if_thens, final_else, ..} => if_thens.iter().any(|(cond, body)| cond.is_malformed() || body.is_malformed()) || final_else.is_malformed(),
|
||||||
When(cond, branches) => cond.is_malformed() || branches.iter().any(|branch| branch.is_malformed()),
|
When(cond, branches) => cond.is_malformed() || branches.iter().any(|branch| branch.is_malformed()),
|
||||||
|
|
||||||
SpaceBefore(expr, _) |
|
SpaceBefore(expr, _) |
|
||||||
|
@ -2548,8 +2479,6 @@ impl<'a> Malformed for Expr<'a> {
|
||||||
MalformedClosure |
|
MalformedClosure |
|
||||||
MalformedSuffixed(..) |
|
MalformedSuffixed(..) |
|
||||||
PrecedenceConflict(_) |
|
PrecedenceConflict(_) |
|
||||||
MultipleOldRecordBuilders(_) |
|
|
||||||
UnappliedOldRecordBuilder(_) |
|
|
||||||
EmptyRecordBuilder(_) |
|
EmptyRecordBuilder(_) |
|
||||||
SingleFieldRecordBuilder(_) |
|
SingleFieldRecordBuilder(_) |
|
||||||
OptionalFieldInRecordBuilder(_, _) => true,
|
OptionalFieldInRecordBuilder(_, _) => true,
|
||||||
|
@ -2629,19 +2558,6 @@ impl<'a, T: Malformed> Malformed for AssignedField<'a, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Malformed for OldRecordBuilderField<'a> {
|
|
||||||
fn is_malformed(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
OldRecordBuilderField::Value(_, _, expr)
|
|
||||||
| OldRecordBuilderField::ApplyValue(_, _, _, expr) => expr.is_malformed(),
|
|
||||||
OldRecordBuilderField::LabelOnly(_) => false,
|
|
||||||
OldRecordBuilderField::SpaceBefore(field, _)
|
|
||||||
| OldRecordBuilderField::SpaceAfter(field, _) => field.is_malformed(),
|
|
||||||
OldRecordBuilderField::Malformed(_) => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Malformed for Pattern<'a> {
|
impl<'a> Malformed for Pattern<'a> {
|
||||||
fn is_malformed(&self) -> bool {
|
fn is_malformed(&self) -> bool {
|
||||||
use Pattern::*;
|
use Pattern::*;
|
||||||
|
|
|
@ -2,8 +2,8 @@ use crate::ast::{
|
||||||
is_expr_suffixed, AssignedField, Collection, CommentOrNewline, Defs, Expr, ExtractSpaces,
|
is_expr_suffixed, AssignedField, Collection, CommentOrNewline, Defs, Expr, ExtractSpaces,
|
||||||
Implements, ImplementsAbilities, ImportAlias, ImportAsKeyword, ImportExposingKeyword,
|
Implements, ImplementsAbilities, ImportAlias, ImportAsKeyword, ImportExposingKeyword,
|
||||||
ImportedModuleName, IngestedFileAnnotation, IngestedFileImport, ModuleImport,
|
ImportedModuleName, IngestedFileAnnotation, IngestedFileImport, ModuleImport,
|
||||||
ModuleImportParams, OldRecordBuilderField, Pattern, Spaceable, Spaced, Spaces, SpacesBefore,
|
ModuleImportParams, Pattern, Spaceable, Spaced, Spaces, SpacesBefore, TryTarget,
|
||||||
TryTarget, TypeAnnotation, TypeDef, TypeHeader, ValueDef,
|
TypeAnnotation, TypeDef, TypeHeader, ValueDef,
|
||||||
};
|
};
|
||||||
use crate::blankspace::{
|
use crate::blankspace::{
|
||||||
loc_space0_e, require_newline_or_eof, space0_after_e, space0_around_ee, space0_before_e,
|
loc_space0_e, require_newline_or_eof, space0_after_e, space0_around_ee, space0_before_e,
|
||||||
|
@ -925,15 +925,11 @@ fn import_params<'a>() -> impl Parser<'a, ModuleImportParams<'a>, EImportParams<
|
||||||
.fields
|
.fields
|
||||||
.map_items_result(arena, |loc_field| {
|
.map_items_result(arena, |loc_field| {
|
||||||
match loc_field.value.to_assigned_field(arena) {
|
match loc_field.value.to_assigned_field(arena) {
|
||||||
Ok(AssignedField::IgnoredValue(_, _, _)) => Err((
|
AssignedField::IgnoredValue(_, _, _) => Err((
|
||||||
MadeProgress,
|
MadeProgress,
|
||||||
EImportParams::RecordIgnoredFieldFound(loc_field.region),
|
EImportParams::RecordIgnoredFieldFound(loc_field.region),
|
||||||
)),
|
)),
|
||||||
Ok(field) => Ok(Loc::at(loc_field.region, field)),
|
field => Ok(Loc::at(loc_field.region, field)),
|
||||||
Err(FoundApplyValue) => Err((
|
|
||||||
MadeProgress,
|
|
||||||
EImportParams::RecordApplyFound(loc_field.region),
|
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
@ -2170,7 +2166,7 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<
|
||||||
| Expr::Backpassing(_, _, _)
|
| Expr::Backpassing(_, _, _)
|
||||||
| Expr::BinOps { .. }
|
| Expr::BinOps { .. }
|
||||||
| Expr::Defs(_, _)
|
| Expr::Defs(_, _)
|
||||||
| Expr::If(_, _)
|
| Expr::If { .. }
|
||||||
| Expr::When(_, _)
|
| Expr::When(_, _)
|
||||||
| Expr::Expect(_, _)
|
| Expr::Expect(_, _)
|
||||||
| Expr::Dbg
|
| Expr::Dbg
|
||||||
|
@ -2179,8 +2175,6 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<
|
||||||
| Expr::MalformedClosure
|
| Expr::MalformedClosure
|
||||||
| Expr::MalformedSuffixed(..)
|
| Expr::MalformedSuffixed(..)
|
||||||
| Expr::PrecedenceConflict { .. }
|
| Expr::PrecedenceConflict { .. }
|
||||||
| Expr::MultipleOldRecordBuilders { .. }
|
|
||||||
| Expr::UnappliedOldRecordBuilder { .. }
|
|
||||||
| Expr::EmptyRecordBuilder(_)
|
| Expr::EmptyRecordBuilder(_)
|
||||||
| Expr::SingleFieldRecordBuilder(_)
|
| Expr::SingleFieldRecordBuilder(_)
|
||||||
| Expr::OptionalFieldInRecordBuilder(_, _)
|
| Expr::OptionalFieldInRecordBuilder(_, _)
|
||||||
|
@ -2189,7 +2183,6 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<
|
||||||
| Expr::UnaryOp(_, _)
|
| Expr::UnaryOp(_, _)
|
||||||
| Expr::TrySuffix { .. }
|
| Expr::TrySuffix { .. }
|
||||||
| Expr::Crash
|
| Expr::Crash
|
||||||
| Expr::OldRecordBuilder(..)
|
|
||||||
| Expr::RecordBuilder { .. } => return Err(()),
|
| Expr::RecordBuilder { .. } => return Err(()),
|
||||||
|
|
||||||
Expr::Str(string) => Pattern::StrLiteral(string),
|
Expr::Str(string) => Pattern::StrLiteral(string),
|
||||||
|
@ -2704,6 +2697,8 @@ fn if_expr_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EIf<
|
||||||
let (_, _, state) =
|
let (_, _, state) =
|
||||||
parser::keyword(keyword::IF, EIf::If).parse(arena, state, min_indent)?;
|
parser::keyword(keyword::IF, EIf::If).parse(arena, state, min_indent)?;
|
||||||
|
|
||||||
|
let if_indent = state.line_indent();
|
||||||
|
|
||||||
let mut branches = Vec::with_capacity_in(1, arena);
|
let mut branches = Vec::with_capacity_in(1, arena);
|
||||||
|
|
||||||
let mut loop_state = state;
|
let mut loop_state = state;
|
||||||
|
@ -2730,16 +2725,37 @@ fn if_expr_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EIf<
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let (_, else_branch, state) = parse_block(
|
let else_indent = state_final_else.line_indent();
|
||||||
|
let indented_else = else_indent > if_indent;
|
||||||
|
|
||||||
|
let min_indent = if !indented_else {
|
||||||
|
else_indent + 1
|
||||||
|
} else {
|
||||||
|
if_indent
|
||||||
|
};
|
||||||
|
|
||||||
|
let (_, loc_first_space, state_final_else) =
|
||||||
|
loc_space0_e(EIf::IndentElseBranch).parse(arena, state_final_else, min_indent)?;
|
||||||
|
|
||||||
|
let allow_defs = !loc_first_space.value.is_empty();
|
||||||
|
|
||||||
|
// use parse_block_inner so we can set min_indent
|
||||||
|
let (_, else_branch, state) = parse_block_inner(
|
||||||
options,
|
options,
|
||||||
arena,
|
arena,
|
||||||
state_final_else,
|
state_final_else,
|
||||||
true,
|
min_indent,
|
||||||
EIf::IndentElseBranch,
|
EIf::IndentElseBranch,
|
||||||
EIf::ElseBranch,
|
EIf::ElseBranch,
|
||||||
|
loc_first_space,
|
||||||
|
allow_defs,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let expr = Expr::If(branches.into_bump_slice(), arena.alloc(else_branch));
|
let expr = Expr::If {
|
||||||
|
if_thens: branches.into_bump_slice(),
|
||||||
|
final_else: arena.alloc(else_branch),
|
||||||
|
indented_else,
|
||||||
|
};
|
||||||
|
|
||||||
Ok((MadeProgress, expr, state))
|
Ok((MadeProgress, expr, state))
|
||||||
}
|
}
|
||||||
|
@ -3367,38 +3383,12 @@ pub enum RecordField<'a> {
|
||||||
LabelOnly(Loc<&'a str>),
|
LabelOnly(Loc<&'a str>),
|
||||||
SpaceBefore(&'a RecordField<'a>, &'a [CommentOrNewline<'a>]),
|
SpaceBefore(&'a RecordField<'a>, &'a [CommentOrNewline<'a>]),
|
||||||
SpaceAfter(&'a RecordField<'a>, &'a [CommentOrNewline<'a>]),
|
SpaceAfter(&'a RecordField<'a>, &'a [CommentOrNewline<'a>]),
|
||||||
ApplyValue(
|
|
||||||
Loc<&'a str>,
|
|
||||||
&'a [CommentOrNewline<'a>],
|
|
||||||
&'a [CommentOrNewline<'a>],
|
|
||||||
&'a Loc<Expr<'a>>,
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FoundApplyValue;
|
pub struct FoundApplyValue;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum NotOldBuilderFieldValue {
|
|
||||||
FoundOptionalValue,
|
|
||||||
FoundIgnoredValue,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> RecordField<'a> {
|
impl<'a> RecordField<'a> {
|
||||||
fn is_apply_value(&self) -> bool {
|
|
||||||
let mut current = self;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match current {
|
|
||||||
RecordField::ApplyValue(_, _, _, _) => break true,
|
|
||||||
RecordField::SpaceBefore(field, _) | RecordField::SpaceAfter(field, _) => {
|
|
||||||
current = *field;
|
|
||||||
}
|
|
||||||
_ => break false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_ignored_value(&self) -> bool {
|
fn is_ignored_value(&self) -> bool {
|
||||||
let mut current = self;
|
let mut current = self;
|
||||||
|
|
||||||
|
@ -3413,74 +3403,34 @@ impl<'a> RecordField<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_assigned_field(
|
pub fn to_assigned_field(self, arena: &'a Bump) -> AssignedField<'a, Expr<'a>> {
|
||||||
self,
|
|
||||||
arena: &'a Bump,
|
|
||||||
) -> Result<AssignedField<'a, Expr<'a>>, FoundApplyValue> {
|
|
||||||
use AssignedField::*;
|
use AssignedField::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
RecordField::RequiredValue(loc_label, spaces, loc_expr) => {
|
RecordField::RequiredValue(loc_label, spaces, loc_expr) => {
|
||||||
Ok(RequiredValue(loc_label, spaces, loc_expr))
|
RequiredValue(loc_label, spaces, loc_expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
RecordField::OptionalValue(loc_label, spaces, loc_expr) => {
|
RecordField::OptionalValue(loc_label, spaces, loc_expr) => {
|
||||||
Ok(OptionalValue(loc_label, spaces, loc_expr))
|
OptionalValue(loc_label, spaces, loc_expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
RecordField::IgnoredValue(loc_label, spaces, loc_expr) => {
|
RecordField::IgnoredValue(loc_label, spaces, loc_expr) => {
|
||||||
Ok(IgnoredValue(loc_label, spaces, loc_expr))
|
IgnoredValue(loc_label, spaces, loc_expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
RecordField::LabelOnly(loc_label) => Ok(LabelOnly(loc_label)),
|
RecordField::LabelOnly(loc_label) => LabelOnly(loc_label),
|
||||||
|
|
||||||
RecordField::ApplyValue(_, _, _, _) => Err(FoundApplyValue),
|
|
||||||
|
|
||||||
RecordField::SpaceBefore(field, spaces) => {
|
RecordField::SpaceBefore(field, spaces) => {
|
||||||
let assigned_field = field.to_assigned_field(arena)?;
|
let assigned_field = field.to_assigned_field(arena);
|
||||||
|
|
||||||
Ok(SpaceBefore(arena.alloc(assigned_field), spaces))
|
SpaceBefore(arena.alloc(assigned_field), spaces)
|
||||||
}
|
}
|
||||||
|
|
||||||
RecordField::SpaceAfter(field, spaces) => {
|
RecordField::SpaceAfter(field, spaces) => {
|
||||||
let assigned_field = field.to_assigned_field(arena)?;
|
let assigned_field = field.to_assigned_field(arena);
|
||||||
|
|
||||||
Ok(SpaceAfter(arena.alloc(assigned_field), spaces))
|
SpaceAfter(arena.alloc(assigned_field), spaces)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_builder_field(
|
|
||||||
self,
|
|
||||||
arena: &'a Bump,
|
|
||||||
) -> Result<OldRecordBuilderField<'a>, NotOldBuilderFieldValue> {
|
|
||||||
use OldRecordBuilderField::*;
|
|
||||||
|
|
||||||
match self {
|
|
||||||
RecordField::RequiredValue(loc_label, spaces, loc_expr) => {
|
|
||||||
Ok(Value(loc_label, spaces, loc_expr))
|
|
||||||
}
|
|
||||||
|
|
||||||
RecordField::OptionalValue(_, _, _) => Err(NotOldBuilderFieldValue::FoundOptionalValue),
|
|
||||||
|
|
||||||
RecordField::IgnoredValue(_, _, _) => Err(NotOldBuilderFieldValue::FoundIgnoredValue),
|
|
||||||
|
|
||||||
RecordField::LabelOnly(loc_label) => Ok(LabelOnly(loc_label)),
|
|
||||||
|
|
||||||
RecordField::ApplyValue(loc_label, colon_spaces, arrow_spaces, loc_expr) => {
|
|
||||||
Ok(ApplyValue(loc_label, colon_spaces, arrow_spaces, loc_expr))
|
|
||||||
}
|
|
||||||
|
|
||||||
RecordField::SpaceBefore(field, spaces) => {
|
|
||||||
let builder_field = field.to_builder_field(arena)?;
|
|
||||||
|
|
||||||
Ok(SpaceBefore(arena.alloc(builder_field), spaces))
|
|
||||||
}
|
|
||||||
|
|
||||||
RecordField::SpaceAfter(field, spaces) => {
|
|
||||||
let builder_field = field.to_builder_field(arena)?;
|
|
||||||
|
|
||||||
Ok(SpaceAfter(arena.alloc(builder_field), spaces))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3534,14 +3484,10 @@ pub fn record_field<'a>() -> impl Parser<'a, RecordField<'a>, ERecord<'a>> {
|
||||||
match field_data {
|
match field_data {
|
||||||
Either::First((loc_label, (spaces, opt_loc_val))) => {
|
Either::First((loc_label, (spaces, opt_loc_val))) => {
|
||||||
match opt_loc_val {
|
match opt_loc_val {
|
||||||
Some(Either::First((_, RecordFieldExpr::Value(loc_val)))) => {
|
Some(Either::First((_, loc_val))) => {
|
||||||
RequiredValue(loc_label, spaces, arena.alloc(loc_val))
|
RequiredValue(loc_label, spaces, arena.alloc(loc_val))
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(Either::First((_, RecordFieldExpr::Apply(arrow_spaces, loc_val)))) => {
|
|
||||||
ApplyValue(loc_label, spaces, arrow_spaces, arena.alloc(loc_val))
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(Either::Second((_, loc_val))) => {
|
Some(Either::Second((_, loc_val))) => {
|
||||||
OptionalValue(loc_label, spaces, arena.alloc(loc_val))
|
OptionalValue(loc_label, spaces, arena.alloc(loc_val))
|
||||||
}
|
}
|
||||||
|
@ -3568,34 +3514,17 @@ pub fn record_field<'a>() -> impl Parser<'a, RecordField<'a>, ERecord<'a>> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RecordFieldExpr<'a> {
|
fn record_field_expr<'a>() -> impl Parser<'a, Loc<Expr<'a>>, ERecord<'a>> {
|
||||||
Apply(&'a [CommentOrNewline<'a>], Loc<Expr<'a>>),
|
|
||||||
Value(Loc<Expr<'a>>),
|
|
||||||
}
|
|
||||||
|
|
||||||
fn record_field_expr<'a>() -> impl Parser<'a, RecordFieldExpr<'a>, ERecord<'a>> {
|
|
||||||
map_with_arena(
|
map_with_arena(
|
||||||
and(
|
and(spaces(), specialize_err_ref(ERecord::Expr, loc_expr(false))),
|
||||||
spaces(),
|
|arena: &'a bumpalo::Bump, (spaces, loc_expr)| {
|
||||||
either(
|
if spaces.is_empty() {
|
||||||
and(
|
loc_expr
|
||||||
two_bytes(b'<', b'-', ERecord::Arrow),
|
} else {
|
||||||
spaces_before(specialize_err_ref(ERecord::Expr, loc_expr(false))),
|
arena
|
||||||
),
|
.alloc(loc_expr.value)
|
||||||
specialize_err_ref(ERecord::Expr, loc_expr(false)),
|
.with_spaces_before(spaces, loc_expr.region)
|
||||||
),
|
}
|
||||||
),
|
|
||||||
|arena: &'a bumpalo::Bump, (spaces, either)| match either {
|
|
||||||
Either::First((_, loc_expr)) => RecordFieldExpr::Apply(spaces, loc_expr),
|
|
||||||
Either::Second(loc_expr) => RecordFieldExpr::Value({
|
|
||||||
if spaces.is_empty() {
|
|
||||||
loc_expr
|
|
||||||
} else {
|
|
||||||
arena
|
|
||||||
.alloc(loc_expr.value)
|
|
||||||
.with_spaces_before(spaces, loc_expr.region)
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3663,13 +3592,11 @@ fn record_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
|
||||||
record_update_help(arena, update, record.fields)
|
record_update_help(arena, update, record.fields)
|
||||||
}
|
}
|
||||||
Some((mapper, RecordHelpPrefix::Mapper)) => {
|
Some((mapper, RecordHelpPrefix::Mapper)) => {
|
||||||
new_record_builder_help(arena, mapper, record.fields)
|
record_builder_help(arena, mapper, record.fields)
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let special_field_found = record.fields.iter().find_map(|field| {
|
let special_field_found = record.fields.iter().find_map(|field| {
|
||||||
if field.value.is_apply_value() {
|
if field.value.is_ignored_value() {
|
||||||
Some(old_record_builder_help(arena, record.fields))
|
|
||||||
} else if field.value.is_ignored_value() {
|
|
||||||
Some(Err(EExpr::RecordUpdateIgnoredField(field.region)))
|
Some(Err(EExpr::RecordUpdateIgnoredField(field.region)))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -3678,7 +3605,7 @@ fn record_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
|
||||||
|
|
||||||
special_field_found.unwrap_or_else(|| {
|
special_field_found.unwrap_or_else(|| {
|
||||||
let fields = record.fields.map_items(arena, |loc_field| {
|
let fields = record.fields.map_items(arena, |loc_field| {
|
||||||
loc_field.map(|field| field.to_assigned_field(arena).unwrap())
|
loc_field.map(|field| field.to_assigned_field(arena))
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(Expr::Record(fields))
|
Ok(Expr::Record(fields))
|
||||||
|
@ -3705,14 +3632,13 @@ fn record_update_help<'a>(
|
||||||
) -> Result<Expr<'a>, EExpr<'a>> {
|
) -> Result<Expr<'a>, EExpr<'a>> {
|
||||||
let result = fields.map_items_result(arena, |loc_field| {
|
let result = fields.map_items_result(arena, |loc_field| {
|
||||||
match loc_field.value.to_assigned_field(arena) {
|
match loc_field.value.to_assigned_field(arena) {
|
||||||
Ok(AssignedField::IgnoredValue(_, _, _)) => {
|
AssignedField::IgnoredValue(_, _, _) => {
|
||||||
Err(EExpr::RecordUpdateIgnoredField(loc_field.region))
|
Err(EExpr::RecordUpdateIgnoredField(loc_field.region))
|
||||||
}
|
}
|
||||||
Ok(builder_field) => Ok(Loc {
|
builder_field => Ok(Loc {
|
||||||
region: loc_field.region,
|
region: loc_field.region,
|
||||||
value: builder_field,
|
value: builder_field,
|
||||||
}),
|
}),
|
||||||
Err(FoundApplyValue) => Err(EExpr::RecordUpdateOldBuilderField(loc_field.region)),
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -3722,19 +3648,18 @@ fn record_update_help<'a>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_record_builder_help<'a>(
|
fn record_builder_help<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
mapper: Loc<Expr<'a>>,
|
mapper: Loc<Expr<'a>>,
|
||||||
fields: Collection<'a, Loc<RecordField<'a>>>,
|
fields: Collection<'a, Loc<RecordField<'a>>>,
|
||||||
) -> Result<Expr<'a>, EExpr<'a>> {
|
) -> Result<Expr<'a>, EExpr<'a>> {
|
||||||
let result = fields.map_items_result(arena, |loc_field| {
|
let result = fields.map_items_result(arena, |loc_field| {
|
||||||
match loc_field.value.to_assigned_field(arena) {
|
let builder_field = loc_field.value.to_assigned_field(arena);
|
||||||
Ok(builder_field) => Ok(Loc {
|
|
||||||
region: loc_field.region,
|
Ok(Loc {
|
||||||
value: builder_field,
|
region: loc_field.region,
|
||||||
}),
|
value: builder_field,
|
||||||
Err(FoundApplyValue) => Err(EExpr::RecordBuilderOldBuilderField(loc_field.region)),
|
})
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
result.map(|fields| Expr::RecordBuilder {
|
result.map(|fields| Expr::RecordBuilder {
|
||||||
|
@ -3743,28 +3668,6 @@ fn new_record_builder_help<'a>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn old_record_builder_help<'a>(
|
|
||||||
arena: &'a Bump,
|
|
||||||
fields: Collection<'a, Loc<RecordField<'a>>>,
|
|
||||||
) -> Result<Expr<'a>, EExpr<'a>> {
|
|
||||||
let result = fields.map_items_result(arena, |loc_field| {
|
|
||||||
match loc_field.value.to_builder_field(arena) {
|
|
||||||
Ok(builder_field) => Ok(Loc {
|
|
||||||
region: loc_field.region,
|
|
||||||
value: builder_field,
|
|
||||||
}),
|
|
||||||
Err(NotOldBuilderFieldValue::FoundOptionalValue) => {
|
|
||||||
Err(EExpr::OptionalValueInOldRecordBuilder(loc_field.region))
|
|
||||||
}
|
|
||||||
Err(NotOldBuilderFieldValue::FoundIgnoredValue) => {
|
|
||||||
Err(EExpr::IgnoredValueInOldRecordBuilder(loc_field.region))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
result.map(Expr::OldRecordBuilder)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn apply_expr_access_chain<'a>(
|
fn apply_expr_access_chain<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
value: Expr<'a>,
|
value: Expr<'a>,
|
||||||
|
|
|
@ -1258,13 +1258,13 @@ pub struct PlatformHeader<'a> {
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
pub enum ImportsEntry<'a> {
|
pub enum ImportsEntry<'a> {
|
||||||
/// e.g. `Task` or `Task.{ Task, after }`
|
/// e.g. `Hello` or `Hello exposing [hello]` see roc-lang.org/examples/MultipleRocFiles/README.html
|
||||||
Module(
|
Module(
|
||||||
ModuleName<'a>,
|
ModuleName<'a>,
|
||||||
Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>,
|
Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>,
|
||||||
),
|
),
|
||||||
|
|
||||||
/// e.g. `pf.Task` or `pf.Task.{ after }` or `pf.{ Task.{ Task, after } }`
|
/// e.g. `pf.Stdout` or `pf.Stdout exposing [line]`
|
||||||
Package(
|
Package(
|
||||||
&'a str,
|
&'a str,
|
||||||
ModuleName<'a>,
|
ModuleName<'a>,
|
||||||
|
|
|
@ -1,905 +0,0 @@
|
||||||
use crate::ast::{Collection, CommentOrNewline, Defs, Header, Module, Spaced, Spaces};
|
|
||||||
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
|
|
||||||
use crate::expr::merge_spaces;
|
|
||||||
use crate::header::{
|
|
||||||
package_entry, package_name, AppHeader, ExposedName, ExposesKeyword, HostedHeader,
|
|
||||||
ImportsCollection, ImportsEntry, ImportsKeyword, ImportsKeywordItem, Keyword, KeywordItem,
|
|
||||||
ModuleHeader, ModuleName, ModuleParams, PackageEntry, PackageHeader, PackagesKeyword,
|
|
||||||
PlatformHeader, PlatformRequires, ProvidesKeyword, ProvidesTo, RequiresKeyword, To, ToKeyword,
|
|
||||||
TypedIdent,
|
|
||||||
};
|
|
||||||
use crate::ident::{self, lowercase_ident, unqualified_ident, UppercaseIdent};
|
|
||||||
use crate::parser::Progress::{self, *};
|
|
||||||
use crate::parser::{
|
|
||||||
and, backtrackable, byte, collection_trailing_sep_e, increment_min_indent, loc, map,
|
|
||||||
map_with_arena, optional, reset_min_indent, skip_first, skip_second, specialize_err, succeed,
|
|
||||||
two_bytes, zero_or_more, EExposes, EHeader, EImports, EPackages, EParams, EProvides, ERequires,
|
|
||||||
ETypedIdent, Parser, SourceError, SpaceProblem, SyntaxError,
|
|
||||||
};
|
|
||||||
use crate::pattern::record_pattern_fields;
|
|
||||||
use crate::state::State;
|
|
||||||
use crate::string_literal::{self, parse_str_literal};
|
|
||||||
use crate::type_annotation;
|
|
||||||
use roc_region::all::{Loc, Position, Region};
|
|
||||||
|
|
||||||
fn end_of_file<'a>() -> impl Parser<'a, (), SyntaxError<'a>> {
|
|
||||||
|_arena, state: State<'a>, _min_indent: u32| {
|
|
||||||
if state.has_reached_end() {
|
|
||||||
Ok((NoProgress, (), state))
|
|
||||||
} else {
|
|
||||||
Err((NoProgress, SyntaxError::NotEndOfFile(state.pos())))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse_module_defs<'a>(
|
|
||||||
arena: &'a bumpalo::Bump,
|
|
||||||
state: State<'a>,
|
|
||||||
defs: Defs<'a>,
|
|
||||||
) -> Result<Defs<'a>, SyntaxError<'a>> {
|
|
||||||
let min_indent = 0;
|
|
||||||
match crate::expr::parse_top_level_defs(arena, state.clone(), defs) {
|
|
||||||
Ok((_, defs, state)) => match end_of_file().parse(arena, state, min_indent) {
|
|
||||||
Ok(_) => Ok(defs),
|
|
||||||
Err((_, fail)) => Err(fail),
|
|
||||||
},
|
|
||||||
Err((_, fail)) => Err(SyntaxError::Expr(fail, state.pos())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse_header<'a>(
|
|
||||||
arena: &'a bumpalo::Bump,
|
|
||||||
state: State<'a>,
|
|
||||||
) -> Result<(Module<'a>, State<'a>), SourceError<'a, EHeader<'a>>> {
|
|
||||||
let min_indent = 0;
|
|
||||||
match header().parse(arena, state.clone(), min_indent) {
|
|
||||||
Ok((_, module, state)) => Ok((module, state)),
|
|
||||||
Err((_, fail)) => Err(SourceError::new(fail, &state)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn header<'a>() -> impl Parser<'a, Module<'a>, EHeader<'a>> {
|
|
||||||
use crate::parser::keyword;
|
|
||||||
|
|
||||||
record!(Module {
|
|
||||||
comments: space0_e(EHeader::IndentStart),
|
|
||||||
header: one_of![
|
|
||||||
map(
|
|
||||||
skip_first(
|
|
||||||
keyword("module", EHeader::Start),
|
|
||||||
increment_min_indent(module_header())
|
|
||||||
),
|
|
||||||
Header::Module
|
|
||||||
),
|
|
||||||
map(
|
|
||||||
skip_first(
|
|
||||||
keyword("interface", EHeader::Start),
|
|
||||||
increment_min_indent(interface_header())
|
|
||||||
),
|
|
||||||
Header::Module
|
|
||||||
),
|
|
||||||
map(
|
|
||||||
skip_first(
|
|
||||||
keyword("app", EHeader::Start),
|
|
||||||
increment_min_indent(one_of![app_header(), old_app_header()])
|
|
||||||
),
|
|
||||||
Header::App
|
|
||||||
),
|
|
||||||
map(
|
|
||||||
skip_first(
|
|
||||||
keyword("package", EHeader::Start),
|
|
||||||
increment_min_indent(one_of![package_header(), old_package_header()])
|
|
||||||
),
|
|
||||||
Header::Package
|
|
||||||
),
|
|
||||||
map(
|
|
||||||
skip_first(
|
|
||||||
keyword("platform", EHeader::Start),
|
|
||||||
increment_min_indent(platform_header())
|
|
||||||
),
|
|
||||||
Header::Platform
|
|
||||||
),
|
|
||||||
map(
|
|
||||||
skip_first(
|
|
||||||
keyword("hosted", EHeader::Start),
|
|
||||||
increment_min_indent(hosted_header())
|
|
||||||
),
|
|
||||||
Header::Hosted
|
|
||||||
),
|
|
||||||
]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn module_header<'a>() -> impl Parser<'a, ModuleHeader<'a>, EHeader<'a>> {
|
|
||||||
record!(ModuleHeader {
|
|
||||||
after_keyword: space0_e(EHeader::IndentStart),
|
|
||||||
params: optional(specialize_err(EHeader::Params, module_params())),
|
|
||||||
exposes: specialize_err(EHeader::Exposes, exposes_list()),
|
|
||||||
interface_imports: succeed(None)
|
|
||||||
})
|
|
||||||
.trace("module_header")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn module_params<'a>() -> impl Parser<'a, ModuleParams<'a>, EParams<'a>> {
|
|
||||||
record!(ModuleParams {
|
|
||||||
params: specialize_err(EParams::Pattern, record_pattern_fields()),
|
|
||||||
before_arrow: skip_second(
|
|
||||||
space0_e(EParams::BeforeArrow),
|
|
||||||
loc(two_bytes(b'-', b'>', EParams::Arrow))
|
|
||||||
),
|
|
||||||
after_arrow: space0_e(EParams::AfterArrow),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO does this need to be a macro?
|
|
||||||
macro_rules! merge_n_spaces {
|
|
||||||
($arena:expr, $($slice:expr),*) => {
|
|
||||||
{
|
|
||||||
let mut merged = bumpalo::collections::Vec::with_capacity_in(0 $(+ $slice.len())*, $arena);
|
|
||||||
$(merged.extend_from_slice($slice);)*
|
|
||||||
merged.into_bump_slice()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse old interface headers so we can format them into module headers
|
|
||||||
#[inline(always)]
|
|
||||||
fn interface_header<'a>() -> impl Parser<'a, ModuleHeader<'a>, EHeader<'a>> {
|
|
||||||
let after_keyword = map_with_arena(
|
|
||||||
and(
|
|
||||||
skip_second(
|
|
||||||
space0_e(EHeader::IndentStart),
|
|
||||||
loc(module_name_help(EHeader::ModuleName)),
|
|
||||||
),
|
|
||||||
specialize_err(EHeader::Exposes, exposes_kw()),
|
|
||||||
),
|
|
||||||
|arena: &'a bumpalo::Bump,
|
|
||||||
(before_name, kw): (&'a [CommentOrNewline<'a>], Spaces<'a, ExposesKeyword>)| {
|
|
||||||
merge_n_spaces!(arena, before_name, kw.before, kw.after)
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
record!(ModuleHeader {
|
|
||||||
after_keyword: after_keyword,
|
|
||||||
params: succeed(None),
|
|
||||||
exposes: specialize_err(EHeader::Exposes, exposes_list()).trace("exposes_list"),
|
|
||||||
interface_imports: map(
|
|
||||||
specialize_err(EHeader::Imports, imports()),
|
|
||||||
imports_none_if_empty
|
|
||||||
)
|
|
||||||
.trace("imports"),
|
|
||||||
})
|
|
||||||
.trace("interface_header")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn imports_none_if_empty(value: ImportsKeywordItem<'_>) -> Option<ImportsKeywordItem<'_>> {
|
|
||||||
if value.item.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn hosted_header<'a>() -> impl Parser<'a, HostedHeader<'a>, EHeader<'a>> {
|
|
||||||
record!(HostedHeader {
|
|
||||||
before_name: space0_e(EHeader::IndentStart),
|
|
||||||
name: loc(module_name_help(EHeader::ModuleName)),
|
|
||||||
exposes: specialize_err(EHeader::Exposes, exposes_values_kw()),
|
|
||||||
imports: specialize_err(EHeader::Imports, imports()),
|
|
||||||
})
|
|
||||||
.trace("hosted_header")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn chomp_module_name(buffer: &[u8]) -> Result<&str, Progress> {
|
|
||||||
use encode_unicode::CharExt;
|
|
||||||
|
|
||||||
let mut chomped = 0;
|
|
||||||
|
|
||||||
if let Ok((first_letter, width)) = char::from_utf8_slice_start(&buffer[chomped..]) {
|
|
||||||
if first_letter.is_uppercase() {
|
|
||||||
chomped += width;
|
|
||||||
} else {
|
|
||||||
return Err(Progress::NoProgress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while let Ok((ch, width)) = char::from_utf8_slice_start(&buffer[chomped..]) {
|
|
||||||
// After the first character, only these are allowed:
|
|
||||||
//
|
|
||||||
// * Unicode alphabetic chars - you might include `鹏` if that's clear to your readers
|
|
||||||
// * ASCII digits - e.g. `1` but not `¾`, both of which pass .is_numeric()
|
|
||||||
// * A '.' separating module parts
|
|
||||||
if ch.is_alphabetic() || ch.is_ascii_digit() {
|
|
||||||
chomped += width;
|
|
||||||
} else if ch == '.' {
|
|
||||||
chomped += width;
|
|
||||||
|
|
||||||
if let Ok((first_letter, width)) = char::from_utf8_slice_start(&buffer[chomped..]) {
|
|
||||||
if first_letter.is_uppercase() {
|
|
||||||
chomped += width;
|
|
||||||
} else if first_letter == '{' {
|
|
||||||
// the .{ starting a `Foo.{ bar, baz }` importing clauses
|
|
||||||
chomped -= width;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
return Err(Progress::MadeProgress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// we're done
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let name = unsafe { std::str::from_utf8_unchecked(&buffer[..chomped]) };
|
|
||||||
|
|
||||||
Ok(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn module_name<'a>() -> impl Parser<'a, ModuleName<'a>, ()> {
|
|
||||||
|_, mut state: State<'a>, _min_indent: u32| match chomp_module_name(state.bytes()) {
|
|
||||||
Ok(name) => {
|
|
||||||
let width = name.len();
|
|
||||||
state = state.advance(width);
|
|
||||||
|
|
||||||
Ok((MadeProgress, ModuleName::new(name), state))
|
|
||||||
}
|
|
||||||
Err(progress) => Err((progress, ())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn app_header<'a>() -> impl Parser<'a, AppHeader<'a>, EHeader<'a>> {
|
|
||||||
record!(AppHeader {
|
|
||||||
before_provides: space0_e(EHeader::IndentStart),
|
|
||||||
provides: specialize_err(EHeader::Exposes, exposes_list()),
|
|
||||||
before_packages: space0_e(EHeader::IndentStart),
|
|
||||||
packages: specialize_err(EHeader::Packages, loc(packages_collection())),
|
|
||||||
old_imports: succeed(None),
|
|
||||||
old_provides_to_new_package: succeed(None),
|
|
||||||
})
|
|
||||||
.trace("app_header")
|
|
||||||
}
|
|
||||||
|
|
||||||
struct OldAppHeader<'a> {
|
|
||||||
pub before_name: &'a [CommentOrNewline<'a>],
|
|
||||||
pub packages: Option<Loc<OldAppPackages<'a>>>,
|
|
||||||
pub imports: Option<KeywordItem<'a, ImportsKeyword, ImportsCollection<'a>>>,
|
|
||||||
pub provides: ProvidesTo<'a>,
|
|
||||||
}
|
|
||||||
|
|
||||||
type OldAppPackages<'a> =
|
|
||||||
KeywordItem<'a, PackagesKeyword, Collection<'a, Loc<Spaced<'a, PackageEntry<'a>>>>>;
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn old_app_header<'a>() -> impl Parser<'a, AppHeader<'a>, EHeader<'a>> {
|
|
||||||
let old = record!(OldAppHeader {
|
|
||||||
before_name: skip_second(
|
|
||||||
space0_e(EHeader::IndentStart),
|
|
||||||
loc(crate::parser::specialize_err(
|
|
||||||
EHeader::AppName,
|
|
||||||
string_literal::parse_str_literal()
|
|
||||||
))
|
|
||||||
),
|
|
||||||
packages: optional(specialize_err(EHeader::Packages, loc(packages()))),
|
|
||||||
imports: optional(specialize_err(EHeader::Imports, imports())),
|
|
||||||
provides: specialize_err(EHeader::Provides, provides_to()),
|
|
||||||
});
|
|
||||||
|
|
||||||
map_with_arena(old, |arena: &'a bumpalo::Bump, old: OldAppHeader<'a>| {
|
|
||||||
let mut before_packages: &'a [CommentOrNewline] = &[];
|
|
||||||
|
|
||||||
let packages = match old.packages {
|
|
||||||
Some(packages) => {
|
|
||||||
before_packages = merge_spaces(
|
|
||||||
arena,
|
|
||||||
packages.value.keyword.before,
|
|
||||||
packages.value.keyword.after,
|
|
||||||
);
|
|
||||||
|
|
||||||
if let To::ExistingPackage(platform_shorthand) = old.provides.to.value {
|
|
||||||
packages.map(|coll| {
|
|
||||||
coll.item.map_items(arena, |loc_spaced_pkg| {
|
|
||||||
if loc_spaced_pkg.value.item().shorthand == platform_shorthand {
|
|
||||||
loc_spaced_pkg.map(|spaced_pkg| {
|
|
||||||
spaced_pkg.map(arena, |pkg| {
|
|
||||||
let mut new_pkg = *pkg;
|
|
||||||
new_pkg.platform_marker = Some(merge_spaces(
|
|
||||||
arena,
|
|
||||||
old.provides.to_keyword.before,
|
|
||||||
old.provides.to_keyword.after,
|
|
||||||
));
|
|
||||||
new_pkg
|
|
||||||
})
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
*loc_spaced_pkg
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
packages.map(|kw| kw.item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => Loc {
|
|
||||||
region: Region::zero(),
|
|
||||||
value: Collection::empty(),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let provides = match old.provides.types {
|
|
||||||
Some(types) => {
|
|
||||||
let mut combined_items = bumpalo::collections::Vec::with_capacity_in(
|
|
||||||
old.provides.entries.items.len() + types.items.len(),
|
|
||||||
arena,
|
|
||||||
);
|
|
||||||
|
|
||||||
combined_items.extend_from_slice(old.provides.entries.items);
|
|
||||||
|
|
||||||
for loc_spaced_type_ident in types.items {
|
|
||||||
combined_items.push(loc_spaced_type_ident.map(|spaced_type_ident| {
|
|
||||||
spaced_type_ident.map(arena, |type_ident| {
|
|
||||||
ExposedName::new(From::from(*type_ident))
|
|
||||||
})
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
let value_comments = old.provides.entries.final_comments();
|
|
||||||
let type_comments = types.final_comments();
|
|
||||||
|
|
||||||
let mut combined_comments = bumpalo::collections::Vec::with_capacity_in(
|
|
||||||
value_comments.len() + type_comments.len(),
|
|
||||||
arena,
|
|
||||||
);
|
|
||||||
combined_comments.extend_from_slice(value_comments);
|
|
||||||
combined_comments.extend_from_slice(type_comments);
|
|
||||||
|
|
||||||
Collection::with_items_and_comments(
|
|
||||||
arena,
|
|
||||||
combined_items.into_bump_slice(),
|
|
||||||
combined_comments.into_bump_slice(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
None => old.provides.entries,
|
|
||||||
};
|
|
||||||
|
|
||||||
AppHeader {
|
|
||||||
before_provides: merge_spaces(
|
|
||||||
arena,
|
|
||||||
old.before_name,
|
|
||||||
old.provides.provides_keyword.before,
|
|
||||||
),
|
|
||||||
provides,
|
|
||||||
before_packages: merge_spaces(
|
|
||||||
arena,
|
|
||||||
before_packages,
|
|
||||||
old.provides.provides_keyword.after,
|
|
||||||
),
|
|
||||||
packages,
|
|
||||||
old_imports: old.imports.and_then(imports_none_if_empty),
|
|
||||||
old_provides_to_new_package: match old.provides.to.value {
|
|
||||||
To::NewPackage(new_pkg) => Some(new_pkg),
|
|
||||||
To::ExistingPackage(_) => None,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn package_header<'a>() -> impl Parser<'a, PackageHeader<'a>, EHeader<'a>> {
|
|
||||||
record!(PackageHeader {
|
|
||||||
before_exposes: space0_e(EHeader::IndentStart),
|
|
||||||
exposes: specialize_err(EHeader::Exposes, exposes_module_collection()),
|
|
||||||
before_packages: space0_e(EHeader::IndentStart),
|
|
||||||
packages: specialize_err(EHeader::Packages, loc(packages_collection())),
|
|
||||||
})
|
|
||||||
.trace("package_header")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
struct OldPackageHeader<'a> {
|
|
||||||
before_name: &'a [CommentOrNewline<'a>],
|
|
||||||
exposes: KeywordItem<'a, ExposesKeyword, Collection<'a, Loc<Spaced<'a, ModuleName<'a>>>>>,
|
|
||||||
packages:
|
|
||||||
Loc<KeywordItem<'a, PackagesKeyword, Collection<'a, Loc<Spaced<'a, PackageEntry<'a>>>>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn old_package_header<'a>() -> impl Parser<'a, PackageHeader<'a>, EHeader<'a>> {
|
|
||||||
map_with_arena(
|
|
||||||
record!(OldPackageHeader {
|
|
||||||
before_name: skip_second(
|
|
||||||
space0_e(EHeader::IndentStart),
|
|
||||||
specialize_err(EHeader::PackageName, package_name())
|
|
||||||
),
|
|
||||||
exposes: specialize_err(EHeader::Exposes, exposes_modules()),
|
|
||||||
packages: specialize_err(EHeader::Packages, loc(packages())),
|
|
||||||
}),
|
|
||||||
|arena: &'a bumpalo::Bump, old: OldPackageHeader<'a>| {
|
|
||||||
let before_exposes = merge_n_spaces!(
|
|
||||||
arena,
|
|
||||||
old.before_name,
|
|
||||||
old.exposes.keyword.before,
|
|
||||||
old.exposes.keyword.after
|
|
||||||
);
|
|
||||||
let before_packages = merge_spaces(
|
|
||||||
arena,
|
|
||||||
old.packages.value.keyword.before,
|
|
||||||
old.packages.value.keyword.after,
|
|
||||||
);
|
|
||||||
|
|
||||||
PackageHeader {
|
|
||||||
before_exposes,
|
|
||||||
exposes: old.exposes.item,
|
|
||||||
before_packages,
|
|
||||||
packages: old.packages.map(|kw| kw.item),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.trace("old_package_header")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn platform_header<'a>() -> impl Parser<'a, PlatformHeader<'a>, EHeader<'a>> {
|
|
||||||
record!(PlatformHeader {
|
|
||||||
before_name: space0_e(EHeader::IndentStart),
|
|
||||||
name: loc(specialize_err(EHeader::PlatformName, package_name())),
|
|
||||||
requires: specialize_err(EHeader::Requires, requires()),
|
|
||||||
exposes: specialize_err(EHeader::Exposes, exposes_modules()),
|
|
||||||
packages: specialize_err(EHeader::Packages, packages()),
|
|
||||||
imports: specialize_err(EHeader::Imports, imports()),
|
|
||||||
provides: specialize_err(EHeader::Provides, provides_exposed()),
|
|
||||||
})
|
|
||||||
.trace("platform_header")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn provides_to_package<'a>() -> impl Parser<'a, To<'a>, EProvides<'a>> {
|
|
||||||
one_of![
|
|
||||||
specialize_err(
|
|
||||||
|_, pos| EProvides::Identifier(pos),
|
|
||||||
map(lowercase_ident(), To::ExistingPackage)
|
|
||||||
),
|
|
||||||
specialize_err(EProvides::Package, map(package_name(), To::NewPackage))
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn provides_to<'a>() -> impl Parser<'a, ProvidesTo<'a>, EProvides<'a>> {
|
|
||||||
record!(ProvidesTo {
|
|
||||||
provides_keyword: spaces_around_keyword(
|
|
||||||
ProvidesKeyword,
|
|
||||||
EProvides::Provides,
|
|
||||||
EProvides::IndentProvides,
|
|
||||||
EProvides::IndentListStart
|
|
||||||
),
|
|
||||||
entries: collection_trailing_sep_e(
|
|
||||||
byte(b'[', EProvides::ListStart),
|
|
||||||
exposes_entry(EProvides::Identifier),
|
|
||||||
byte(b',', EProvides::ListEnd),
|
|
||||||
byte(b']', EProvides::ListEnd),
|
|
||||||
Spaced::SpaceBefore
|
|
||||||
),
|
|
||||||
types: optional(backtrackable(provides_types())),
|
|
||||||
to_keyword: spaces_around_keyword(
|
|
||||||
ToKeyword,
|
|
||||||
EProvides::To,
|
|
||||||
EProvides::IndentTo,
|
|
||||||
EProvides::IndentListStart
|
|
||||||
),
|
|
||||||
to: loc(provides_to_package()),
|
|
||||||
})
|
|
||||||
.trace("provides_to")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn provides_exposed<'a>() -> impl Parser<
|
|
||||||
'a,
|
|
||||||
KeywordItem<'a, ProvidesKeyword, Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>>,
|
|
||||||
EProvides<'a>,
|
|
||||||
> {
|
|
||||||
record!(KeywordItem {
|
|
||||||
keyword: spaces_around_keyword(
|
|
||||||
ProvidesKeyword,
|
|
||||||
EProvides::Provides,
|
|
||||||
EProvides::IndentProvides,
|
|
||||||
EProvides::IndentListStart
|
|
||||||
),
|
|
||||||
item: collection_trailing_sep_e(
|
|
||||||
byte(b'[', EProvides::ListStart),
|
|
||||||
exposes_entry(EProvides::Identifier),
|
|
||||||
byte(b',', EProvides::ListEnd),
|
|
||||||
byte(b']', EProvides::ListEnd),
|
|
||||||
Spaced::SpaceBefore
|
|
||||||
),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn provides_types<'a>(
|
|
||||||
) -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, UppercaseIdent<'a>>>>, EProvides<'a>> {
|
|
||||||
skip_first(
|
|
||||||
// We only support spaces here, not newlines, because this is not intended
|
|
||||||
// to be the design forever. Someday it will hopefully work like Elm,
|
|
||||||
// where platform authors can provide functions like Browser.sandbox which
|
|
||||||
// present an API based on ordinary-looking type variables.
|
|
||||||
zero_or_more(byte(
|
|
||||||
b' ',
|
|
||||||
// HACK: If this errors, EProvides::Provides is not an accurate reflection
|
|
||||||
// of what went wrong. However, this is both skipped and zero_or_more,
|
|
||||||
// so this error should never be visible to anyone in practice!
|
|
||||||
EProvides::Provides,
|
|
||||||
)),
|
|
||||||
collection_trailing_sep_e(
|
|
||||||
byte(b'{', EProvides::ListStart),
|
|
||||||
provides_type_entry(EProvides::Identifier),
|
|
||||||
byte(b',', EProvides::ListEnd),
|
|
||||||
byte(b'}', EProvides::ListEnd),
|
|
||||||
Spaced::SpaceBefore,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn provides_type_entry<'a, F, E>(
|
|
||||||
to_expectation: F,
|
|
||||||
) -> impl Parser<'a, Loc<Spaced<'a, UppercaseIdent<'a>>>, E>
|
|
||||||
where
|
|
||||||
F: Fn(Position) -> E,
|
|
||||||
F: Copy,
|
|
||||||
E: 'a,
|
|
||||||
{
|
|
||||||
loc(map(
|
|
||||||
specialize_err(move |_, pos| to_expectation(pos), ident::uppercase()),
|
|
||||||
Spaced::Item,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn exposes_entry<'a, F, E>(
|
|
||||||
to_expectation: F,
|
|
||||||
) -> impl Parser<'a, Loc<Spaced<'a, ExposedName<'a>>>, E>
|
|
||||||
where
|
|
||||||
F: Fn(Position) -> E,
|
|
||||||
F: Copy,
|
|
||||||
E: 'a,
|
|
||||||
{
|
|
||||||
loc(map(
|
|
||||||
specialize_err(move |_, pos| to_expectation(pos), unqualified_ident()),
|
|
||||||
|n| Spaced::Item(ExposedName::new(n)),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn requires<'a>(
|
|
||||||
) -> impl Parser<'a, KeywordItem<'a, RequiresKeyword, PlatformRequires<'a>>, ERequires<'a>> {
|
|
||||||
record!(KeywordItem {
|
|
||||||
keyword: spaces_around_keyword(
|
|
||||||
RequiresKeyword,
|
|
||||||
ERequires::Requires,
|
|
||||||
ERequires::IndentRequires,
|
|
||||||
ERequires::IndentListStart
|
|
||||||
),
|
|
||||||
item: platform_requires(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn platform_requires<'a>() -> impl Parser<'a, PlatformRequires<'a>, ERequires<'a>> {
|
|
||||||
record!(PlatformRequires {
|
|
||||||
rigids: skip_second(requires_rigids(), space0_e(ERequires::ListStart)),
|
|
||||||
signature: requires_typed_ident()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn requires_rigids<'a>(
|
|
||||||
) -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, UppercaseIdent<'a>>>>, ERequires<'a>> {
|
|
||||||
collection_trailing_sep_e(
|
|
||||||
byte(b'{', ERequires::ListStart),
|
|
||||||
specialize_err(
|
|
||||||
|_, pos| ERequires::Rigid(pos),
|
|
||||||
loc(map(ident::uppercase(), Spaced::Item)),
|
|
||||||
),
|
|
||||||
byte(b',', ERequires::ListEnd),
|
|
||||||
byte(b'}', ERequires::ListEnd),
|
|
||||||
Spaced::SpaceBefore,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn requires_typed_ident<'a>() -> impl Parser<'a, Loc<Spaced<'a, TypedIdent<'a>>>, ERequires<'a>> {
|
|
||||||
skip_first(
|
|
||||||
byte(b'{', ERequires::ListStart),
|
|
||||||
skip_second(
|
|
||||||
reset_min_indent(space0_around_ee(
|
|
||||||
specialize_err(ERequires::TypedIdent, loc(typed_ident())),
|
|
||||||
ERequires::ListStart,
|
|
||||||
ERequires::ListEnd,
|
|
||||||
)),
|
|
||||||
byte(b'}', ERequires::ListStart),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn exposes_values_kw<'a>() -> impl Parser<
|
|
||||||
'a,
|
|
||||||
KeywordItem<'a, ExposesKeyword, Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>>,
|
|
||||||
EExposes,
|
|
||||||
> {
|
|
||||||
record!(KeywordItem {
|
|
||||||
keyword: exposes_kw(),
|
|
||||||
item: exposes_list()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn exposes_kw<'a>() -> impl Parser<'a, Spaces<'a, ExposesKeyword>, EExposes> {
|
|
||||||
spaces_around_keyword(
|
|
||||||
ExposesKeyword,
|
|
||||||
EExposes::Exposes,
|
|
||||||
EExposes::IndentExposes,
|
|
||||||
EExposes::IndentListStart,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn exposes_list<'a>() -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>, EExposes>
|
|
||||||
{
|
|
||||||
collection_trailing_sep_e(
|
|
||||||
byte(b'[', EExposes::ListStart),
|
|
||||||
exposes_entry(EExposes::Identifier),
|
|
||||||
byte(b',', EExposes::ListEnd),
|
|
||||||
byte(b']', EExposes::ListEnd),
|
|
||||||
Spaced::SpaceBefore,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn spaces_around_keyword<'a, K: Keyword, E>(
|
|
||||||
keyword_item: K,
|
|
||||||
expectation: fn(Position) -> E,
|
|
||||||
indent_problem1: fn(Position) -> E,
|
|
||||||
indent_problem2: fn(Position) -> E,
|
|
||||||
) -> impl Parser<'a, Spaces<'a, K>, E>
|
|
||||||
where
|
|
||||||
E: 'a + SpaceProblem,
|
|
||||||
{
|
|
||||||
map(
|
|
||||||
and(
|
|
||||||
skip_second(
|
|
||||||
// parse any leading space before the keyword
|
|
||||||
backtrackable(space0_e(indent_problem1)),
|
|
||||||
// parse the keyword
|
|
||||||
crate::parser::keyword(K::KEYWORD, expectation),
|
|
||||||
),
|
|
||||||
// parse the trailing space
|
|
||||||
space0_e(indent_problem2),
|
|
||||||
),
|
|
||||||
move |(before, after)| Spaces {
|
|
||||||
before,
|
|
||||||
item: keyword_item,
|
|
||||||
after,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn exposes_modules<'a>() -> impl Parser<
|
|
||||||
'a,
|
|
||||||
KeywordItem<'a, ExposesKeyword, Collection<'a, Loc<Spaced<'a, ModuleName<'a>>>>>,
|
|
||||||
EExposes,
|
|
||||||
> {
|
|
||||||
record!(KeywordItem {
|
|
||||||
keyword: spaces_around_keyword(
|
|
||||||
ExposesKeyword,
|
|
||||||
EExposes::Exposes,
|
|
||||||
EExposes::IndentExposes,
|
|
||||||
EExposes::IndentListStart
|
|
||||||
),
|
|
||||||
item: exposes_module_collection(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn exposes_module_collection<'a>(
|
|
||||||
) -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, ModuleName<'a>>>>, EExposes> {
|
|
||||||
collection_trailing_sep_e(
|
|
||||||
byte(b'[', EExposes::ListStart),
|
|
||||||
exposes_module(EExposes::Identifier),
|
|
||||||
byte(b',', EExposes::ListEnd),
|
|
||||||
byte(b']', EExposes::ListEnd),
|
|
||||||
Spaced::SpaceBefore,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn exposes_module<'a, F, E>(
|
|
||||||
to_expectation: F,
|
|
||||||
) -> impl Parser<'a, Loc<Spaced<'a, ModuleName<'a>>>, E>
|
|
||||||
where
|
|
||||||
F: Fn(Position) -> E,
|
|
||||||
F: Copy,
|
|
||||||
E: 'a,
|
|
||||||
{
|
|
||||||
loc(map(
|
|
||||||
specialize_err(move |_, pos| to_expectation(pos), module_name()),
|
|
||||||
Spaced::Item,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn packages<'a>() -> impl Parser<
|
|
||||||
'a,
|
|
||||||
KeywordItem<'a, PackagesKeyword, Collection<'a, Loc<Spaced<'a, PackageEntry<'a>>>>>,
|
|
||||||
EPackages<'a>,
|
|
||||||
> {
|
|
||||||
record!(KeywordItem {
|
|
||||||
keyword: packages_kw(),
|
|
||||||
item: packages_collection()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn packages_kw<'a>() -> impl Parser<'a, Spaces<'a, PackagesKeyword>, EPackages<'a>> {
|
|
||||||
spaces_around_keyword(
|
|
||||||
PackagesKeyword,
|
|
||||||
EPackages::Packages,
|
|
||||||
EPackages::IndentPackages,
|
|
||||||
EPackages::IndentListStart,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn packages_collection<'a>(
|
|
||||||
) -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, PackageEntry<'a>>>>, EPackages<'a>> {
|
|
||||||
collection_trailing_sep_e(
|
|
||||||
byte(b'{', EPackages::ListStart),
|
|
||||||
specialize_err(EPackages::PackageEntry, loc(package_entry())),
|
|
||||||
byte(b',', EPackages::ListEnd),
|
|
||||||
byte(b'}', EPackages::ListEnd),
|
|
||||||
Spaced::SpaceBefore,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn imports<'a>() -> impl Parser<
|
|
||||||
'a,
|
|
||||||
KeywordItem<'a, ImportsKeyword, Collection<'a, Loc<Spaced<'a, ImportsEntry<'a>>>>>,
|
|
||||||
EImports,
|
|
||||||
> {
|
|
||||||
record!(KeywordItem {
|
|
||||||
keyword: spaces_around_keyword(
|
|
||||||
ImportsKeyword,
|
|
||||||
EImports::Imports,
|
|
||||||
EImports::IndentImports,
|
|
||||||
EImports::IndentListStart
|
|
||||||
),
|
|
||||||
item: collection_trailing_sep_e(
|
|
||||||
byte(b'[', EImports::ListStart),
|
|
||||||
loc(imports_entry()),
|
|
||||||
byte(b',', EImports::ListEnd),
|
|
||||||
byte(b']', EImports::ListEnd),
|
|
||||||
Spaced::SpaceBefore
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.trace("imports")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn typed_ident<'a>() -> impl Parser<'a, Spaced<'a, TypedIdent<'a>>, ETypedIdent<'a>> {
|
|
||||||
// e.g.
|
|
||||||
//
|
|
||||||
// printLine : Str -> Task {} *
|
|
||||||
map(
|
|
||||||
and(
|
|
||||||
and(
|
|
||||||
loc(specialize_err(
|
|
||||||
|_, pos| ETypedIdent::Identifier(pos),
|
|
||||||
lowercase_ident(),
|
|
||||||
)),
|
|
||||||
space0_e(ETypedIdent::IndentHasType),
|
|
||||||
),
|
|
||||||
skip_first(
|
|
||||||
byte(b':', ETypedIdent::HasType),
|
|
||||||
space0_before_e(
|
|
||||||
specialize_err(
|
|
||||||
ETypedIdent::Type,
|
|
||||||
reset_min_indent(type_annotation::located(true)),
|
|
||||||
),
|
|
||||||
ETypedIdent::IndentType,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|((ident, spaces_before_colon), ann)| {
|
|
||||||
Spaced::Item(TypedIdent {
|
|
||||||
ident,
|
|
||||||
spaces_before_colon,
|
|
||||||
ann,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn shortname<'a>() -> impl Parser<'a, &'a str, EImports> {
|
|
||||||
specialize_err(|_, pos| EImports::Shorthand(pos), lowercase_ident())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn module_name_help<'a, F, E>(to_expectation: F) -> impl Parser<'a, ModuleName<'a>, E>
|
|
||||||
where
|
|
||||||
F: Fn(Position) -> E,
|
|
||||||
E: 'a,
|
|
||||||
F: 'a,
|
|
||||||
{
|
|
||||||
specialize_err(move |_, pos| to_expectation(pos), module_name())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn imports_entry<'a>() -> impl Parser<'a, Spaced<'a, ImportsEntry<'a>>, EImports> {
|
|
||||||
type Temp<'a> = (
|
|
||||||
(Option<&'a str>, ModuleName<'a>),
|
|
||||||
Option<Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>>,
|
|
||||||
);
|
|
||||||
|
|
||||||
let spaced_import = |((opt_shortname, module_name), opt_values): Temp<'a>| {
|
|
||||||
let exposed_values = opt_values.unwrap_or_else(Collection::empty);
|
|
||||||
|
|
||||||
let entry = match opt_shortname {
|
|
||||||
Some(shortname) => ImportsEntry::Package(shortname, module_name, exposed_values),
|
|
||||||
|
|
||||||
None => ImportsEntry::Module(module_name, exposed_values),
|
|
||||||
};
|
|
||||||
|
|
||||||
Spaced::Item(entry)
|
|
||||||
};
|
|
||||||
|
|
||||||
one_of!(
|
|
||||||
map(
|
|
||||||
and(
|
|
||||||
and(
|
|
||||||
// e.g. `pf.`
|
|
||||||
optional(backtrackable(skip_second(
|
|
||||||
shortname(),
|
|
||||||
byte(b'.', EImports::ShorthandDot)
|
|
||||||
))),
|
|
||||||
// e.g. `Task`
|
|
||||||
module_name_help(EImports::ModuleName)
|
|
||||||
),
|
|
||||||
// e.g. `.{ Task, after}`
|
|
||||||
optional(skip_first(
|
|
||||||
byte(b'.', EImports::ExposingDot),
|
|
||||||
collection_trailing_sep_e(
|
|
||||||
byte(b'{', EImports::SetStart),
|
|
||||||
exposes_entry(EImports::Identifier),
|
|
||||||
byte(b',', EImports::SetEnd),
|
|
||||||
byte(b'}', EImports::SetEnd),
|
|
||||||
Spaced::SpaceBefore
|
|
||||||
)
|
|
||||||
))
|
|
||||||
),
|
|
||||||
spaced_import
|
|
||||||
)
|
|
||||||
.trace("normal_import"),
|
|
||||||
map(
|
|
||||||
and(
|
|
||||||
and(
|
|
||||||
// e.g. "filename"
|
|
||||||
// TODO: str literal allows for multiline strings. We probably don't want that for file names.
|
|
||||||
specialize_err(|_, pos| EImports::StrLiteral(pos), parse_str_literal()),
|
|
||||||
// e.g. as
|
|
||||||
and(
|
|
||||||
and(
|
|
||||||
space0_e(EImports::AsKeyword),
|
|
||||||
two_bytes(b'a', b's', EImports::AsKeyword)
|
|
||||||
),
|
|
||||||
space0_e(EImports::AsKeyword)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
// e.g. file : Str
|
|
||||||
specialize_err(|_, pos| EImports::TypedIdent(pos), typed_ident())
|
|
||||||
),
|
|
||||||
|((file_name, _), typed_ident)| {
|
|
||||||
// TODO: look at blacking block strings during parsing.
|
|
||||||
Spaced::Item(ImportsEntry::IngestedFile(file_name, typed_ident))
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.trace("ingest_file_import")
|
|
||||||
)
|
|
||||||
.trace("imports_entry")
|
|
||||||
}
|
|
|
@ -8,9 +8,9 @@ use crate::{
|
||||||
AbilityImpls, AbilityMember, AssignedField, Collection, Defs, Expr, FullAst, Header,
|
AbilityImpls, AbilityMember, AssignedField, Collection, Defs, Expr, FullAst, Header,
|
||||||
Implements, ImplementsAbilities, ImplementsAbility, ImplementsClause, ImportAlias,
|
Implements, ImplementsAbilities, ImplementsAbility, ImplementsClause, ImportAlias,
|
||||||
ImportAsKeyword, ImportExposingKeyword, ImportedModuleName, IngestedFileAnnotation,
|
ImportAsKeyword, ImportExposingKeyword, ImportedModuleName, IngestedFileAnnotation,
|
||||||
IngestedFileImport, ModuleImport, ModuleImportParams, OldRecordBuilderField, Pattern,
|
IngestedFileImport, ModuleImport, ModuleImportParams, Pattern, PatternAs, Spaced, Spaces,
|
||||||
PatternAs, Spaced, Spaces, SpacesBefore, StrLiteral, StrSegment, Tag, TypeAnnotation,
|
SpacesBefore, StrLiteral, StrSegment, Tag, TypeAnnotation, TypeDef, TypeHeader, ValueDef,
|
||||||
TypeDef, TypeHeader, ValueDef, WhenBranch,
|
WhenBranch,
|
||||||
},
|
},
|
||||||
header::{
|
header::{
|
||||||
AppHeader, ExposedName, ExposesKeyword, HostedHeader, ImportsEntry, ImportsKeyword,
|
AppHeader, ExposedName, ExposesKeyword, HostedHeader, ImportsEntry, ImportsKeyword,
|
||||||
|
@ -562,30 +562,6 @@ impl<'a, T: Normalize<'a> + Copy + std::fmt::Debug> Normalize<'a> for AssignedFi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Normalize<'a> for OldRecordBuilderField<'a> {
|
|
||||||
fn normalize(&self, arena: &'a Bump) -> Self {
|
|
||||||
match *self {
|
|
||||||
OldRecordBuilderField::Value(a, _, c) => OldRecordBuilderField::Value(
|
|
||||||
a.normalize(arena),
|
|
||||||
&[],
|
|
||||||
arena.alloc(c.normalize(arena)),
|
|
||||||
),
|
|
||||||
OldRecordBuilderField::ApplyValue(a, _, _, c) => OldRecordBuilderField::ApplyValue(
|
|
||||||
a.normalize(arena),
|
|
||||||
&[],
|
|
||||||
&[],
|
|
||||||
arena.alloc(c.normalize(arena)),
|
|
||||||
),
|
|
||||||
OldRecordBuilderField::LabelOnly(a) => {
|
|
||||||
OldRecordBuilderField::LabelOnly(a.normalize(arena))
|
|
||||||
}
|
|
||||||
OldRecordBuilderField::Malformed(a) => OldRecordBuilderField::Malformed(a),
|
|
||||||
OldRecordBuilderField::SpaceBefore(a, _) => a.normalize(arena),
|
|
||||||
OldRecordBuilderField::SpaceAfter(a, _) => a.normalize(arena),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Normalize<'a> for StrLiteral<'a> {
|
impl<'a> Normalize<'a> for StrLiteral<'a> {
|
||||||
fn normalize(&self, arena: &'a Bump) -> Self {
|
fn normalize(&self, arena: &'a Bump) -> Self {
|
||||||
match *self {
|
match *self {
|
||||||
|
@ -738,7 +714,6 @@ impl<'a> Normalize<'a> for Expr<'a> {
|
||||||
fields: fields.normalize(arena),
|
fields: fields.normalize(arena),
|
||||||
},
|
},
|
||||||
Expr::Record(a) => Expr::Record(a.normalize(arena)),
|
Expr::Record(a) => Expr::Record(a.normalize(arena)),
|
||||||
Expr::OldRecordBuilder(a) => Expr::OldRecordBuilder(a.normalize(arena)),
|
|
||||||
Expr::RecordBuilder { mapper, fields } => Expr::RecordBuilder {
|
Expr::RecordBuilder { mapper, fields } => Expr::RecordBuilder {
|
||||||
mapper: arena.alloc(mapper.normalize(arena)),
|
mapper: arena.alloc(mapper.normalize(arena)),
|
||||||
fields: fields.normalize(arena),
|
fields: fields.normalize(arena),
|
||||||
|
@ -796,7 +771,15 @@ impl<'a> Normalize<'a> for Expr<'a> {
|
||||||
Expr::UnaryOp(a, b) => {
|
Expr::UnaryOp(a, b) => {
|
||||||
Expr::UnaryOp(arena.alloc(a.normalize(arena)), b.normalize(arena))
|
Expr::UnaryOp(arena.alloc(a.normalize(arena)), b.normalize(arena))
|
||||||
}
|
}
|
||||||
Expr::If(a, b) => Expr::If(a.normalize(arena), arena.alloc(b.normalize(arena))),
|
Expr::If {
|
||||||
|
if_thens,
|
||||||
|
final_else,
|
||||||
|
indented_else,
|
||||||
|
} => Expr::If {
|
||||||
|
if_thens: if_thens.normalize(arena),
|
||||||
|
final_else: arena.alloc(final_else.normalize(arena)),
|
||||||
|
indented_else,
|
||||||
|
},
|
||||||
Expr::When(a, b) => Expr::When(arena.alloc(a.normalize(arena)), b.normalize(arena)),
|
Expr::When(a, b) => Expr::When(arena.alloc(a.normalize(arena)), b.normalize(arena)),
|
||||||
Expr::ParensAround(a) => {
|
Expr::ParensAround(a) => {
|
||||||
// The formatter can remove redundant parentheses, so also remove these when normalizing for comparison.
|
// The formatter can remove redundant parentheses, so also remove these when normalizing for comparison.
|
||||||
|
@ -809,12 +792,6 @@ impl<'a> Normalize<'a> for Expr<'a> {
|
||||||
Expr::SpaceBefore(a, _) => a.normalize(arena),
|
Expr::SpaceBefore(a, _) => a.normalize(arena),
|
||||||
Expr::SpaceAfter(a, _) => a.normalize(arena),
|
Expr::SpaceAfter(a, _) => a.normalize(arena),
|
||||||
Expr::SingleQuote(a) => Expr::Num(a),
|
Expr::SingleQuote(a) => Expr::Num(a),
|
||||||
Expr::MultipleOldRecordBuilders(a) => {
|
|
||||||
Expr::MultipleOldRecordBuilders(arena.alloc(a.normalize(arena)))
|
|
||||||
}
|
|
||||||
Expr::UnappliedOldRecordBuilder(a) => {
|
|
||||||
Expr::UnappliedOldRecordBuilder(arena.alloc(a.normalize(arena)))
|
|
||||||
}
|
|
||||||
Expr::EmptyRecordBuilder(a) => {
|
Expr::EmptyRecordBuilder(a) => {
|
||||||
Expr::EmptyRecordBuilder(arena.alloc(a.normalize(arena)))
|
Expr::EmptyRecordBuilder(arena.alloc(a.normalize(arena)))
|
||||||
}
|
}
|
||||||
|
@ -1084,12 +1061,6 @@ impl<'a> Normalize<'a> for EExpr<'a> {
|
||||||
EExpr::Record(inner_err, _pos) => {
|
EExpr::Record(inner_err, _pos) => {
|
||||||
EExpr::Record(inner_err.normalize(arena), Position::zero())
|
EExpr::Record(inner_err.normalize(arena), Position::zero())
|
||||||
}
|
}
|
||||||
EExpr::OptionalValueInOldRecordBuilder(_pos) => {
|
|
||||||
EExpr::OptionalValueInOldRecordBuilder(Region::zero())
|
|
||||||
}
|
|
||||||
EExpr::IgnoredValueInOldRecordBuilder(_pos) => {
|
|
||||||
EExpr::OptionalValueInOldRecordBuilder(Region::zero())
|
|
||||||
}
|
|
||||||
EExpr::Str(inner_err, _pos) => EExpr::Str(inner_err.normalize(arena), Position::zero()),
|
EExpr::Str(inner_err, _pos) => EExpr::Str(inner_err.normalize(arena), Position::zero()),
|
||||||
EExpr::Number(inner_err, _pos) => EExpr::Number(inner_err.clone(), Position::zero()),
|
EExpr::Number(inner_err, _pos) => EExpr::Number(inner_err.clone(), Position::zero()),
|
||||||
EExpr::List(inner_err, _pos) => {
|
EExpr::List(inner_err, _pos) => {
|
||||||
|
@ -1323,7 +1294,6 @@ impl<'a> Normalize<'a> for EImportParams<'a> {
|
||||||
EImportParams::Record(inner_err.normalize(arena), Position::zero())
|
EImportParams::Record(inner_err.normalize(arena), Position::zero())
|
||||||
}
|
}
|
||||||
EImportParams::RecordUpdateFound(_) => EImportParams::RecordUpdateFound(Region::zero()),
|
EImportParams::RecordUpdateFound(_) => EImportParams::RecordUpdateFound(Region::zero()),
|
||||||
EImportParams::RecordApplyFound(_) => EImportParams::RecordApplyFound(Region::zero()),
|
|
||||||
EImportParams::RecordIgnoredFieldFound(_) => {
|
EImportParams::RecordIgnoredFieldFound(_) => {
|
||||||
EImportParams::RecordIgnoredFieldFound(Region::zero())
|
EImportParams::RecordIgnoredFieldFound(Region::zero())
|
||||||
}
|
}
|
||||||
|
|
|
@ -344,8 +344,6 @@ pub enum EExpr<'a> {
|
||||||
|
|
||||||
InParens(EInParens<'a>, Position),
|
InParens(EInParens<'a>, Position),
|
||||||
Record(ERecord<'a>, Position),
|
Record(ERecord<'a>, Position),
|
||||||
OptionalValueInOldRecordBuilder(Region),
|
|
||||||
IgnoredValueInOldRecordBuilder(Region),
|
|
||||||
RecordUpdateOldBuilderField(Region),
|
RecordUpdateOldBuilderField(Region),
|
||||||
RecordUpdateIgnoredField(Region),
|
RecordUpdateIgnoredField(Region),
|
||||||
RecordBuilderOldBuilderField(Region),
|
RecordBuilderOldBuilderField(Region),
|
||||||
|
@ -551,7 +549,6 @@ pub enum EImportParams<'a> {
|
||||||
Record(ERecord<'a>, Position),
|
Record(ERecord<'a>, Position),
|
||||||
RecordUpdateFound(Region),
|
RecordUpdateFound(Region),
|
||||||
RecordBuilderFound(Region),
|
RecordBuilderFound(Region),
|
||||||
RecordApplyFound(Region),
|
|
||||||
RecordIgnoredFieldFound(Region),
|
RecordIgnoredFieldFound(Region),
|
||||||
Space(BadInputError, Position),
|
Space(BadInputError, Position),
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::ast::{
|
||||||
use crate::blankspace::{
|
use crate::blankspace::{
|
||||||
space0_around_ee, space0_before_e, space0_before_optional_after, space0_e,
|
space0_around_ee, space0_before_e, space0_before_optional_after, space0_e,
|
||||||
};
|
};
|
||||||
use crate::expr::{record_field, FoundApplyValue};
|
use crate::expr::record_field;
|
||||||
use crate::ident::{lowercase_ident, lowercase_ident_keyword_e};
|
use crate::ident::{lowercase_ident, lowercase_ident_keyword_e};
|
||||||
use crate::keyword;
|
use crate::keyword;
|
||||||
use crate::parser::{
|
use crate::parser::{
|
||||||
|
@ -565,11 +565,10 @@ fn parse_implements_ability<'a>() -> impl Parser<'a, ImplementsAbility<'a>, ETyp
|
||||||
fn ability_impl_field<'a>() -> impl Parser<'a, AssignedField<'a, Expr<'a>>, ERecord<'a>> {
|
fn ability_impl_field<'a>() -> impl Parser<'a, AssignedField<'a, Expr<'a>>, ERecord<'a>> {
|
||||||
then(record_field(), move |arena, state, _, field| {
|
then(record_field(), move |arena, state, _, field| {
|
||||||
match field.to_assigned_field(arena) {
|
match field.to_assigned_field(arena) {
|
||||||
Ok(AssignedField::IgnoredValue(_, _, _)) => {
|
AssignedField::IgnoredValue(_, _, _) => {
|
||||||
Err((MadeProgress, ERecord::Field(state.pos())))
|
Err((MadeProgress, ERecord::Field(state.pos())))
|
||||||
}
|
}
|
||||||
Ok(assigned_field) => Ok((MadeProgress, assigned_field, state)),
|
assigned_field => Ok((MadeProgress, assigned_field, state)),
|
||||||
Err(FoundApplyValue) => Err((MadeProgress, ERecord::Field(state.pos()))),
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -427,8 +427,6 @@ impl Problem {
|
||||||
| Problem::RuntimeError(RuntimeError::EmptySingleQuote(region))
|
| Problem::RuntimeError(RuntimeError::EmptySingleQuote(region))
|
||||||
| Problem::RuntimeError(RuntimeError::MultipleCharsInSingleQuote(region))
|
| Problem::RuntimeError(RuntimeError::MultipleCharsInSingleQuote(region))
|
||||||
| Problem::RuntimeError(RuntimeError::DegenerateBranch(region))
|
| Problem::RuntimeError(RuntimeError::DegenerateBranch(region))
|
||||||
| Problem::RuntimeError(RuntimeError::MultipleOldRecordBuilders(region))
|
|
||||||
| Problem::RuntimeError(RuntimeError::UnappliedOldRecordBuilder(region))
|
|
||||||
| Problem::RuntimeError(RuntimeError::EmptyRecordBuilder(region))
|
| Problem::RuntimeError(RuntimeError::EmptyRecordBuilder(region))
|
||||||
| Problem::RuntimeError(RuntimeError::SingleFieldRecordBuilder(region))
|
| Problem::RuntimeError(RuntimeError::SingleFieldRecordBuilder(region))
|
||||||
| Problem::RuntimeError(RuntimeError::OptionalFieldInRecordBuilder {
|
| Problem::RuntimeError(RuntimeError::OptionalFieldInRecordBuilder {
|
||||||
|
@ -686,9 +684,6 @@ pub enum RuntimeError {
|
||||||
|
|
||||||
DegenerateBranch(Region),
|
DegenerateBranch(Region),
|
||||||
|
|
||||||
MultipleOldRecordBuilders(Region),
|
|
||||||
UnappliedOldRecordBuilder(Region),
|
|
||||||
|
|
||||||
EmptyRecordBuilder(Region),
|
EmptyRecordBuilder(Region),
|
||||||
SingleFieldRecordBuilder(Region),
|
SingleFieldRecordBuilder(Region),
|
||||||
OptionalFieldInRecordBuilder {
|
OptionalFieldInRecordBuilder {
|
||||||
|
@ -739,8 +734,6 @@ impl RuntimeError {
|
||||||
| RuntimeError::DegenerateBranch(region)
|
| RuntimeError::DegenerateBranch(region)
|
||||||
| RuntimeError::InvalidInterpolation(region)
|
| RuntimeError::InvalidInterpolation(region)
|
||||||
| RuntimeError::InvalidHexadecimal(region)
|
| RuntimeError::InvalidHexadecimal(region)
|
||||||
| RuntimeError::MultipleOldRecordBuilders(region)
|
|
||||||
| RuntimeError::UnappliedOldRecordBuilder(region)
|
|
||||||
| RuntimeError::EmptyRecordBuilder(region)
|
| RuntimeError::EmptyRecordBuilder(region)
|
||||||
| RuntimeError::SingleFieldRecordBuilder(region)
|
| RuntimeError::SingleFieldRecordBuilder(region)
|
||||||
| RuntimeError::OptionalFieldInRecordBuilder {
|
| RuntimeError::OptionalFieldInRecordBuilder {
|
||||||
|
|
|
@ -547,6 +547,11 @@ fn list_drop_at() {
|
||||||
RocList::from_slice(&[2, 3]),
|
RocList::from_slice(&[2, 3]),
|
||||||
RocList<i64>
|
RocList<i64>
|
||||||
);
|
);
|
||||||
|
assert_evals_to!(
|
||||||
|
"List.dropAt [1, 2, 3] 1",
|
||||||
|
RocList::from_slice(&[1, 3]),
|
||||||
|
RocList<i64>
|
||||||
|
);
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
"List.dropAt [0, 0, 0] 3",
|
"List.dropAt [0, 0, 0] 3",
|
||||||
RocList::from_slice(&[0, 0, 0]),
|
RocList::from_slice(&[0, 0, 0]),
|
||||||
|
|
|
@ -1988,3 +1988,75 @@ fn str_contains_self() {
|
||||||
bool
|
bool
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||||
|
fn str_drop_prefix() {
|
||||||
|
assert_evals_to!(
|
||||||
|
r#"
|
||||||
|
Str.dropPrefix "" "foo"
|
||||||
|
"#,
|
||||||
|
RocStr::from(""),
|
||||||
|
RocStr
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_evals_to!(
|
||||||
|
r#"
|
||||||
|
Str.dropPrefix "bar" "foo"
|
||||||
|
"#,
|
||||||
|
RocStr::from("bar"),
|
||||||
|
RocStr
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_evals_to!(
|
||||||
|
r#"
|
||||||
|
Str.dropPrefix "foobar" "foo"
|
||||||
|
"#,
|
||||||
|
RocStr::from("bar"),
|
||||||
|
RocStr
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_evals_to!(
|
||||||
|
r#"
|
||||||
|
Str.dropPrefix "fooBarThisIsDefinitelyAReallyLongAndNotaShortString" "foo"
|
||||||
|
"#,
|
||||||
|
RocStr::from("BarThisIsDefinitelyAReallyLongAndNotaShortString"),
|
||||||
|
RocStr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||||
|
fn str_drop_suffix() {
|
||||||
|
assert_evals_to!(
|
||||||
|
r#"
|
||||||
|
Str.dropSuffix "" "foo"
|
||||||
|
"#,
|
||||||
|
RocStr::from(""),
|
||||||
|
RocStr
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_evals_to!(
|
||||||
|
r#"
|
||||||
|
Str.dropSuffix "bar" "foo"
|
||||||
|
"#,
|
||||||
|
RocStr::from("bar"),
|
||||||
|
RocStr
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_evals_to!(
|
||||||
|
r#"
|
||||||
|
Str.dropSuffix "barfoo" "foo"
|
||||||
|
"#,
|
||||||
|
RocStr::from("bar"),
|
||||||
|
RocStr
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_evals_to!(
|
||||||
|
r#"
|
||||||
|
Str.dropSuffix "BarThisIsDefinitelyAReallyLongAndNotaShortStringfoo" "foo"
|
||||||
|
"#,
|
||||||
|
RocStr::from("BarThisIsDefinitelyAReallyLongAndNotaShortString"),
|
||||||
|
RocStr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -41,8 +41,8 @@ procedure Num.51 (#Attr.2, #Attr.3):
|
||||||
ret Num.281;
|
ret Num.281;
|
||||||
|
|
||||||
procedure Str.3 (#Attr.2, #Attr.3):
|
procedure Str.3 (#Attr.2, #Attr.3):
|
||||||
let Str.238 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
let Str.248 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||||
ret Str.238;
|
ret Str.248;
|
||||||
|
|
||||||
procedure Test.1 (Test.5):
|
procedure Test.1 (Test.5):
|
||||||
ret Test.5;
|
ret Test.5;
|
||||||
|
|
18
crates/compiler/test_mono/generated/dbg_expr.txt
generated
18
crates/compiler/test_mono/generated/dbg_expr.txt
generated
|
@ -43,14 +43,14 @@ procedure Num.96 (#Attr.2):
|
||||||
ret Num.282;
|
ret Num.282;
|
||||||
|
|
||||||
procedure Str.3 (#Attr.2, #Attr.3):
|
procedure Str.3 (#Attr.2, #Attr.3):
|
||||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||||
ret Str.236;
|
ret Str.246;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.4 : I64 = 1i64;
|
let Test.5 : I64 = 1i64;
|
||||||
let Test.1 : I64 = 2i64;
|
let Test.2 : I64 = 2i64;
|
||||||
let Test.2 : Str = CallByName Inspect.33 Test.1;
|
let Test.3 : Str = CallByName Inspect.33 Test.2;
|
||||||
dbg Test.2;
|
dbg Test.3;
|
||||||
dec Test.2;
|
dec Test.3;
|
||||||
let Test.3 : I64 = CallByName Num.19 Test.4 Test.1;
|
let Test.4 : I64 = CallByName Num.19 Test.5 Test.2;
|
||||||
ret Test.3;
|
ret Test.4;
|
||||||
|
|
|
@ -44,8 +44,8 @@ procedure Inspect.64 (Inspect.302):
|
||||||
ret Inspect.302;
|
ret Inspect.302;
|
||||||
|
|
||||||
procedure Str.3 (#Attr.2, #Attr.3):
|
procedure Str.3 (#Attr.2, #Attr.3):
|
||||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||||
ret Str.236;
|
ret Str.246;
|
||||||
|
|
||||||
procedure Test.1 ():
|
procedure Test.1 ():
|
||||||
let Test.4 : Str = "";
|
let Test.4 : Str = "";
|
||||||
|
|
|
@ -40,19 +40,19 @@ procedure Inspect.64 (Inspect.302):
|
||||||
ret Inspect.302;
|
ret Inspect.302;
|
||||||
|
|
||||||
procedure Str.3 (#Attr.2, #Attr.3):
|
procedure Str.3 (#Attr.2, #Attr.3):
|
||||||
let Str.238 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
let Str.248 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||||
ret Str.238;
|
ret Str.248;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.4 : Str = "Hello ";
|
let Test.5 : Str = "Hello ";
|
||||||
let Test.1 : Str = "world";
|
let Test.2 : Str = "world";
|
||||||
inc Test.1;
|
inc Test.2;
|
||||||
let Test.2 : Str = CallByName Inspect.33 Test.1;
|
let Test.3 : Str = CallByName Inspect.33 Test.2;
|
||||||
dbg Test.2;
|
dbg Test.3;
|
||||||
dec Test.2;
|
dec Test.3;
|
||||||
let Test.7 : Str = "!";
|
let Test.8 : Str = "!";
|
||||||
let Test.5 : Str = CallByName Str.3 Test.1 Test.7;
|
let Test.6 : Str = CallByName Str.3 Test.2 Test.8;
|
||||||
dec Test.7;
|
dec Test.8;
|
||||||
let Test.3 : Str = CallByName Str.3 Test.4 Test.5;
|
let Test.4 : Str = CallByName Str.3 Test.5 Test.6;
|
||||||
dec Test.5;
|
dec Test.6;
|
||||||
ret Test.3;
|
ret Test.4;
|
||||||
|
|
|
@ -39,18 +39,18 @@ procedure Num.96 (#Attr.2):
|
||||||
ret Num.281;
|
ret Num.281;
|
||||||
|
|
||||||
procedure Str.3 (#Attr.2, #Attr.3):
|
procedure Str.3 (#Attr.2, #Attr.3):
|
||||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||||
ret Str.236;
|
ret Str.246;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.3 : I64 = 1i64;
|
let Test.6 : I64 = 1i64;
|
||||||
let Test.4 : Str = CallByName Inspect.33 Test.3;
|
let Test.7 : Str = CallByName Inspect.33 Test.6;
|
||||||
dbg Test.4;
|
dbg Test.7;
|
||||||
dec Test.4;
|
dec Test.7;
|
||||||
let Test.5 : Str = CallByName Inspect.33 Test.3;
|
let Test.8 : Str = CallByName Inspect.33 Test.6;
|
||||||
dbg Test.5;
|
dbg Test.8;
|
||||||
dec Test.5;
|
dec Test.8;
|
||||||
let Test.6 : Str = CallByName Inspect.33 Test.3;
|
let Test.9 : Str = CallByName Inspect.33 Test.6;
|
||||||
dbg Test.6;
|
dbg Test.9;
|
||||||
dec Test.6;
|
dec Test.9;
|
||||||
ret Test.3;
|
ret Test.6;
|
||||||
|
|
|
@ -40,8 +40,8 @@ procedure Inspect.64 (Inspect.302):
|
||||||
ret Inspect.302;
|
ret Inspect.302;
|
||||||
|
|
||||||
procedure Str.3 (#Attr.2, #Attr.3):
|
procedure Str.3 (#Attr.2, #Attr.3):
|
||||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||||
ret Str.236;
|
ret Str.246;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.3 : Str = "";
|
let Test.3 : Str = "";
|
||||||
|
|
38
crates/compiler/test_mono/generated/dict.txt
generated
38
crates/compiler/test_mono/generated/dict.txt
generated
|
@ -1,29 +1,29 @@
|
||||||
procedure Dict.1 (Dict.730):
|
procedure Dict.1 (Dict.731):
|
||||||
let Dict.739 : List {U32, U32} = Array [];
|
let Dict.740 : List {U32, U32} = Array [];
|
||||||
let Dict.740 : List {[], []} = Array [];
|
let Dict.741 : List {[], []} = Array [];
|
||||||
let Dict.741 : U64 = 0i64;
|
let Dict.742 : U64 = 0i64;
|
||||||
let Dict.51 : Float32 = CallByName Dict.51;
|
let Dict.51 : Float32 = CallByName Dict.51;
|
||||||
let Dict.52 : U8 = CallByName Dict.52;
|
let Dict.52 : U8 = CallByName Dict.52;
|
||||||
let Dict.738 : {List {U32, U32}, List {[], []}, U64, Float32, U8} = Struct {Dict.739, Dict.740, Dict.741, Dict.51, Dict.52};
|
let Dict.739 : {List {U32, U32}, List {[], []}, U64, Float32, U8} = Struct {Dict.740, Dict.741, Dict.742, Dict.51, Dict.52};
|
||||||
|
ret Dict.739;
|
||||||
|
|
||||||
|
procedure Dict.4 (Dict.737):
|
||||||
|
let Dict.163 : List {[], []} = StructAtIndex 1 Dict.737;
|
||||||
|
let #Derived_gen.0 : List {U32, U32} = StructAtIndex 0 Dict.737;
|
||||||
|
dec #Derived_gen.0;
|
||||||
|
let Dict.738 : U64 = CallByName List.6 Dict.163;
|
||||||
|
dec Dict.163;
|
||||||
ret Dict.738;
|
ret Dict.738;
|
||||||
|
|
||||||
procedure Dict.4 (Dict.736):
|
|
||||||
let Dict.163 : List {[], []} = StructAtIndex 1 Dict.736;
|
|
||||||
let #Derived_gen.0 : List {U32, U32} = StructAtIndex 0 Dict.736;
|
|
||||||
dec #Derived_gen.0;
|
|
||||||
let Dict.737 : U64 = CallByName List.6 Dict.163;
|
|
||||||
dec Dict.163;
|
|
||||||
ret Dict.737;
|
|
||||||
|
|
||||||
procedure Dict.51 ():
|
procedure Dict.51 ():
|
||||||
let Dict.745 : Float32 = 0.8f64;
|
let Dict.746 : Float32 = 0.8f64;
|
||||||
ret Dict.745;
|
ret Dict.746;
|
||||||
|
|
||||||
procedure Dict.52 ():
|
procedure Dict.52 ():
|
||||||
let Dict.743 : U8 = 64i64;
|
let Dict.744 : U8 = 64i64;
|
||||||
let Dict.744 : U8 = 3i64;
|
let Dict.745 : U8 = 3i64;
|
||||||
let Dict.742 : U8 = CallByName Num.75 Dict.743 Dict.744;
|
let Dict.743 : U8 = CallByName Num.75 Dict.744 Dict.745;
|
||||||
ret Dict.742;
|
ret Dict.743;
|
||||||
|
|
||||||
procedure List.6 (#Attr.2):
|
procedure List.6 (#Attr.2):
|
||||||
let List.625 : U64 = lowlevel ListLenU64 #Attr.2;
|
let List.625 : U64 = lowlevel ListLenU64 #Attr.2;
|
||||||
|
|
|
@ -164,32 +164,32 @@ procedure Num.96 (#Attr.2):
|
||||||
ret Num.285;
|
ret Num.285;
|
||||||
|
|
||||||
procedure Str.12 (#Attr.2):
|
procedure Str.12 (#Attr.2):
|
||||||
let Str.248 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
let Str.258 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||||
ret Str.248;
|
ret Str.258;
|
||||||
|
|
||||||
procedure Str.36 (#Attr.2):
|
procedure Str.36 (#Attr.2):
|
||||||
let Str.249 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
let Str.259 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||||
ret Str.249;
|
ret Str.259;
|
||||||
|
|
||||||
procedure Str.43 (#Attr.2):
|
procedure Str.43 (#Attr.2):
|
||||||
let Str.243 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
let Str.253 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||||
ret Str.243;
|
ret Str.253;
|
||||||
|
|
||||||
procedure Str.9 (Str.71):
|
procedure Str.9 (Str.73):
|
||||||
let Str.72 : {U64, Str, Int1, U8} = CallByName Str.43 Str.71;
|
let Str.74 : {U64, Str, Int1, U8} = CallByName Str.43 Str.73;
|
||||||
let Str.240 : Int1 = StructAtIndex 2 Str.72;
|
let Str.250 : Int1 = StructAtIndex 2 Str.74;
|
||||||
if Str.240 then
|
if Str.250 then
|
||||||
let Str.242 : Str = StructAtIndex 1 Str.72;
|
let Str.252 : Str = StructAtIndex 1 Str.74;
|
||||||
let Str.241 : [C {U64, U8}, C Str] = TagId(1) Str.242;
|
let Str.251 : [C {U64, U8}, C Str] = TagId(1) Str.252;
|
||||||
ret Str.241;
|
ret Str.251;
|
||||||
else
|
else
|
||||||
let Str.238 : U8 = StructAtIndex 3 Str.72;
|
let Str.248 : U8 = StructAtIndex 3 Str.74;
|
||||||
let Str.239 : U64 = StructAtIndex 0 Str.72;
|
let Str.249 : U64 = StructAtIndex 0 Str.74;
|
||||||
let #Derived_gen.45 : Str = StructAtIndex 1 Str.72;
|
let #Derived_gen.45 : Str = StructAtIndex 1 Str.74;
|
||||||
dec #Derived_gen.45;
|
dec #Derived_gen.45;
|
||||||
let Str.237 : {U64, U8} = Struct {Str.239, Str.238};
|
let Str.247 : {U64, U8} = Struct {Str.249, Str.248};
|
||||||
let Str.236 : [C {U64, U8}, C Str] = TagId(0) Str.237;
|
let Str.246 : [C {U64, U8}, C Str] = TagId(0) Str.247;
|
||||||
ret Str.236;
|
ret Str.246;
|
||||||
|
|
||||||
procedure Test.20 (Test.56):
|
procedure Test.20 (Test.56):
|
||||||
let Test.325 : Str = CallByName Encode.23 Test.56;
|
let Test.325 : Str = CallByName Encode.23 Test.56;
|
||||||
|
|
|
@ -105,32 +105,32 @@ procedure Num.96 (#Attr.2):
|
||||||
ret Num.281;
|
ret Num.281;
|
||||||
|
|
||||||
procedure Str.12 (#Attr.2):
|
procedure Str.12 (#Attr.2):
|
||||||
let Str.245 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
let Str.255 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||||
ret Str.245;
|
ret Str.255;
|
||||||
|
|
||||||
procedure Str.36 (#Attr.2):
|
procedure Str.36 (#Attr.2):
|
||||||
let Str.246 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
let Str.256 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||||
ret Str.246;
|
ret Str.256;
|
||||||
|
|
||||||
procedure Str.43 (#Attr.2):
|
procedure Str.43 (#Attr.2):
|
||||||
let Str.243 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
let Str.253 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||||
ret Str.243;
|
ret Str.253;
|
||||||
|
|
||||||
procedure Str.9 (Str.71):
|
procedure Str.9 (Str.73):
|
||||||
let Str.72 : {U64, Str, Int1, U8} = CallByName Str.43 Str.71;
|
let Str.74 : {U64, Str, Int1, U8} = CallByName Str.43 Str.73;
|
||||||
let Str.240 : Int1 = StructAtIndex 2 Str.72;
|
let Str.250 : Int1 = StructAtIndex 2 Str.74;
|
||||||
if Str.240 then
|
if Str.250 then
|
||||||
let Str.242 : Str = StructAtIndex 1 Str.72;
|
let Str.252 : Str = StructAtIndex 1 Str.74;
|
||||||
let Str.241 : [C {U64, U8}, C Str] = TagId(1) Str.242;
|
let Str.251 : [C {U64, U8}, C Str] = TagId(1) Str.252;
|
||||||
ret Str.241;
|
ret Str.251;
|
||||||
else
|
else
|
||||||
let Str.238 : U8 = StructAtIndex 3 Str.72;
|
let Str.248 : U8 = StructAtIndex 3 Str.74;
|
||||||
let Str.239 : U64 = StructAtIndex 0 Str.72;
|
let Str.249 : U64 = StructAtIndex 0 Str.74;
|
||||||
let #Derived_gen.24 : Str = StructAtIndex 1 Str.72;
|
let #Derived_gen.24 : Str = StructAtIndex 1 Str.74;
|
||||||
dec #Derived_gen.24;
|
dec #Derived_gen.24;
|
||||||
let Str.237 : {U64, U8} = Struct {Str.239, Str.238};
|
let Str.247 : {U64, U8} = Struct {Str.249, Str.248};
|
||||||
let Str.236 : [C {U64, U8}, C Str] = TagId(0) Str.237;
|
let Str.246 : [C {U64, U8}, C Str] = TagId(0) Str.247;
|
||||||
ret Str.236;
|
ret Str.246;
|
||||||
|
|
||||||
procedure Test.20 (Test.56):
|
procedure Test.20 (Test.56):
|
||||||
let Test.292 : Str = CallByName Encode.23 Test.56;
|
let Test.292 : Str = CallByName Encode.23 Test.56;
|
||||||
|
|
|
@ -112,32 +112,32 @@ procedure Num.96 (#Attr.2):
|
||||||
ret Num.281;
|
ret Num.281;
|
||||||
|
|
||||||
procedure Str.12 (#Attr.2):
|
procedure Str.12 (#Attr.2):
|
||||||
let Str.245 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
let Str.255 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||||
ret Str.245;
|
ret Str.255;
|
||||||
|
|
||||||
procedure Str.36 (#Attr.2):
|
procedure Str.36 (#Attr.2):
|
||||||
let Str.246 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
let Str.256 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||||
ret Str.246;
|
ret Str.256;
|
||||||
|
|
||||||
procedure Str.43 (#Attr.2):
|
procedure Str.43 (#Attr.2):
|
||||||
let Str.243 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
let Str.253 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||||
ret Str.243;
|
ret Str.253;
|
||||||
|
|
||||||
procedure Str.9 (Str.71):
|
procedure Str.9 (Str.73):
|
||||||
let Str.72 : {U64, Str, Int1, U8} = CallByName Str.43 Str.71;
|
let Str.74 : {U64, Str, Int1, U8} = CallByName Str.43 Str.73;
|
||||||
let Str.240 : Int1 = StructAtIndex 2 Str.72;
|
let Str.250 : Int1 = StructAtIndex 2 Str.74;
|
||||||
if Str.240 then
|
if Str.250 then
|
||||||
let Str.242 : Str = StructAtIndex 1 Str.72;
|
let Str.252 : Str = StructAtIndex 1 Str.74;
|
||||||
let Str.241 : [C {U64, U8}, C Str] = TagId(1) Str.242;
|
let Str.251 : [C {U64, U8}, C Str] = TagId(1) Str.252;
|
||||||
ret Str.241;
|
ret Str.251;
|
||||||
else
|
else
|
||||||
let Str.238 : U8 = StructAtIndex 3 Str.72;
|
let Str.248 : U8 = StructAtIndex 3 Str.74;
|
||||||
let Str.239 : U64 = StructAtIndex 0 Str.72;
|
let Str.249 : U64 = StructAtIndex 0 Str.74;
|
||||||
let #Derived_gen.28 : Str = StructAtIndex 1 Str.72;
|
let #Derived_gen.28 : Str = StructAtIndex 1 Str.74;
|
||||||
dec #Derived_gen.28;
|
dec #Derived_gen.28;
|
||||||
let Str.237 : {U64, U8} = Struct {Str.239, Str.238};
|
let Str.247 : {U64, U8} = Struct {Str.249, Str.248};
|
||||||
let Str.236 : [C {U64, U8}, C Str] = TagId(0) Str.237;
|
let Str.246 : [C {U64, U8}, C Str] = TagId(0) Str.247;
|
||||||
ret Str.236;
|
ret Str.246;
|
||||||
|
|
||||||
procedure Test.20 (Test.56):
|
procedure Test.20 (Test.56):
|
||||||
let Test.296 : Str = CallByName Encode.23 Test.56;
|
let Test.296 : Str = CallByName Encode.23 Test.56;
|
||||||
|
|
|
@ -38,32 +38,32 @@ procedure Num.96 (#Attr.2):
|
||||||
ret Num.281;
|
ret Num.281;
|
||||||
|
|
||||||
procedure Str.12 (#Attr.2):
|
procedure Str.12 (#Attr.2):
|
||||||
let Str.245 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
let Str.255 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||||
ret Str.245;
|
ret Str.255;
|
||||||
|
|
||||||
procedure Str.36 (#Attr.2):
|
procedure Str.36 (#Attr.2):
|
||||||
let Str.246 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
let Str.256 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||||
ret Str.246;
|
ret Str.256;
|
||||||
|
|
||||||
procedure Str.43 (#Attr.2):
|
procedure Str.43 (#Attr.2):
|
||||||
let Str.243 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
let Str.253 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||||
ret Str.243;
|
ret Str.253;
|
||||||
|
|
||||||
procedure Str.9 (Str.71):
|
procedure Str.9 (Str.73):
|
||||||
let Str.72 : {U64, Str, Int1, U8} = CallByName Str.43 Str.71;
|
let Str.74 : {U64, Str, Int1, U8} = CallByName Str.43 Str.73;
|
||||||
let Str.240 : Int1 = StructAtIndex 2 Str.72;
|
let Str.250 : Int1 = StructAtIndex 2 Str.74;
|
||||||
if Str.240 then
|
if Str.250 then
|
||||||
let Str.242 : Str = StructAtIndex 1 Str.72;
|
let Str.252 : Str = StructAtIndex 1 Str.74;
|
||||||
let Str.241 : [C {U64, U8}, C Str] = TagId(1) Str.242;
|
let Str.251 : [C {U64, U8}, C Str] = TagId(1) Str.252;
|
||||||
ret Str.241;
|
ret Str.251;
|
||||||
else
|
else
|
||||||
let Str.238 : U8 = StructAtIndex 3 Str.72;
|
let Str.248 : U8 = StructAtIndex 3 Str.74;
|
||||||
let Str.239 : U64 = StructAtIndex 0 Str.72;
|
let Str.249 : U64 = StructAtIndex 0 Str.74;
|
||||||
let #Derived_gen.3 : Str = StructAtIndex 1 Str.72;
|
let #Derived_gen.3 : Str = StructAtIndex 1 Str.74;
|
||||||
dec #Derived_gen.3;
|
dec #Derived_gen.3;
|
||||||
let Str.237 : {U64, U8} = Struct {Str.239, Str.238};
|
let Str.247 : {U64, U8} = Struct {Str.249, Str.248};
|
||||||
let Str.236 : [C {U64, U8}, C Str] = TagId(0) Str.237;
|
let Str.246 : [C {U64, U8}, C Str] = TagId(0) Str.247;
|
||||||
ret Str.236;
|
ret Str.246;
|
||||||
|
|
||||||
procedure Test.20 (Test.56):
|
procedure Test.20 (Test.56):
|
||||||
let Test.259 : Str = CallByName Encode.23 Test.56;
|
let Test.259 : Str = CallByName Encode.23 Test.56;
|
||||||
|
|
|
@ -110,32 +110,32 @@ procedure Num.96 (#Attr.2):
|
||||||
ret Num.281;
|
ret Num.281;
|
||||||
|
|
||||||
procedure Str.12 (#Attr.2):
|
procedure Str.12 (#Attr.2):
|
||||||
let Str.245 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
let Str.255 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||||
ret Str.245;
|
ret Str.255;
|
||||||
|
|
||||||
procedure Str.36 (#Attr.2):
|
procedure Str.36 (#Attr.2):
|
||||||
let Str.246 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
let Str.256 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||||
ret Str.246;
|
ret Str.256;
|
||||||
|
|
||||||
procedure Str.43 (#Attr.2):
|
procedure Str.43 (#Attr.2):
|
||||||
let Str.243 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
let Str.253 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||||
ret Str.243;
|
ret Str.253;
|
||||||
|
|
||||||
procedure Str.9 (Str.71):
|
procedure Str.9 (Str.73):
|
||||||
let Str.72 : {U64, Str, Int1, U8} = CallByName Str.43 Str.71;
|
let Str.74 : {U64, Str, Int1, U8} = CallByName Str.43 Str.73;
|
||||||
let Str.240 : Int1 = StructAtIndex 2 Str.72;
|
let Str.250 : Int1 = StructAtIndex 2 Str.74;
|
||||||
if Str.240 then
|
if Str.250 then
|
||||||
let Str.242 : Str = StructAtIndex 1 Str.72;
|
let Str.252 : Str = StructAtIndex 1 Str.74;
|
||||||
let Str.241 : [C {U64, U8}, C Str] = TagId(1) Str.242;
|
let Str.251 : [C {U64, U8}, C Str] = TagId(1) Str.252;
|
||||||
ret Str.241;
|
ret Str.251;
|
||||||
else
|
else
|
||||||
let Str.238 : U8 = StructAtIndex 3 Str.72;
|
let Str.248 : U8 = StructAtIndex 3 Str.74;
|
||||||
let Str.239 : U64 = StructAtIndex 0 Str.72;
|
let Str.249 : U64 = StructAtIndex 0 Str.74;
|
||||||
let #Derived_gen.27 : Str = StructAtIndex 1 Str.72;
|
let #Derived_gen.27 : Str = StructAtIndex 1 Str.74;
|
||||||
dec #Derived_gen.27;
|
dec #Derived_gen.27;
|
||||||
let Str.237 : {U64, U8} = Struct {Str.239, Str.238};
|
let Str.247 : {U64, U8} = Struct {Str.249, Str.248};
|
||||||
let Str.236 : [C {U64, U8}, C Str] = TagId(0) Str.237;
|
let Str.246 : [C {U64, U8}, C Str] = TagId(0) Str.247;
|
||||||
ret Str.236;
|
ret Str.246;
|
||||||
|
|
||||||
procedure Test.20 (Test.56):
|
procedure Test.20 (Test.56):
|
||||||
let Test.297 : Str = CallByName Encode.23 Test.56;
|
let Test.297 : Str = CallByName Encode.23 Test.56;
|
||||||
|
|
|
@ -113,32 +113,32 @@ procedure Num.96 (#Attr.2):
|
||||||
ret Num.281;
|
ret Num.281;
|
||||||
|
|
||||||
procedure Str.12 (#Attr.2):
|
procedure Str.12 (#Attr.2):
|
||||||
let Str.245 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
let Str.255 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||||
ret Str.245;
|
ret Str.255;
|
||||||
|
|
||||||
procedure Str.36 (#Attr.2):
|
procedure Str.36 (#Attr.2):
|
||||||
let Str.246 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
let Str.256 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||||
ret Str.246;
|
ret Str.256;
|
||||||
|
|
||||||
procedure Str.43 (#Attr.2):
|
procedure Str.43 (#Attr.2):
|
||||||
let Str.243 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
let Str.253 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||||
ret Str.243;
|
ret Str.253;
|
||||||
|
|
||||||
procedure Str.9 (Str.71):
|
procedure Str.9 (Str.73):
|
||||||
let Str.72 : {U64, Str, Int1, U8} = CallByName Str.43 Str.71;
|
let Str.74 : {U64, Str, Int1, U8} = CallByName Str.43 Str.73;
|
||||||
let Str.240 : Int1 = StructAtIndex 2 Str.72;
|
let Str.250 : Int1 = StructAtIndex 2 Str.74;
|
||||||
if Str.240 then
|
if Str.250 then
|
||||||
let Str.242 : Str = StructAtIndex 1 Str.72;
|
let Str.252 : Str = StructAtIndex 1 Str.74;
|
||||||
let Str.241 : [C {U64, U8}, C Str] = TagId(1) Str.242;
|
let Str.251 : [C {U64, U8}, C Str] = TagId(1) Str.252;
|
||||||
ret Str.241;
|
ret Str.251;
|
||||||
else
|
else
|
||||||
let Str.238 : U8 = StructAtIndex 3 Str.72;
|
let Str.248 : U8 = StructAtIndex 3 Str.74;
|
||||||
let Str.239 : U64 = StructAtIndex 0 Str.72;
|
let Str.249 : U64 = StructAtIndex 0 Str.74;
|
||||||
let #Derived_gen.28 : Str = StructAtIndex 1 Str.72;
|
let #Derived_gen.28 : Str = StructAtIndex 1 Str.74;
|
||||||
dec #Derived_gen.28;
|
dec #Derived_gen.28;
|
||||||
let Str.237 : {U64, U8} = Struct {Str.239, Str.238};
|
let Str.247 : {U64, U8} = Struct {Str.249, Str.248};
|
||||||
let Str.236 : [C {U64, U8}, C Str] = TagId(0) Str.237;
|
let Str.246 : [C {U64, U8}, C Str] = TagId(0) Str.247;
|
||||||
ret Str.236;
|
ret Str.246;
|
||||||
|
|
||||||
procedure Test.20 (Test.56):
|
procedure Test.20 (Test.56):
|
||||||
let Test.301 : Str = CallByName Encode.23 Test.56;
|
let Test.301 : Str = CallByName Encode.23 Test.56;
|
||||||
|
|
1140
crates/compiler/test_mono/generated/inspect_derived_dict.txt
generated
1140
crates/compiler/test_mono/generated/inspect_derived_dict.txt
generated
File diff suppressed because it is too large
Load diff
|
@ -178,8 +178,8 @@ procedure Num.96 (#Attr.2):
|
||||||
ret Num.281;
|
ret Num.281;
|
||||||
|
|
||||||
procedure Str.3 (#Attr.2, #Attr.3):
|
procedure Str.3 (#Attr.2, #Attr.3):
|
||||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||||
ret Str.236;
|
ret Str.246;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.2 : List I64 = Array [1i64, 2i64, 3i64];
|
let Test.2 : List I64 = Array [1i64, 2i64, 3i64];
|
||||||
|
|
|
@ -292,8 +292,8 @@ procedure Num.51 (#Attr.2, #Attr.3):
|
||||||
ret Num.283;
|
ret Num.283;
|
||||||
|
|
||||||
procedure Str.3 (#Attr.2, #Attr.3):
|
procedure Str.3 (#Attr.2, #Attr.3):
|
||||||
let Str.237 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
let Str.247 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||||
ret Str.237;
|
ret Str.247;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.4 : Str = "bar";
|
let Test.4 : Str = "bar";
|
||||||
|
|
|
@ -209,8 +209,8 @@ procedure Num.96 (#Attr.2):
|
||||||
ret Num.282;
|
ret Num.282;
|
||||||
|
|
||||||
procedure Str.3 (#Attr.2, #Attr.3):
|
procedure Str.3 (#Attr.2, #Attr.3):
|
||||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||||
ret Str.236;
|
ret Str.246;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.3 : Decimal = 3dec;
|
let Test.3 : Decimal = 3dec;
|
||||||
|
|
|
@ -179,8 +179,8 @@ procedure Num.51 (#Attr.2, #Attr.3):
|
||||||
ret Num.281;
|
ret Num.281;
|
||||||
|
|
||||||
procedure Str.3 (#Attr.2, #Attr.3):
|
procedure Str.3 (#Attr.2, #Attr.3):
|
||||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||||
ret Str.236;
|
ret Str.246;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.3 : Str = "foo";
|
let Test.3 : Str = "foo";
|
||||||
|
|
|
@ -186,8 +186,8 @@ procedure Num.51 (#Attr.2, #Attr.3):
|
||||||
ret Num.281;
|
ret Num.281;
|
||||||
|
|
||||||
procedure Str.3 (#Attr.2, #Attr.3):
|
procedure Str.3 (#Attr.2, #Attr.3):
|
||||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||||
ret Str.236;
|
ret Str.246;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.3 : Str = "foo";
|
let Test.3 : Str = "foo";
|
||||||
|
|
|
@ -40,8 +40,8 @@ procedure Inspect.64 (Inspect.302):
|
||||||
ret Inspect.302;
|
ret Inspect.302;
|
||||||
|
|
||||||
procedure Str.3 (#Attr.2, #Attr.3):
|
procedure Str.3 (#Attr.2, #Attr.3):
|
||||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||||
ret Str.236;
|
ret Str.246;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.2 : Str = "abc";
|
let Test.2 : Str = "abc";
|
||||||
|
|
|
@ -179,8 +179,8 @@ procedure Num.51 (#Attr.2, #Attr.3):
|
||||||
ret Num.281;
|
ret Num.281;
|
||||||
|
|
||||||
procedure Str.3 (#Attr.2, #Attr.3):
|
procedure Str.3 (#Attr.2, #Attr.3):
|
||||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||||
ret Str.236;
|
ret Str.246;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.4 : Str = "foo";
|
let Test.4 : Str = "foo";
|
||||||
|
|
|
@ -182,8 +182,8 @@ procedure Num.51 (#Attr.2, #Attr.3):
|
||||||
ret Num.281;
|
ret Num.281;
|
||||||
|
|
||||||
procedure Str.3 (#Attr.2, #Attr.3):
|
procedure Str.3 (#Attr.2, #Attr.3):
|
||||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||||
ret Str.236;
|
ret Str.246;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.5 : Str = "foo";
|
let Test.5 : Str = "foo";
|
||||||
|
|
|
@ -45,27 +45,27 @@ procedure Num.22 (#Attr.2, #Attr.3):
|
||||||
let Num.281 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
let Num.281 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||||
ret Num.281;
|
ret Num.281;
|
||||||
|
|
||||||
procedure Str.27 (Str.82):
|
procedure Str.27 (Str.84):
|
||||||
let Str.236 : [C Int1, C I64] = CallByName Str.64 Str.82;
|
let Str.246 : [C Int1, C I64] = CallByName Str.66 Str.84;
|
||||||
ret Str.236;
|
ret Str.246;
|
||||||
|
|
||||||
procedure Str.42 (#Attr.2):
|
procedure Str.42 (#Attr.2):
|
||||||
let Str.244 : {I64, U8} = lowlevel StrToNum #Attr.2;
|
let Str.254 : {I64, U8} = lowlevel StrToNum #Attr.2;
|
||||||
ret Str.244;
|
ret Str.254;
|
||||||
|
|
||||||
procedure Str.64 (Str.189):
|
procedure Str.66 (Str.191):
|
||||||
let Str.190 : {I64, U8} = CallByName Str.42 Str.189;
|
let Str.192 : {I64, U8} = CallByName Str.42 Str.191;
|
||||||
let Str.242 : U8 = StructAtIndex 1 Str.190;
|
let Str.252 : U8 = StructAtIndex 1 Str.192;
|
||||||
let Str.243 : U8 = 0i64;
|
let Str.253 : U8 = 0i64;
|
||||||
let Str.239 : Int1 = CallByName Bool.11 Str.242 Str.243;
|
let Str.249 : Int1 = CallByName Bool.11 Str.252 Str.253;
|
||||||
if Str.239 then
|
if Str.249 then
|
||||||
let Str.241 : I64 = StructAtIndex 0 Str.190;
|
let Str.251 : I64 = StructAtIndex 0 Str.192;
|
||||||
let Str.240 : [C Int1, C I64] = TagId(1) Str.241;
|
let Str.250 : [C Int1, C I64] = TagId(1) Str.251;
|
||||||
ret Str.240;
|
ret Str.250;
|
||||||
else
|
else
|
||||||
let Str.238 : Int1 = false;
|
let Str.248 : Int1 = false;
|
||||||
let Str.237 : [C Int1, C I64] = TagId(0) Str.238;
|
let Str.247 : [C Int1, C I64] = TagId(0) Str.248;
|
||||||
ret Str.237;
|
ret Str.247;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.3 : Int1 = CallByName Bool.2;
|
let Test.3 : Int1 = CallByName Bool.2;
|
||||||
|
|
|
@ -19,30 +19,30 @@ procedure Decode.26 (Decode.109, Decode.110):
|
||||||
ret Decode.126;
|
ret Decode.126;
|
||||||
|
|
||||||
procedure Str.12 (#Attr.2):
|
procedure Str.12 (#Attr.2):
|
||||||
let Str.245 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
let Str.255 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||||
ret Str.245;
|
ret Str.255;
|
||||||
|
|
||||||
procedure Str.27 (Str.82):
|
procedure Str.27 (Str.84):
|
||||||
let Str.236 : [C {}, C I64] = CallByName Str.64 Str.82;
|
let Str.246 : [C {}, C I64] = CallByName Str.66 Str.84;
|
||||||
ret Str.236;
|
ret Str.246;
|
||||||
|
|
||||||
procedure Str.42 (#Attr.2):
|
procedure Str.42 (#Attr.2):
|
||||||
let Str.244 : {I64, U8} = lowlevel StrToNum #Attr.2;
|
let Str.254 : {I64, U8} = lowlevel StrToNum #Attr.2;
|
||||||
ret Str.244;
|
ret Str.254;
|
||||||
|
|
||||||
procedure Str.64 (Str.189):
|
procedure Str.66 (Str.191):
|
||||||
let Str.190 : {I64, U8} = CallByName Str.42 Str.189;
|
let Str.192 : {I64, U8} = CallByName Str.42 Str.191;
|
||||||
let Str.242 : U8 = StructAtIndex 1 Str.190;
|
let Str.252 : U8 = StructAtIndex 1 Str.192;
|
||||||
let Str.243 : U8 = 0i64;
|
let Str.253 : U8 = 0i64;
|
||||||
let Str.239 : Int1 = CallByName Bool.11 Str.242 Str.243;
|
let Str.249 : Int1 = CallByName Bool.11 Str.252 Str.253;
|
||||||
if Str.239 then
|
if Str.249 then
|
||||||
let Str.241 : I64 = StructAtIndex 0 Str.190;
|
let Str.251 : I64 = StructAtIndex 0 Str.192;
|
||||||
let Str.240 : [C {}, C I64] = TagId(1) Str.241;
|
let Str.250 : [C {}, C I64] = TagId(1) Str.251;
|
||||||
ret Str.240;
|
ret Str.250;
|
||||||
else
|
else
|
||||||
let Str.238 : {} = Struct {};
|
let Str.248 : {} = Struct {};
|
||||||
let Str.237 : [C {}, C I64] = TagId(0) Str.238;
|
let Str.247 : [C {}, C I64] = TagId(0) Str.248;
|
||||||
ret Str.237;
|
ret Str.247;
|
||||||
|
|
||||||
procedure Test.103 ():
|
procedure Test.103 ():
|
||||||
let Test.101 : [C Str, C {List U8, I64}] = CallByName Test.19;
|
let Test.101 : [C Str, C {List U8, I64}] = CallByName Test.19;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
procedure Str.3 (#Attr.2, #Attr.3):
|
procedure Str.3 (#Attr.2, #Attr.3):
|
||||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||||
ret Str.236;
|
ret Str.246;
|
||||||
|
|
||||||
procedure Test.1 (Test.5):
|
procedure Test.1 (Test.5):
|
||||||
let Test.16 : [C {}, C U64, C Str] = TagId(0) Test.5;
|
let Test.16 : [C {}, C U64, C Str] = TagId(0) Test.5;
|
||||||
|
|
|
@ -71,12 +71,12 @@ procedure Num.51 (#Attr.2, #Attr.3):
|
||||||
ret Num.283;
|
ret Num.283;
|
||||||
|
|
||||||
procedure Str.16 (#Attr.2, #Attr.3):
|
procedure Str.16 (#Attr.2, #Attr.3):
|
||||||
let Str.236 : Str = lowlevel StrRepeat #Attr.2 #Attr.3;
|
let Str.246 : Str = lowlevel StrRepeat #Attr.2 #Attr.3;
|
||||||
ret Str.236;
|
ret Str.246;
|
||||||
|
|
||||||
procedure Str.3 (#Attr.2, #Attr.3):
|
procedure Str.3 (#Attr.2, #Attr.3):
|
||||||
let Str.237 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
let Str.247 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||||
ret Str.237;
|
ret Str.247;
|
||||||
|
|
||||||
procedure Test.1 ():
|
procedure Test.1 ():
|
||||||
let Test.21 : Str = "lllllllllllllllllllllooooooooooong";
|
let Test.21 : Str = "lllllllllllllllllllllooooooooooong";
|
||||||
|
|
|
@ -70,8 +70,8 @@ procedure Num.51 (#Attr.2, #Attr.3):
|
||||||
ret Num.283;
|
ret Num.283;
|
||||||
|
|
||||||
procedure Str.3 (#Attr.2, #Attr.3):
|
procedure Str.3 (#Attr.2, #Attr.3):
|
||||||
let Str.237 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
let Str.247 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||||
ret Str.237;
|
ret Str.247;
|
||||||
|
|
||||||
procedure Test.1 ():
|
procedure Test.1 ():
|
||||||
let Test.21 : Str = "lllllllllllllllllllllooooooooooong";
|
let Test.21 : Str = "lllllllllllllllllllllooooooooooong";
|
||||||
|
|
59
crates/compiler/test_mono/generated/pizza_dbg.txt
generated
Normal file
59
crates/compiler/test_mono/generated/pizza_dbg.txt
generated
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
procedure Inspect.278 (Inspect.279, Inspect.277):
|
||||||
|
let Inspect.318 : Str = CallByName Num.96 Inspect.277;
|
||||||
|
let Inspect.317 : Str = CallByName Inspect.63 Inspect.279 Inspect.318;
|
||||||
|
dec Inspect.318;
|
||||||
|
ret Inspect.317;
|
||||||
|
|
||||||
|
procedure Inspect.30 (Inspect.147):
|
||||||
|
ret Inspect.147;
|
||||||
|
|
||||||
|
procedure Inspect.33 (Inspect.152):
|
||||||
|
let Inspect.322 : Str = CallByName Inspect.5 Inspect.152;
|
||||||
|
let Inspect.321 : Str = CallByName Inspect.64 Inspect.322;
|
||||||
|
ret Inspect.321;
|
||||||
|
|
||||||
|
procedure Inspect.39 (Inspect.301):
|
||||||
|
let Inspect.311 : Str = "";
|
||||||
|
ret Inspect.311;
|
||||||
|
|
||||||
|
procedure Inspect.5 (Inspect.150):
|
||||||
|
let Inspect.312 : I64 = CallByName Inspect.57 Inspect.150;
|
||||||
|
let Inspect.309 : {} = Struct {};
|
||||||
|
let Inspect.308 : Str = CallByName Inspect.39 Inspect.309;
|
||||||
|
let Inspect.307 : Str = CallByName Inspect.278 Inspect.308 Inspect.312;
|
||||||
|
ret Inspect.307;
|
||||||
|
|
||||||
|
procedure Inspect.57 (Inspect.277):
|
||||||
|
let Inspect.313 : I64 = CallByName Inspect.30 Inspect.277;
|
||||||
|
ret Inspect.313;
|
||||||
|
|
||||||
|
procedure Inspect.63 (Inspect.300, Inspect.296):
|
||||||
|
let Inspect.320 : Str = CallByName Str.3 Inspect.300 Inspect.296;
|
||||||
|
ret Inspect.320;
|
||||||
|
|
||||||
|
procedure Inspect.64 (Inspect.302):
|
||||||
|
ret Inspect.302;
|
||||||
|
|
||||||
|
procedure Num.19 (#Attr.2, #Attr.3):
|
||||||
|
let Num.281 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||||
|
ret Num.281;
|
||||||
|
|
||||||
|
procedure Num.96 (#Attr.2):
|
||||||
|
let Num.282 : Str = lowlevel NumToStr #Attr.2;
|
||||||
|
ret Num.282;
|
||||||
|
|
||||||
|
procedure Str.3 (#Attr.2, #Attr.3):
|
||||||
|
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||||
|
ret Str.246;
|
||||||
|
|
||||||
|
procedure Test.0 ():
|
||||||
|
let Test.4 : I64 = 1i64;
|
||||||
|
let Test.5 : Str = CallByName Inspect.33 Test.4;
|
||||||
|
dbg Test.5;
|
||||||
|
dec Test.5;
|
||||||
|
let Test.9 : I64 = 2i64;
|
||||||
|
let Test.3 : I64 = CallByName Num.19 Test.4 Test.9;
|
||||||
|
let Test.6 : Str = CallByName Inspect.33 Test.3;
|
||||||
|
dbg Test.6;
|
||||||
|
dec Test.6;
|
||||||
|
ret Test.3;
|
|
@ -3,8 +3,8 @@ procedure Bool.11 (#Attr.2, #Attr.3):
|
||||||
ret Bool.23;
|
ret Bool.23;
|
||||||
|
|
||||||
procedure Str.3 (#Attr.2, #Attr.3):
|
procedure Str.3 (#Attr.2, #Attr.3):
|
||||||
let Str.237 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
let Str.247 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||||
ret Str.237;
|
ret Str.247;
|
||||||
|
|
||||||
procedure Test.2 (Test.7):
|
procedure Test.2 (Test.7):
|
||||||
let Test.24 : Str = ".trace(\"";
|
let Test.24 : Str = ".trace(\"";
|
||||||
|
|
|
@ -3,8 +3,8 @@ procedure Num.20 (#Attr.2, #Attr.3):
|
||||||
ret Num.281;
|
ret Num.281;
|
||||||
|
|
||||||
procedure Str.3 (#Attr.2, #Attr.3):
|
procedure Str.3 (#Attr.2, #Attr.3):
|
||||||
let Str.238 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
let Str.248 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||||
ret Str.238;
|
ret Str.248;
|
||||||
|
|
||||||
procedure Test.11 (Test.29, #Attr.12):
|
procedure Test.11 (Test.29, #Attr.12):
|
||||||
let Test.32 : {} = UnionAtIndex (Id 0) (Index 0) #Attr.12;
|
let Test.32 : {} = UnionAtIndex (Id 0) (Index 0) #Attr.12;
|
||||||
|
|
|
@ -99,12 +99,12 @@ procedure Num.96 (#Attr.2):
|
||||||
ret Num.281;
|
ret Num.281;
|
||||||
|
|
||||||
procedure Str.12 (#Attr.2):
|
procedure Str.12 (#Attr.2):
|
||||||
let Str.237 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
let Str.247 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||||
ret Str.237;
|
ret Str.247;
|
||||||
|
|
||||||
procedure Str.36 (#Attr.2):
|
procedure Str.36 (#Attr.2):
|
||||||
let Str.238 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
let Str.248 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||||
ret Str.238;
|
ret Str.248;
|
||||||
|
|
||||||
procedure Test.20 (Test.58):
|
procedure Test.20 (Test.58):
|
||||||
let Test.295 : Str = CallByName Encode.23 Test.58;
|
let Test.295 : Str = CallByName Encode.23 Test.58;
|
||||||
|
|
|
@ -192,12 +192,12 @@ procedure Num.96 (#Attr.2):
|
||||||
ret Num.285;
|
ret Num.285;
|
||||||
|
|
||||||
procedure Str.12 (#Attr.2):
|
procedure Str.12 (#Attr.2):
|
||||||
let Str.240 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
let Str.250 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||||
ret Str.240;
|
ret Str.250;
|
||||||
|
|
||||||
procedure Str.36 (#Attr.2):
|
procedure Str.36 (#Attr.2):
|
||||||
let Str.241 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
let Str.251 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||||
ret Str.241;
|
ret Str.251;
|
||||||
|
|
||||||
procedure Test.20 (Test.58):
|
procedure Test.20 (Test.58):
|
||||||
inc Test.58;
|
inc Test.58;
|
||||||
|
|
|
@ -3295,6 +3295,18 @@ fn dbg_inside_string() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[mono_test]
|
||||||
|
fn pizza_dbg() {
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
1
|
||||||
|
|> dbg
|
||||||
|
|> Num.add 2
|
||||||
|
|> dbg
|
||||||
|
"#
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[mono_test]
|
#[mono_test]
|
||||||
fn linked_list_reverse() {
|
fn linked_list_reverse() {
|
||||||
indoc!(
|
indoc!(
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Expr(If(IndentElseBranch(@31), @0), @0)
|
|
@ -0,0 +1,4 @@
|
||||||
|
if thing then
|
||||||
|
whatever
|
||||||
|
else
|
||||||
|
something better
|
|
@ -1,6 +1,6 @@
|
||||||
SpaceAfter(
|
SpaceAfter(
|
||||||
If(
|
If {
|
||||||
[
|
if_thens: [
|
||||||
(
|
(
|
||||||
@3-6 Var {
|
@3-6 Var {
|
||||||
module_name: "",
|
module_name: "",
|
||||||
|
@ -60,7 +60,7 @@ SpaceAfter(
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@49-50 SpaceBefore(
|
final_else: @49-50 SpaceBefore(
|
||||||
Var {
|
Var {
|
||||||
module_name: "",
|
module_name: "",
|
||||||
ident: "c",
|
ident: "c",
|
||||||
|
@ -71,7 +71,8 @@ SpaceAfter(
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
indented_else: false,
|
||||||
|
},
|
||||||
[
|
[
|
||||||
LineComment(
|
LineComment(
|
||||||
" 4",
|
" 4",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
SpaceAfter(
|
SpaceAfter(
|
||||||
If(
|
If {
|
||||||
[
|
if_thens: [
|
||||||
(
|
(
|
||||||
@3-5 Var {
|
@3-5 Var {
|
||||||
module_name: "",
|
module_name: "",
|
||||||
|
@ -40,7 +40,7 @@ SpaceAfter(
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@42-43 SpaceBefore(
|
final_else: @42-43 SpaceBefore(
|
||||||
Num(
|
Num(
|
||||||
"3",
|
"3",
|
||||||
),
|
),
|
||||||
|
@ -48,7 +48,8 @@ SpaceAfter(
|
||||||
Newline,
|
Newline,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
indented_else: false,
|
||||||
|
},
|
||||||
[
|
[
|
||||||
Newline,
|
Newline,
|
||||||
],
|
],
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
1 |> dbg
|
|
@ -0,0 +1,16 @@
|
||||||
|
SpaceAfter(
|
||||||
|
BinOps(
|
||||||
|
[
|
||||||
|
(
|
||||||
|
@0-1 Num(
|
||||||
|
"1",
|
||||||
|
),
|
||||||
|
@2-4 Pizza,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
@5-8 Dbg,
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
)
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue