mirror of
https://github.com/roc-lang/roc.git
synced 2025-11-25 13:36:37 +00:00
Merge branch 'main' into builtin-task
This commit is contained in:
commit
7e72541a79
82 changed files with 2468 additions and 1003 deletions
|
|
@ -30,7 +30,7 @@ rustflags = ["-Clink-args=/FORCE:UNRESOLVED"]
|
||||||
# https://github.com/rust-lang/cargo/issues/3946#issuecomment-973132993
|
# https://github.com/rust-lang/cargo/issues/3946#issuecomment-973132993
|
||||||
ROC_WORKSPACE_DIR = { value = "", relative = true }
|
ROC_WORKSPACE_DIR = { value = "", relative = true }
|
||||||
|
|
||||||
# Debug flags. Keep this up-to-date with compiler/debug_flags/src/lib.rs.
|
# Debug flags. Explanations for these are in compiler/debug_flags/src/lib.rs.
|
||||||
# Set = "1" to turn a debug flag on.
|
# Set = "1" to turn a debug flag on.
|
||||||
ROC_PRETTY_PRINT_ALIAS_CONTENTS = "0"
|
ROC_PRETTY_PRINT_ALIAS_CONTENTS = "0"
|
||||||
ROC_PRINT_UNIFICATIONS = "0"
|
ROC_PRINT_UNIFICATIONS = "0"
|
||||||
|
|
@ -49,6 +49,7 @@ ROC_PRINT_IR_AFTER_TRMC = "0"
|
||||||
ROC_PRINT_IR_AFTER_DROP_SPECIALIZATION = "0"
|
ROC_PRINT_IR_AFTER_DROP_SPECIALIZATION = "0"
|
||||||
ROC_DEBUG_ALIAS_ANALYSIS = "0"
|
ROC_DEBUG_ALIAS_ANALYSIS = "0"
|
||||||
ROC_PRINT_RUNTIME_ERROR_GEN = "0"
|
ROC_PRINT_RUNTIME_ERROR_GEN = "0"
|
||||||
|
ROC_NO_UNBOUND_LAYOUT = "0"
|
||||||
ROC_PRINT_LLVM_FN_VERIFICATION = "0"
|
ROC_PRINT_LLVM_FN_VERIFICATION = "0"
|
||||||
ROC_WRITE_FINAL_WASM = "0"
|
ROC_WRITE_FINAL_WASM = "0"
|
||||||
ROC_LOG_WASM_INTERP = "0"
|
ROC_LOG_WASM_INTERP = "0"
|
||||||
|
|
|
||||||
4
.github/workflows/ubuntu_x86_64_debug.yml
vendored
4
.github/workflows/ubuntu_x86_64_debug.yml
vendored
|
|
@ -31,8 +31,12 @@ jobs:
|
||||||
sudo ln -s /usr/bin/lld-16 /usr/bin/ld.lld
|
sudo ln -s /usr/bin/lld-16 /usr/bin/ld.lld
|
||||||
sudo apt -y install libpolly-16-dev
|
sudo apt -y install libpolly-16-dev
|
||||||
|
|
||||||
|
- name: Check if debug flag files are in sync
|
||||||
|
run: ./ci/check_debug_vars.sh
|
||||||
|
|
||||||
# for skipped tests; see #6946, #6947
|
# for skipped tests; see #6946, #6947
|
||||||
- name: cargo test without --release
|
- name: cargo test without --release
|
||||||
env:
|
env:
|
||||||
RUSTFLAGS: -C link-arg=-fuse-ld=lld
|
RUSTFLAGS: -C link-arg=-fuse-ld=lld
|
||||||
|
ROC_CHECK_MONO_IR: 1
|
||||||
run: cargo test -- --skip tests/exhaustive/match_on_result_with_uninhabited_error_destructuring_in_lambda_syntax.txt --skip tests::identity_lambda --skip tests::issue_2300 --skip tests::issue_2582_specialize_result_value --skip tests::sum_lambda
|
run: cargo test -- --skip tests/exhaustive/match_on_result_with_uninhabited_error_destructuring_in_lambda_syntax.txt --skip tests::identity_lambda --skip tests::issue_2300 --skip tests::issue_2582_specialize_result_value --skip tests::sum_lambda
|
||||||
|
|
|
||||||
|
|
@ -43,19 +43,9 @@ Execute `cargo fmt --all` to fix the formatting.
|
||||||
- The [compiler's README](https://github.com/roc-lang/roc/tree/main/crates/compiler) contains important info.
|
- The [compiler's README](https://github.com/roc-lang/roc/tree/main/crates/compiler) contains important info.
|
||||||
- The AI chat in the [cursor editor](https://www.cursor.com/) can also help you find your way in the codebase.
|
- The AI chat in the [cursor editor](https://www.cursor.com/) can also help you find your way in the codebase.
|
||||||
|
|
||||||
<details>
|
### Debugging tips
|
||||||
<summary>:beetle: Debugging Tips</summary>
|
|
||||||
- Use a debug build of the compiler. We have many asserts enabled in the debug compiler that can alert you to something going wrong. When building from source, build the debug compiler with `cargo build --bin roc`, the binary is at roc/target/debug/roc. When using roc through a nix flake like in [basic-cli](https://github.com/roc-lang/basic-cli), use `rocPkgs.cli-debug` instead of `rocPkgs.cli`.
|
|
||||||
- At the bottom of [.cargo/config.toml](https://github.com/roc-lang/roc/blob/main/.cargo/config.toml) we have useful debug flags that activate certain debug prints.
|
|
||||||
- For Roc code; minimize the code that produces the issue.
|
|
||||||
- For segmentation faults:
|
|
||||||
+ In general we recommend using linux to investigate, it has better tools for this.
|
|
||||||
+ Use `roc build myApp.roc --linker=legacy` followed by `valgrind ./myApp`.
|
|
||||||
+ Use gdb to step through the code, [this gdb script](https://roc.zulipchat.com/#narrow/stream/395097-compiler-development/topic/gdb.20script/near/424422545) can be helpful.
|
|
||||||
+ Inspect the generated LLVM IR (`roc build myApp.roc --emit-llvm-ir`) between Roc code that encounters the segfault and code that doesn't.
|
|
||||||
|
|
||||||
|
|
||||||
</details>
|
If you need to do some debugging, check out [our tips](devtools/debug_tips.md).
|
||||||
|
|
||||||
### Commit signing
|
### Commit signing
|
||||||
|
|
||||||
|
|
|
||||||
22
ci/check_debug_vars.sh
Executable file
22
ci/check_debug_vars.sh
Executable file
|
|
@ -0,0 +1,22 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Extract vars from .cargo/config.toml
|
||||||
|
config_vars=$(grep -E "^ROC_.*= \"[01]\"" .cargo/config.toml | cut -d'=' -f1 | tr -d ' ')
|
||||||
|
|
||||||
|
# Extract vars from crates/compiler/debug_flags/src/lib.rs
|
||||||
|
lib_vars=$(grep -E "^ ROC_.*" crates/compiler/debug_flags/src/lib.rs | tr -d ' ')
|
||||||
|
|
||||||
|
# Sort both lists
|
||||||
|
sorted_config_vars=$(echo "$config_vars" | sort)
|
||||||
|
sorted_lib_vars=$(echo "$lib_vars" | sort)
|
||||||
|
|
||||||
|
# Compare the sorted lists
|
||||||
|
if diff <(echo "$sorted_config_vars") <(echo "$sorted_lib_vars") > /dev/null; then
|
||||||
|
echo "The flags in both files are identical."
|
||||||
|
else
|
||||||
|
echo "Looks like some flags are out of sync between .cargo/config.toml and crates/compiler/debug_flags/src/lib.rs:"
|
||||||
|
diff <(echo "$sorted_config_vars") <(echo "$sorted_lib_vars")
|
||||||
|
fi
|
||||||
|
|
@ -5,11 +5,12 @@ use std::path::{Path, PathBuf};
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_error_macros::{internal_error, user_error};
|
use roc_error_macros::{internal_error, user_error};
|
||||||
use roc_fmt::def::fmt_defs;
|
use roc_fmt::def::fmt_defs;
|
||||||
use roc_fmt::module::fmt_module;
|
use roc_fmt::header::fmt_header;
|
||||||
use roc_fmt::{Ast, Buf};
|
use roc_fmt::Buf;
|
||||||
use roc_parse::module::parse_module_defs;
|
use roc_parse::ast::{FullAst, SpacesBefore};
|
||||||
|
use roc_parse::header::parse_module_defs;
|
||||||
use roc_parse::remove_spaces::RemoveSpaces;
|
use roc_parse::remove_spaces::RemoveSpaces;
|
||||||
use roc_parse::{module, parser::SyntaxError, state::State};
|
use roc_parse::{header, parser::SyntaxError, state::State};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub enum FormatMode {
|
pub enum FormatMode {
|
||||||
|
|
@ -230,19 +231,25 @@ pub fn format_src(arena: &Bump, src: &str) -> Result<String, FormatProblem> {
|
||||||
Ok(buf.as_str().to_string())
|
Ok(buf.as_str().to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_all<'a>(arena: &'a Bump, src: &'a str) -> Result<Ast<'a>, SyntaxError<'a>> {
|
fn parse_all<'a>(arena: &'a Bump, src: &'a str) -> Result<FullAst<'a>, SyntaxError<'a>> {
|
||||||
let (module, state) = module::parse_header(arena, State::new(src.as_bytes()))
|
let (header, state) = header::parse_header(arena, State::new(src.as_bytes()))
|
||||||
.map_err(|e| SyntaxError::Header(e.problem))?;
|
.map_err(|e| SyntaxError::Header(e.problem))?;
|
||||||
|
|
||||||
let (module, defs) = module.upgrade_header_imports(arena);
|
let (h, defs) = header.item.upgrade_header_imports(arena);
|
||||||
|
|
||||||
let defs = parse_module_defs(arena, state, defs)?;
|
let defs = parse_module_defs(arena, state, defs)?;
|
||||||
|
|
||||||
Ok(Ast { module, defs })
|
Ok(FullAst {
|
||||||
|
header: SpacesBefore {
|
||||||
|
before: header.before,
|
||||||
|
item: h,
|
||||||
|
},
|
||||||
|
defs,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fmt_all<'a>(buf: &mut Buf<'a>, ast: &'a Ast) {
|
fn fmt_all<'a>(buf: &mut Buf<'a>, ast: &'a FullAst) {
|
||||||
fmt_module(buf, &ast.module);
|
fmt_header(buf, &ast.header);
|
||||||
|
|
||||||
fmt_defs(buf, &ast.defs, 0);
|
fmt_defs(buf, &ast.defs, 0);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -432,6 +432,14 @@ pub fn build_app() -> Command {
|
||||||
.action(ArgAction::SetTrue)
|
.action(ArgAction::SetTrue)
|
||||||
.required(false)
|
.required(false)
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new(FLAG_TARGET)
|
||||||
|
.long(FLAG_TARGET)
|
||||||
|
.help("Choose a different target")
|
||||||
|
.default_value(Into::<&'static str>::into(Target::default()))
|
||||||
|
.value_parser(build_target_values_parser.clone())
|
||||||
|
.required(false),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
.arg(flag_optimize)
|
.arg(flag_optimize)
|
||||||
.arg(flag_max_threads)
|
.arg(flag_max_threads)
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ main =
|
||||||
a: Task.ok 123,
|
a: Task.ok 123,
|
||||||
b: Task.ok "abc",
|
b: Task.ok "abc",
|
||||||
c: Task.ok [123],
|
c: Task.ok [123],
|
||||||
d: Task.ok ["abc"],
|
_d: Task.ok ["abc"],
|
||||||
e: Task.ok (Dict.single "a" "b"),
|
_: Task.ok (Dict.single "a" "b"),
|
||||||
}!
|
}!
|
||||||
|
|
||||||
Stdout.line! "For multiple tasks: $(Inspect.toStr multipleIn)"
|
Stdout.line! "For multiple tasks: $(Inspect.toStr multipleIn)"
|
||||||
|
|
|
||||||
|
|
@ -711,6 +711,17 @@ mod cli_run {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg_attr(windows, ignore)]
|
||||||
|
fn platform_requires_pkg() {
|
||||||
|
test_roc_app_slim(
|
||||||
|
"crates/cli/tests/platform_requires_pkg",
|
||||||
|
"app.roc",
|
||||||
|
"from app from package",
|
||||||
|
UseValgrind::No,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg_attr(windows, ignore)]
|
#[cfg_attr(windows, ignore)]
|
||||||
fn transitive_expects() {
|
fn transitive_expects() {
|
||||||
|
|
@ -947,7 +958,7 @@ mod cli_run {
|
||||||
&[],
|
&[],
|
||||||
&[],
|
&[],
|
||||||
&[],
|
&[],
|
||||||
"For multiple tasks: {a: 123, b: \"abc\", c: [123], d: [\"abc\"], e: {\"a\": \"b\"}}\n",
|
"For multiple tasks: {a: 123, b: \"abc\", c: [123]}\n",
|
||||||
UseValgrind::No,
|
UseValgrind::No,
|
||||||
TestCliCommands::Run,
|
TestCliCommands::Run,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
6
crates/cli/tests/platform_requires_pkg/app.roc
Normal file
6
crates/cli/tests/platform_requires_pkg/app.roc
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
app [main] {
|
||||||
|
pf: platform "./platform/main.roc"
|
||||||
|
}
|
||||||
|
|
||||||
|
main =
|
||||||
|
"from app"
|
||||||
3
crates/cli/tests/platform_requires_pkg/foo/Foo.roc
Normal file
3
crates/cli/tests/platform_requires_pkg/foo/Foo.roc
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
module [foo]
|
||||||
|
|
||||||
|
foo = "from package"
|
||||||
1
crates/cli/tests/platform_requires_pkg/foo/main.roc
Normal file
1
crates/cli/tests/platform_requires_pkg/foo/main.roc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
package [Foo] {}
|
||||||
129
crates/cli/tests/platform_requires_pkg/platform/host.zig
Normal file
129
crates/cli/tests/platform_requires_pkg/platform/host.zig
Normal file
|
|
@ -0,0 +1,129 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const str = @import("glue").str;
|
||||||
|
const RocStr = str.RocStr;
|
||||||
|
const testing = std.testing;
|
||||||
|
const expectEqual = testing.expectEqual;
|
||||||
|
const expect = testing.expect;
|
||||||
|
|
||||||
|
const Align = 2 * @alignOf(usize);
|
||||||
|
extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque;
|
||||||
|
extern fn realloc(c_ptr: [*]align(Align) u8, size: usize) callconv(.C) ?*anyopaque;
|
||||||
|
extern fn free(c_ptr: [*]align(Align) u8) callconv(.C) void;
|
||||||
|
extern fn memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void;
|
||||||
|
extern fn memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void;
|
||||||
|
|
||||||
|
const DEBUG: bool = false;
|
||||||
|
|
||||||
|
export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*anyopaque {
|
||||||
|
if (DEBUG) {
|
||||||
|
var ptr = malloc(size);
|
||||||
|
const stdout = std.io.getStdOut().writer();
|
||||||
|
stdout.print("alloc: {d} (alignment {d}, size {d})\n", .{ ptr, alignment, size }) catch unreachable;
|
||||||
|
return ptr;
|
||||||
|
} else {
|
||||||
|
return malloc(size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn roc_realloc(c_ptr: *anyopaque, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*anyopaque {
|
||||||
|
if (DEBUG) {
|
||||||
|
const stdout = std.io.getStdOut().writer();
|
||||||
|
stdout.print("realloc: {d} (alignment {d}, old_size {d})\n", .{ c_ptr, alignment, old_size }) catch unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
return realloc(@as([*]align(Align) u8, @alignCast(@ptrCast(c_ptr))), new_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
|
||||||
|
if (DEBUG) {
|
||||||
|
const stdout = std.io.getStdOut().writer();
|
||||||
|
stdout.print("dealloc: {d} (alignment {d})\n", .{ c_ptr, alignment }) catch unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(@as([*]align(Align) u8, @alignCast(@ptrCast(c_ptr))));
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn roc_panic(msg: *RocStr, tag_id: u32) callconv(.C) void {
|
||||||
|
_ = tag_id;
|
||||||
|
|
||||||
|
const stderr = std.io.getStdErr().writer();
|
||||||
|
stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable;
|
||||||
|
std.process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn roc_dbg(loc: *RocStr, msg: *RocStr, src: *RocStr) callconv(.C) void {
|
||||||
|
// This platform uses stdout for testing purposes instead of the normal stderr.
|
||||||
|
const stdout = std.io.getStdOut().writer();
|
||||||
|
stdout.print("[{s}] {s} = {s}\n", .{ loc.asSlice(), src.asSlice(), msg.asSlice() }) catch unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
||||||
|
return memset(dst, value, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern fn kill(pid: c_int, sig: c_int) c_int;
|
||||||
|
extern fn shm_open(name: *const i8, oflag: c_int, mode: c_uint) c_int;
|
||||||
|
extern fn mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) *anyopaque;
|
||||||
|
extern fn getppid() c_int;
|
||||||
|
|
||||||
|
fn roc_getppid() callconv(.C) c_int {
|
||||||
|
return getppid();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn roc_getppid_windows_stub() callconv(.C) c_int {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn roc_send_signal(pid: c_int, sig: c_int) callconv(.C) c_int {
|
||||||
|
return kill(pid, sig);
|
||||||
|
}
|
||||||
|
fn roc_shm_open(name: *const i8, oflag: c_int, mode: c_uint) callconv(.C) c_int {
|
||||||
|
return shm_open(name, oflag, mode);
|
||||||
|
}
|
||||||
|
fn roc_mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) callconv(.C) *anyopaque {
|
||||||
|
return mmap(addr, length, prot, flags, fd, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
comptime {
|
||||||
|
if (builtin.os.tag == .macos or builtin.os.tag == .linux) {
|
||||||
|
@export(roc_getppid, .{ .name = "roc_getppid", .linkage = .Strong });
|
||||||
|
@export(roc_mmap, .{ .name = "roc_mmap", .linkage = .Strong });
|
||||||
|
@export(roc_send_signal, .{ .name = "roc_send_signal", .linkage = .Strong });
|
||||||
|
@export(roc_shm_open, .{ .name = "roc_shm_open", .linkage = .Strong });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (builtin.os.tag == .windows) {
|
||||||
|
@export(roc_getppid_windows_stub, .{ .name = "roc_getppid", .linkage = .Strong });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mem = std.mem;
|
||||||
|
const Allocator = mem.Allocator;
|
||||||
|
|
||||||
|
extern fn roc__mainForHost_1_exposed_generic(*RocStr) void;
|
||||||
|
|
||||||
|
const Unit = extern struct {};
|
||||||
|
|
||||||
|
pub fn main() u8 {
|
||||||
|
const stdout = std.io.getStdOut().writer();
|
||||||
|
const stderr = std.io.getStdErr().writer();
|
||||||
|
|
||||||
|
var timer = std.time.Timer.start() catch unreachable;
|
||||||
|
|
||||||
|
// actually call roc to populate the callresult
|
||||||
|
var callresult = RocStr.empty();
|
||||||
|
roc__mainForHost_1_exposed_generic(&callresult);
|
||||||
|
|
||||||
|
const nanos = timer.read();
|
||||||
|
const seconds = (@as(f64, @floatFromInt(nanos)) / 1_000_000_000.0);
|
||||||
|
|
||||||
|
// stdout the result
|
||||||
|
stdout.print("{s}", .{callresult.asSlice()}) catch unreachable;
|
||||||
|
|
||||||
|
callresult.decref();
|
||||||
|
|
||||||
|
stderr.print("runtime: {d:.3}ms\n", .{seconds * 1000}) catch unreachable;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
14
crates/cli/tests/platform_requires_pkg/platform/main.roc
Normal file
14
crates/cli/tests/platform_requires_pkg/platform/main.roc
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
platform "test"
|
||||||
|
requires {} { main : _ }
|
||||||
|
exposes []
|
||||||
|
packages {
|
||||||
|
foo: "../foo/main.roc",
|
||||||
|
}
|
||||||
|
imports []
|
||||||
|
provides [mainForHost]
|
||||||
|
|
||||||
|
import foo.Foo
|
||||||
|
|
||||||
|
mainForHost : Str
|
||||||
|
mainForHost =
|
||||||
|
"$(main) $(Foo.foo)"
|
||||||
|
|
@ -708,6 +708,9 @@ absDiff = \a, b ->
|
||||||
##
|
##
|
||||||
## Num.neg 0.0
|
## Num.neg 0.0
|
||||||
## ```
|
## ```
|
||||||
|
## !! Num.neg is not completely implemented for all types in all contexts, see github.com/roc-lang/roc/issues/6959
|
||||||
|
## You can use `\someNum -> 0 - someNum` as a workaround.
|
||||||
|
##
|
||||||
## This is safe to use with any [Frac], but it can cause overflow when used with certain [Int] values.
|
## This is safe to use with any [Frac], but it can cause overflow when used with certain [Int] values.
|
||||||
##
|
##
|
||||||
## For example, calling #Num.neg on the lowest value of a signed integer (such as [Num.minI64] or [Num.minI32]) will cause overflow.
|
## For example, calling #Num.neg on the lowest value of a signed integer (such as [Num.minI64] or [Num.minI32]) will cause overflow.
|
||||||
|
|
|
||||||
|
|
@ -467,7 +467,8 @@ pub fn find_type_def_symbols(
|
||||||
while let Some(assigned_field) = inner_stack.pop() {
|
while let Some(assigned_field) = inner_stack.pop() {
|
||||||
match assigned_field {
|
match assigned_field {
|
||||||
AssignedField::RequiredValue(_, _, t)
|
AssignedField::RequiredValue(_, _, t)
|
||||||
| AssignedField::OptionalValue(_, _, t) => {
|
| AssignedField::OptionalValue(_, _, t)
|
||||||
|
| AssignedField::IgnoredValue(_, _, t) => {
|
||||||
stack.push(&t.value);
|
stack.push(&t.value);
|
||||||
}
|
}
|
||||||
AssignedField::LabelOnly(_) => {}
|
AssignedField::LabelOnly(_) => {}
|
||||||
|
|
@ -1386,6 +1387,7 @@ fn can_assigned_fields<'a>(
|
||||||
|
|
||||||
break 'inner label;
|
break 'inner label;
|
||||||
}
|
}
|
||||||
|
IgnoredValue(_, _, _) => unreachable!(),
|
||||||
LabelOnly(loc_field_name) => {
|
LabelOnly(loc_field_name) => {
|
||||||
// Interpret { a, b } as { a : a, b : b }
|
// Interpret { a, b } as { a : a, b : b }
|
||||||
let field_name = Lowercase::from(loc_field_name.value);
|
let field_name = Lowercase::from(loc_field_name.value);
|
||||||
|
|
|
||||||
|
|
@ -631,7 +631,9 @@ fn canonicalize_claimed_ability_impl<'a>(
|
||||||
// An error will already have been reported
|
// An error will already have been reported
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
AssignedField::SpaceBefore(_, _) | AssignedField::SpaceAfter(_, _) => {
|
AssignedField::SpaceBefore(_, _)
|
||||||
|
| AssignedField::SpaceAfter(_, _)
|
||||||
|
| AssignedField::IgnoredValue(_, _, _) => {
|
||||||
internal_error!("unreachable")
|
internal_error!("unreachable")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -521,44 +521,68 @@ pub fn desugar_expr<'a>(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut field_names = Vec::with_capacity_in(fields.len(), arena);
|
struct FieldData<'d> {
|
||||||
let mut field_vals = Vec::with_capacity_in(fields.len(), arena);
|
name: Loc<&'d str>,
|
||||||
|
value: &'d Loc<Expr<'d>>,
|
||||||
for field in fields.items {
|
ignored: bool,
|
||||||
match desugar_field(arena, &field.value, src, line_info, module_path) {
|
|
||||||
AssignedField::RequiredValue(loc_name, _, loc_val) => {
|
|
||||||
field_names.push(loc_name);
|
|
||||||
field_vals.push(loc_val);
|
|
||||||
}
|
|
||||||
AssignedField::LabelOnly(loc_name) => {
|
|
||||||
field_names.push(loc_name);
|
|
||||||
field_vals.push(arena.alloc(Loc {
|
|
||||||
region: loc_name.region,
|
|
||||||
value: Expr::Var {
|
|
||||||
module_name: "",
|
|
||||||
ident: loc_name.value,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
AssignedField::OptionalValue(loc_name, _, loc_val) => {
|
|
||||||
return arena.alloc(Loc {
|
|
||||||
region: loc_expr.region,
|
|
||||||
value: OptionalFieldInRecordBuilder(arena.alloc(loc_name), loc_val),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
AssignedField::SpaceBefore(_, _) | AssignedField::SpaceAfter(_, _) => {
|
|
||||||
unreachable!("Should have been desugared in `desugar_field`")
|
|
||||||
}
|
|
||||||
AssignedField::Malformed(_name) => {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let closure_arg_from_field = |field: Loc<&'a str>| Loc {
|
let mut field_data = Vec::with_capacity_in(fields.len(), arena);
|
||||||
region: field.region,
|
|
||||||
value: Pattern::Identifier {
|
for field in fields.items {
|
||||||
ident: arena.alloc_str(&format!("#{}", field.value)),
|
let (name, value, ignored) =
|
||||||
},
|
match desugar_field(arena, &field.value, src, line_info, module_path) {
|
||||||
};
|
AssignedField::RequiredValue(loc_name, _, loc_val) => {
|
||||||
|
(loc_name, loc_val, false)
|
||||||
|
}
|
||||||
|
AssignedField::IgnoredValue(loc_name, _, loc_val) => {
|
||||||
|
(loc_name, loc_val, true)
|
||||||
|
}
|
||||||
|
AssignedField::LabelOnly(loc_name) => (
|
||||||
|
loc_name,
|
||||||
|
&*arena.alloc(Loc {
|
||||||
|
region: loc_name.region,
|
||||||
|
value: Expr::Var {
|
||||||
|
module_name: "",
|
||||||
|
ident: loc_name.value,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
AssignedField::OptionalValue(loc_name, _, loc_val) => {
|
||||||
|
return arena.alloc(Loc {
|
||||||
|
region: loc_expr.region,
|
||||||
|
value: OptionalFieldInRecordBuilder(arena.alloc(loc_name), loc_val),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
AssignedField::SpaceBefore(_, _) | AssignedField::SpaceAfter(_, _) => {
|
||||||
|
unreachable!("Should have been desugared in `desugar_field`")
|
||||||
|
}
|
||||||
|
AssignedField::Malformed(_name) => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
field_data.push(FieldData {
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
ignored,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let closure_arg_from_field =
|
||||||
|
|FieldData {
|
||||||
|
name,
|
||||||
|
value: _,
|
||||||
|
ignored,
|
||||||
|
}: &FieldData<'a>| Loc {
|
||||||
|
region: name.region,
|
||||||
|
value: if *ignored {
|
||||||
|
Pattern::Underscore(name.value)
|
||||||
|
} else {
|
||||||
|
Pattern::Identifier {
|
||||||
|
ident: arena.alloc_str(&format!("#{}", name.value)),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
let combiner_closure_in_region = |region| {
|
let combiner_closure_in_region = |region| {
|
||||||
let closure_body = Tuple(Collection::with_items(
|
let closure_body = Tuple(Collection::with_items(
|
||||||
|
|
@ -607,15 +631,15 @@ pub fn desugar_expr<'a>(
|
||||||
};
|
};
|
||||||
|
|
||||||
let closure_args = {
|
let closure_args = {
|
||||||
if field_names.len() == 2 {
|
if field_data.len() == 2 {
|
||||||
arena.alloc_slice_copy(&[
|
arena.alloc_slice_copy(&[
|
||||||
closure_arg_from_field(field_names[0]),
|
closure_arg_from_field(&field_data[0]),
|
||||||
closure_arg_from_field(field_names[1]),
|
closure_arg_from_field(&field_data[1]),
|
||||||
])
|
])
|
||||||
} else {
|
} else {
|
||||||
let second_to_last_arg =
|
let second_to_last_arg =
|
||||||
closure_arg_from_field(field_names[field_names.len() - 2]);
|
closure_arg_from_field(&field_data[field_data.len() - 2]);
|
||||||
let last_arg = closure_arg_from_field(field_names[field_names.len() - 1]);
|
let last_arg = closure_arg_from_field(&field_data[field_data.len() - 1]);
|
||||||
|
|
||||||
let mut second_arg = Pattern::Tuple(Collection::with_items(
|
let mut second_arg = Pattern::Tuple(Collection::with_items(
|
||||||
arena.alloc_slice_copy(&[second_to_last_arg, last_arg]),
|
arena.alloc_slice_copy(&[second_to_last_arg, last_arg]),
|
||||||
|
|
@ -623,18 +647,18 @@ pub fn desugar_expr<'a>(
|
||||||
let mut second_arg_region =
|
let mut second_arg_region =
|
||||||
Region::span_across(&second_to_last_arg.region, &last_arg.region);
|
Region::span_across(&second_to_last_arg.region, &last_arg.region);
|
||||||
|
|
||||||
for index in (1..(field_names.len() - 2)).rev() {
|
for index in (1..(field_data.len() - 2)).rev() {
|
||||||
second_arg =
|
second_arg =
|
||||||
Pattern::Tuple(Collection::with_items(arena.alloc_slice_copy(&[
|
Pattern::Tuple(Collection::with_items(arena.alloc_slice_copy(&[
|
||||||
closure_arg_from_field(field_names[index]),
|
closure_arg_from_field(&field_data[index]),
|
||||||
Loc::at(second_arg_region, second_arg),
|
Loc::at(second_arg_region, second_arg),
|
||||||
])));
|
])));
|
||||||
second_arg_region =
|
second_arg_region =
|
||||||
Region::span_across(&field_names[index].region, &second_arg_region);
|
Region::span_across(&field_data[index].name.region, &second_arg_region);
|
||||||
}
|
}
|
||||||
|
|
||||||
arena.alloc_slice_copy(&[
|
arena.alloc_slice_copy(&[
|
||||||
closure_arg_from_field(field_names[0]),
|
closure_arg_from_field(&field_data[0]),
|
||||||
Loc::at(second_arg_region, second_arg),
|
Loc::at(second_arg_region, second_arg),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
@ -642,22 +666,26 @@ pub fn desugar_expr<'a>(
|
||||||
|
|
||||||
let record_val = Record(Collection::with_items(
|
let record_val = Record(Collection::with_items(
|
||||||
Vec::from_iter_in(
|
Vec::from_iter_in(
|
||||||
field_names.iter().map(|field_name| {
|
field_data
|
||||||
Loc::at(
|
.iter()
|
||||||
field_name.region,
|
.filter(|field| !field.ignored)
|
||||||
AssignedField::RequiredValue(
|
.map(|field| {
|
||||||
Loc::at(field_name.region, field_name.value),
|
Loc::at(
|
||||||
&[],
|
field.name.region,
|
||||||
arena.alloc(Loc::at(
|
AssignedField::RequiredValue(
|
||||||
field_name.region,
|
field.name,
|
||||||
Expr::Var {
|
&[],
|
||||||
module_name: "",
|
arena.alloc(Loc::at(
|
||||||
ident: arena.alloc_str(&format!("#{}", field_name.value)),
|
field.name.region,
|
||||||
},
|
Expr::Var {
|
||||||
)),
|
module_name: "",
|
||||||
),
|
ident: arena
|
||||||
)
|
.alloc_str(&format!("#{}", field.name.value)),
|
||||||
}),
|
},
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}),
|
||||||
arena,
|
arena,
|
||||||
)
|
)
|
||||||
.into_bump_slice(),
|
.into_bump_slice(),
|
||||||
|
|
@ -671,14 +699,14 @@ pub fn desugar_expr<'a>(
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
if field_names.len() == 2 {
|
if field_data.len() == 2 {
|
||||||
return arena.alloc(Loc {
|
return arena.alloc(Loc {
|
||||||
region: loc_expr.region,
|
region: loc_expr.region,
|
||||||
value: Apply(
|
value: Apply(
|
||||||
new_mapper,
|
new_mapper,
|
||||||
arena.alloc_slice_copy(&[
|
arena.alloc_slice_copy(&[
|
||||||
field_vals[0],
|
field_data[0].value,
|
||||||
field_vals[1],
|
field_data[1].value,
|
||||||
record_combiner_closure,
|
record_combiner_closure,
|
||||||
]),
|
]),
|
||||||
CalledVia::RecordBuilder,
|
CalledVia::RecordBuilder,
|
||||||
|
|
@ -688,27 +716,30 @@ pub fn desugar_expr<'a>(
|
||||||
|
|
||||||
let mut inner_combined = arena.alloc(Loc {
|
let mut inner_combined = arena.alloc(Loc {
|
||||||
region: Region::span_across(
|
region: Region::span_across(
|
||||||
&field_vals[field_names.len() - 2].region,
|
&field_data[field_data.len() - 2].value.region,
|
||||||
&field_vals[field_names.len() - 1].region,
|
&field_data[field_data.len() - 1].value.region,
|
||||||
),
|
),
|
||||||
value: Apply(
|
value: Apply(
|
||||||
new_mapper,
|
new_mapper,
|
||||||
arena.alloc_slice_copy(&[
|
arena.alloc_slice_copy(&[
|
||||||
field_vals[field_names.len() - 2],
|
field_data[field_data.len() - 2].value,
|
||||||
field_vals[field_names.len() - 1],
|
field_data[field_data.len() - 1].value,
|
||||||
combiner_closure_in_region(loc_expr.region),
|
combiner_closure_in_region(loc_expr.region),
|
||||||
]),
|
]),
|
||||||
CalledVia::RecordBuilder,
|
CalledVia::RecordBuilder,
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
for index in (1..(field_names.len() - 2)).rev() {
|
for index in (1..(field_data.len() - 2)).rev() {
|
||||||
inner_combined = arena.alloc(Loc {
|
inner_combined = arena.alloc(Loc {
|
||||||
region: Region::span_across(&field_vals[index].region, &inner_combined.region),
|
region: Region::span_across(
|
||||||
|
&field_data[index].value.region,
|
||||||
|
&inner_combined.region,
|
||||||
|
),
|
||||||
value: Apply(
|
value: Apply(
|
||||||
new_mapper,
|
new_mapper,
|
||||||
arena.alloc_slice_copy(&[
|
arena.alloc_slice_copy(&[
|
||||||
field_vals[index],
|
field_data[index].value,
|
||||||
inner_combined,
|
inner_combined,
|
||||||
combiner_closure_in_region(loc_expr.region),
|
combiner_closure_in_region(loc_expr.region),
|
||||||
]),
|
]),
|
||||||
|
|
@ -722,7 +753,7 @@ pub fn desugar_expr<'a>(
|
||||||
value: Apply(
|
value: Apply(
|
||||||
new_mapper,
|
new_mapper,
|
||||||
arena.alloc_slice_copy(&[
|
arena.alloc_slice_copy(&[
|
||||||
field_vals[0],
|
field_data[0].value,
|
||||||
inner_combined,
|
inner_combined,
|
||||||
record_combiner_closure,
|
record_combiner_closure,
|
||||||
]),
|
]),
|
||||||
|
|
@ -1095,6 +1126,14 @@ fn desugar_field<'a>(
|
||||||
spaces,
|
spaces,
|
||||||
desugar_expr(arena, loc_expr, src, line_info, module_path),
|
desugar_expr(arena, loc_expr, src, line_info, module_path),
|
||||||
),
|
),
|
||||||
|
IgnoredValue(loc_str, spaces, loc_expr) => IgnoredValue(
|
||||||
|
Loc {
|
||||||
|
value: loc_str.value,
|
||||||
|
region: loc_str.region,
|
||||||
|
},
|
||||||
|
spaces,
|
||||||
|
desugar_expr(arena, loc_expr, src, line_info, module_path),
|
||||||
|
),
|
||||||
LabelOnly(loc_str) => {
|
LabelOnly(loc_str) => {
|
||||||
// Desugar { x } into { x: x }
|
// Desugar { x } into { x: x }
|
||||||
let loc_expr = Loc {
|
let loc_expr = Loc {
|
||||||
|
|
|
||||||
|
|
@ -1846,6 +1846,11 @@ fn canonicalize_field<'a>(
|
||||||
field_region: Region::span_across(&label.region, &loc_expr.region),
|
field_region: Region::span_across(&label.region, &loc_expr.region),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
// An ignored value, e.g. `{ _name: 123 }`
|
||||||
|
IgnoredValue(_, _, _) => {
|
||||||
|
internal_error!("Somehow an IgnoredValue record field was not desugared!");
|
||||||
|
}
|
||||||
|
|
||||||
// A label with no value, e.g. `{ name }` (this is sugar for { name: name })
|
// A label with no value, e.g. `{ name }` (this is sugar for { name: name })
|
||||||
LabelOnly(_) => {
|
LabelOnly(_) => {
|
||||||
internal_error!("Somehow a LabelOnly record field was not desugared!");
|
internal_error!("Somehow a LabelOnly record field was not desugared!");
|
||||||
|
|
@ -2433,7 +2438,8 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
|
||||||
}
|
}
|
||||||
ast::Expr::Record(fields) => fields.iter().all(|loc_field| match loc_field.value {
|
ast::Expr::Record(fields) => fields.iter().all(|loc_field| match loc_field.value {
|
||||||
ast::AssignedField::RequiredValue(_label, loc_comments, loc_val)
|
ast::AssignedField::RequiredValue(_label, loc_comments, loc_val)
|
||||||
| ast::AssignedField::OptionalValue(_label, loc_comments, loc_val) => {
|
| ast::AssignedField::OptionalValue(_label, loc_comments, loc_val)
|
||||||
|
| ast::AssignedField::IgnoredValue(_label, loc_comments, loc_val) => {
|
||||||
loc_comments.is_empty() && is_valid_interpolation(&loc_val.value)
|
loc_comments.is_empty() && is_valid_interpolation(&loc_val.value)
|
||||||
}
|
}
|
||||||
ast::AssignedField::Malformed(_) | ast::AssignedField::LabelOnly(_) => true,
|
ast::AssignedField::Malformed(_) | ast::AssignedField::LabelOnly(_) => true,
|
||||||
|
|
@ -2481,7 +2487,8 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
|
||||||
is_valid_interpolation(&update.value)
|
is_valid_interpolation(&update.value)
|
||||||
&& fields.iter().all(|loc_field| match loc_field.value {
|
&& fields.iter().all(|loc_field| match loc_field.value {
|
||||||
ast::AssignedField::RequiredValue(_label, loc_comments, loc_val)
|
ast::AssignedField::RequiredValue(_label, loc_comments, loc_val)
|
||||||
| ast::AssignedField::OptionalValue(_label, loc_comments, loc_val) => {
|
| ast::AssignedField::OptionalValue(_label, loc_comments, loc_val)
|
||||||
|
| ast::AssignedField::IgnoredValue(_label, loc_comments, loc_val) => {
|
||||||
loc_comments.is_empty() && is_valid_interpolation(&loc_val.value)
|
loc_comments.is_empty() && is_valid_interpolation(&loc_val.value)
|
||||||
}
|
}
|
||||||
ast::AssignedField::Malformed(_) | ast::AssignedField::LabelOnly(_) => true,
|
ast::AssignedField::Malformed(_) | ast::AssignedField::LabelOnly(_) => true,
|
||||||
|
|
@ -2514,7 +2521,8 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
|
||||||
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 {
|
||||||
ast::AssignedField::RequiredValue(_label, loc_comments, loc_val)
|
ast::AssignedField::RequiredValue(_label, loc_comments, loc_val)
|
||||||
| ast::AssignedField::OptionalValue(_label, loc_comments, loc_val) => {
|
| ast::AssignedField::OptionalValue(_label, loc_comments, loc_val)
|
||||||
|
| ast::AssignedField::IgnoredValue(_label, loc_comments, loc_val) => {
|
||||||
loc_comments.is_empty() && is_valid_interpolation(&loc_val.value)
|
loc_comments.is_empty() && is_valid_interpolation(&loc_val.value)
|
||||||
}
|
}
|
||||||
ast::AssignedField::Malformed(_) | ast::AssignedField::LabelOnly(_) => true,
|
ast::AssignedField::Malformed(_) | ast::AssignedField::LabelOnly(_) => true,
|
||||||
|
|
|
||||||
|
|
@ -428,9 +428,9 @@ fn is_multiline_assigned_field_help<T: Formattable>(afield: &AssignedField<'_, T
|
||||||
use self::AssignedField::*;
|
use self::AssignedField::*;
|
||||||
|
|
||||||
match afield {
|
match afield {
|
||||||
RequiredValue(_, spaces, ann) | OptionalValue(_, spaces, ann) => {
|
RequiredValue(_, spaces, ann)
|
||||||
!spaces.is_empty() || ann.value.is_multiline()
|
| OptionalValue(_, spaces, ann)
|
||||||
}
|
| IgnoredValue(_, spaces, ann) => !spaces.is_empty() || ann.value.is_multiline(),
|
||||||
LabelOnly(_) => false,
|
LabelOnly(_) => false,
|
||||||
AssignedField::SpaceBefore(_, _) | AssignedField::SpaceAfter(_, _) => true,
|
AssignedField::SpaceBefore(_, _) | AssignedField::SpaceAfter(_, _) => true,
|
||||||
Malformed(text) => text.chars().any(|c| c == '\n'),
|
Malformed(text) => text.chars().any(|c| c == '\n'),
|
||||||
|
|
@ -483,6 +483,24 @@ fn format_assigned_field_help<T>(
|
||||||
buf.spaces(1);
|
buf.spaces(1);
|
||||||
ann.value.format(buf, indent);
|
ann.value.format(buf, indent);
|
||||||
}
|
}
|
||||||
|
IgnoredValue(name, spaces, ann) => {
|
||||||
|
if is_multiline {
|
||||||
|
buf.newline();
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.indent(indent);
|
||||||
|
buf.push('_');
|
||||||
|
buf.push_str(name.value);
|
||||||
|
|
||||||
|
if !spaces.is_empty() {
|
||||||
|
fmt_spaces(buf, spaces.iter(), indent);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.spaces(separator_spaces);
|
||||||
|
buf.push(':');
|
||||||
|
buf.spaces(1);
|
||||||
|
ann.value.format(buf, indent);
|
||||||
|
}
|
||||||
LabelOnly(name) => {
|
LabelOnly(name) => {
|
||||||
if is_multiline {
|
if is_multiline {
|
||||||
buf.newline();
|
buf.newline();
|
||||||
|
|
|
||||||
|
|
@ -1529,6 +1529,23 @@ fn format_assigned_field_multiline<T>(
|
||||||
ann.value.format(buf, indent);
|
ann.value.format(buf, indent);
|
||||||
buf.push(',');
|
buf.push(',');
|
||||||
}
|
}
|
||||||
|
IgnoredValue(name, spaces, ann) => {
|
||||||
|
buf.newline();
|
||||||
|
buf.indent(indent);
|
||||||
|
buf.push('_');
|
||||||
|
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(":");
|
||||||
|
buf.spaces(1);
|
||||||
|
ann.value.format(buf, indent);
|
||||||
|
buf.push(',');
|
||||||
|
}
|
||||||
LabelOnly(name) => {
|
LabelOnly(name) => {
|
||||||
buf.newline();
|
buf.newline();
|
||||||
buf.indent(indent);
|
buf.indent(indent);
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use crate::collection::{fmt_collection, Braces};
|
||||||
use crate::expr::fmt_str_literal;
|
use crate::expr::fmt_str_literal;
|
||||||
use crate::spaces::{fmt_comments_only, fmt_default_spaces, fmt_spaces, NewlineAt, INDENT};
|
use crate::spaces::{fmt_comments_only, fmt_default_spaces, fmt_spaces, NewlineAt, INDENT};
|
||||||
use crate::Buf;
|
use crate::Buf;
|
||||||
use roc_parse::ast::{Collection, CommentOrNewline, Header, Module, Spaced, Spaces};
|
use roc_parse::ast::{Collection, CommentOrNewline, Header, Spaced, Spaces, SpacesBefore};
|
||||||
use roc_parse::header::{
|
use roc_parse::header::{
|
||||||
AppHeader, ExposedName, ExposesKeyword, HostedHeader, ImportsEntry, ImportsKeyword, Keyword,
|
AppHeader, ExposedName, ExposesKeyword, HostedHeader, ImportsEntry, ImportsKeyword, Keyword,
|
||||||
KeywordItem, ModuleHeader, ModuleName, PackageEntry, PackageHeader, PackageKeyword,
|
KeywordItem, ModuleHeader, ModuleName, PackageEntry, PackageHeader, PackageKeyword,
|
||||||
|
|
@ -15,9 +15,9 @@ use roc_parse::header::{
|
||||||
use roc_parse::ident::UppercaseIdent;
|
use roc_parse::ident::UppercaseIdent;
|
||||||
use roc_region::all::Loc;
|
use roc_region::all::Loc;
|
||||||
|
|
||||||
pub fn fmt_module<'a>(buf: &mut Buf<'_>, module: &'a Module<'a>) {
|
pub fn fmt_header<'a>(buf: &mut Buf<'_>, header: &'a SpacesBefore<'a, Header<'a>>) {
|
||||||
fmt_comments_only(buf, module.comments.iter(), NewlineAt::Bottom, 0);
|
fmt_comments_only(buf, header.before.iter(), NewlineAt::Bottom, 0);
|
||||||
match &module.header {
|
match &header.item {
|
||||||
Header::Module(header) => {
|
Header::Module(header) => {
|
||||||
fmt_module_header(buf, header);
|
fmt_module_header(buf, header);
|
||||||
}
|
}
|
||||||
|
|
@ -6,18 +6,11 @@ pub mod annotation;
|
||||||
pub mod collection;
|
pub mod collection;
|
||||||
pub mod def;
|
pub mod def;
|
||||||
pub mod expr;
|
pub mod expr;
|
||||||
pub mod module;
|
pub mod header;
|
||||||
pub mod pattern;
|
pub mod pattern;
|
||||||
pub mod spaces;
|
pub mod spaces;
|
||||||
|
|
||||||
use bumpalo::{collections::String, Bump};
|
use bumpalo::{collections::String, Bump};
|
||||||
use roc_parse::ast::Module;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Ast<'a> {
|
|
||||||
pub module: Module<'a>,
|
|
||||||
pub defs: roc_parse::ast::Defs<'a>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Buf<'a> {
|
pub struct Buf<'a> {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
use bumpalo::Bump;
|
use roc_parse::ast::CommentOrNewline;
|
||||||
use roc_parse::{ast::CommentOrNewline, remove_spaces::RemoveSpaces};
|
|
||||||
|
|
||||||
use crate::{Ast, Buf};
|
use crate::Buf;
|
||||||
|
|
||||||
/// The number of spaces to indent.
|
/// The number of spaces to indent.
|
||||||
pub const INDENT: u16 = 4;
|
pub const INDENT: u16 = 4;
|
||||||
|
|
@ -192,12 +191,3 @@ fn fmt_docs(buf: &mut Buf, docs: &str) {
|
||||||
}
|
}
|
||||||
buf.push_str(docs.trim_end());
|
buf.push_str(docs.trim_end());
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RemoveSpaces<'a> for Ast<'a> {
|
|
||||||
fn remove_spaces(&self, arena: &'a Bump) -> Self {
|
|
||||||
Ast {
|
|
||||||
module: self.module.remove_spaces(arena),
|
|
||||||
defs: self.defs.remove_spaces(arena),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ mod test_reporting {
|
||||||
use roc_load::{self, ExecutionMode, LoadConfig, LoadedModule, LoadingProblem, Threading};
|
use roc_load::{self, ExecutionMode, LoadConfig, LoadedModule, LoadingProblem, Threading};
|
||||||
use roc_module::symbol::{Interns, ModuleId};
|
use roc_module::symbol::{Interns, ModuleId};
|
||||||
use roc_packaging::cache::RocCacheDir;
|
use roc_packaging::cache::RocCacheDir;
|
||||||
use roc_parse::module::parse_header;
|
use roc_parse::header::parse_header;
|
||||||
use roc_parse::state::State;
|
use roc_parse::state::State;
|
||||||
use roc_parse::test_helpers::parse_expr_with;
|
use roc_parse::test_helpers::parse_expr_with;
|
||||||
use roc_problem::Severity;
|
use roc_problem::Severity;
|
||||||
|
|
@ -359,7 +359,7 @@ mod test_reporting {
|
||||||
let src_lines: Vec<&str> = src.split('\n').collect();
|
let src_lines: Vec<&str> = src.split('\n').collect();
|
||||||
let lines = LineInfo::new(src);
|
let lines = LineInfo::new(src);
|
||||||
|
|
||||||
match roc_parse::module::parse_header(arena, state) {
|
match roc_parse::header::parse_header(arena, state) {
|
||||||
Err(fail) => {
|
Err(fail) => {
|
||||||
let interns = Interns::default();
|
let interns = Interns::default();
|
||||||
let home = crate::helpers::test_home();
|
let home = crate::helpers::test_home();
|
||||||
|
|
@ -10876,12 +10876,12 @@ All branches in an `if` must have the same type!
|
||||||
),
|
),
|
||||||
@r#"
|
@r#"
|
||||||
── EMPTY RECORD BUILDER in /code/proj/Main.roc ─────────────────────────────────
|
── EMPTY RECORD BUILDER in /code/proj/Main.roc ─────────────────────────────────
|
||||||
|
|
||||||
This record builder has no fields:
|
This record builder has no fields:
|
||||||
|
|
||||||
4│ { a <- }
|
4│ { a <- }
|
||||||
^^^^^^^^
|
^^^^^^^^
|
||||||
|
|
||||||
I need at least two fields to combine their values into a record.
|
I need at least two fields to combine their values into a record.
|
||||||
"#
|
"#
|
||||||
);
|
);
|
||||||
|
|
@ -10899,11 +10899,11 @@ All branches in an `if` must have the same type!
|
||||||
── NOT ENOUGH FIELDS IN RECORD BUILDER in /code/proj/Main.roc ──────────────────
|
── NOT ENOUGH FIELDS IN RECORD BUILDER in /code/proj/Main.roc ──────────────────
|
||||||
|
|
||||||
This record builder only has one field:
|
This record builder only has one field:
|
||||||
|
|
||||||
4│> { a <-
|
4│> { a <-
|
||||||
5│> b: 123
|
5│> b: 123
|
||||||
6│> }
|
6│> }
|
||||||
|
|
||||||
I need at least two fields to combine their values into a record.
|
I need at least two fields to combine their values into a record.
|
||||||
"#
|
"#
|
||||||
);
|
);
|
||||||
|
|
@ -10920,14 +10920,14 @@ All branches in an `if` must have the same type!
|
||||||
),
|
),
|
||||||
@r#"
|
@r#"
|
||||||
── OPTIONAL FIELD IN RECORD BUILDER in /code/proj/Main.roc ─────────────────────
|
── OPTIONAL FIELD IN RECORD BUILDER in /code/proj/Main.roc ─────────────────────
|
||||||
|
|
||||||
Optional fields are not allowed to be used in record builders.
|
Optional fields are not allowed to be used in record builders.
|
||||||
|
|
||||||
4│ { a <-
|
4│ { a <-
|
||||||
5│ b: 123,
|
5│ b: 123,
|
||||||
6│> c? 456
|
6│> c? 456
|
||||||
7│ }
|
7│ }
|
||||||
|
|
||||||
Record builders can only have required values for their fields.
|
Record builders can only have required values for their fields.
|
||||||
"#
|
"#
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -465,7 +465,8 @@ fn contains_unexposed_type(
|
||||||
while let Some(field) = fields_to_process.pop() {
|
while let Some(field) = fields_to_process.pop() {
|
||||||
match field {
|
match field {
|
||||||
AssignedField::RequiredValue(_field, _spaces, loc_val)
|
AssignedField::RequiredValue(_field, _spaces, loc_val)
|
||||||
| AssignedField::OptionalValue(_field, _spaces, loc_val) => {
|
| AssignedField::OptionalValue(_field, _spaces, loc_val)
|
||||||
|
| AssignedField::IgnoredValue(_field, _spaces, loc_val) => {
|
||||||
if contains_unexposed_type(&loc_val.value, exposed_module_ids, module_ids) {
|
if contains_unexposed_type(&loc_val.value, exposed_module_ids, module_ids) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -721,7 +722,7 @@ fn record_field_to_doc(
|
||||||
AssignedField::LabelOnly(label) => Some(RecordField::LabelOnly {
|
AssignedField::LabelOnly(label) => Some(RecordField::LabelOnly {
|
||||||
name: label.value.to_string(),
|
name: label.value.to_string(),
|
||||||
}),
|
}),
|
||||||
AssignedField::Malformed(_) => None,
|
AssignedField::Malformed(_) | AssignedField::IgnoredValue(_, _, _) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,11 +48,11 @@ use roc_mono::reset_reuse;
|
||||||
use roc_mono::{drop_specialization, inc_dec};
|
use roc_mono::{drop_specialization, inc_dec};
|
||||||
use roc_packaging::cache::RocCacheDir;
|
use roc_packaging::cache::RocCacheDir;
|
||||||
use roc_parse::ast::{self, CommentOrNewline, ExtractSpaces, Spaced, ValueDef};
|
use roc_parse::ast::{self, CommentOrNewline, ExtractSpaces, Spaced, ValueDef};
|
||||||
|
use roc_parse::header::parse_module_defs;
|
||||||
use roc_parse::header::{
|
use roc_parse::header::{
|
||||||
self, AppHeader, ExposedName, HeaderType, ImportsKeywordItem, PackageEntry, PackageHeader,
|
self, AppHeader, ExposedName, HeaderType, ImportsKeywordItem, PackageEntry, PackageHeader,
|
||||||
PlatformHeader, To, TypedIdent,
|
PlatformHeader, To, TypedIdent,
|
||||||
};
|
};
|
||||||
use roc_parse::module::parse_module_defs;
|
|
||||||
use roc_parse::parser::{FileError, SourceError, SyntaxError};
|
use roc_parse::parser::{FileError, SourceError, SyntaxError};
|
||||||
use roc_problem::Severity;
|
use roc_problem::Severity;
|
||||||
use roc_region::all::{LineInfo, Loc, Region};
|
use roc_region::all::{LineInfo, Loc, Region};
|
||||||
|
|
@ -1327,8 +1327,8 @@ fn load_packages_from_main<'a>(
|
||||||
|
|
||||||
let parse_state = roc_parse::state::State::new(arena.alloc(src_bytes));
|
let parse_state = roc_parse::state::State::new(arena.alloc(src_bytes));
|
||||||
|
|
||||||
let (parsed_module, _) =
|
let (parsed_header, _) =
|
||||||
roc_parse::module::parse_header(arena, parse_state.clone()).map_err(|fail| {
|
roc_parse::header::parse_header(arena, parse_state.clone()).map_err(|fail| {
|
||||||
LoadingProblem::ParsingFailed(
|
LoadingProblem::ParsingFailed(
|
||||||
fail.map_problem(SyntaxError::Header)
|
fail.map_problem(SyntaxError::Header)
|
||||||
.into_file_error(filename.clone()),
|
.into_file_error(filename.clone()),
|
||||||
|
|
@ -1337,7 +1337,7 @@ fn load_packages_from_main<'a>(
|
||||||
|
|
||||||
use ast::Header::*;
|
use ast::Header::*;
|
||||||
|
|
||||||
let packages = match parsed_module.header {
|
let packages = match parsed_header.item {
|
||||||
App(AppHeader { packages, .. }) | Package(PackageHeader { packages, .. }) => {
|
App(AppHeader { packages, .. }) | Package(PackageHeader { packages, .. }) => {
|
||||||
unspace(arena, packages.value.items)
|
unspace(arena, packages.value.items)
|
||||||
}
|
}
|
||||||
|
|
@ -3350,7 +3350,7 @@ fn load_package_from_disk<'a>(
|
||||||
let parse_start = Instant::now();
|
let parse_start = Instant::now();
|
||||||
let bytes = arena.alloc(bytes_vec);
|
let bytes = arena.alloc(bytes_vec);
|
||||||
let parse_state = roc_parse::state::State::new(bytes);
|
let parse_state = roc_parse::state::State::new(bytes);
|
||||||
let parsed = roc_parse::module::parse_header(arena, parse_state.clone());
|
let parsed = roc_parse::header::parse_header(arena, parse_state.clone());
|
||||||
let parse_header_duration = parse_start.elapsed();
|
let parse_header_duration = parse_start.elapsed();
|
||||||
|
|
||||||
// Insert the first entries for this module's timings
|
// Insert the first entries for this module's timings
|
||||||
|
|
@ -3361,8 +3361,8 @@ fn load_package_from_disk<'a>(
|
||||||
|
|
||||||
match parsed {
|
match parsed {
|
||||||
Ok((
|
Ok((
|
||||||
ast::Module {
|
ast::SpacesBefore {
|
||||||
header: ast::Header::Module(header),
|
item: ast::Header::Module(header),
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
_parse_state,
|
_parse_state,
|
||||||
|
|
@ -3370,8 +3370,8 @@ fn load_package_from_disk<'a>(
|
||||||
"expected platform/package module, got Module with header\n{header:?}"
|
"expected platform/package module, got Module with header\n{header:?}"
|
||||||
))),
|
))),
|
||||||
Ok((
|
Ok((
|
||||||
ast::Module {
|
ast::SpacesBefore {
|
||||||
header: ast::Header::Hosted(header),
|
item: ast::Header::Hosted(header),
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
_parse_state,
|
_parse_state,
|
||||||
|
|
@ -3379,8 +3379,8 @@ fn load_package_from_disk<'a>(
|
||||||
"expected platform/package module, got Hosted module with header\n{header:?}"
|
"expected platform/package module, got Hosted module with header\n{header:?}"
|
||||||
))),
|
))),
|
||||||
Ok((
|
Ok((
|
||||||
ast::Module {
|
ast::SpacesBefore {
|
||||||
header: ast::Header::App(header),
|
item: ast::Header::App(header),
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
_parse_state,
|
_parse_state,
|
||||||
|
|
@ -3388,9 +3388,9 @@ fn load_package_from_disk<'a>(
|
||||||
"expected platform/package module, got App with header\n{header:?}"
|
"expected platform/package module, got App with header\n{header:?}"
|
||||||
))),
|
))),
|
||||||
Ok((
|
Ok((
|
||||||
ast::Module {
|
ast::SpacesBefore {
|
||||||
header: ast::Header::Package(header),
|
item: ast::Header::Package(header),
|
||||||
comments,
|
before: comments,
|
||||||
},
|
},
|
||||||
parser_state,
|
parser_state,
|
||||||
)) => {
|
)) => {
|
||||||
|
|
@ -3431,9 +3431,9 @@ fn load_package_from_disk<'a>(
|
||||||
Ok(Msg::Many(messages))
|
Ok(Msg::Many(messages))
|
||||||
}
|
}
|
||||||
Ok((
|
Ok((
|
||||||
ast::Module {
|
ast::SpacesBefore {
|
||||||
header: ast::Header::Platform(header),
|
item: ast::Header::Platform(header),
|
||||||
comments,
|
before: comments,
|
||||||
},
|
},
|
||||||
parser_state,
|
parser_state,
|
||||||
)) => {
|
)) => {
|
||||||
|
|
@ -3531,13 +3531,13 @@ fn load_builtin_module_help<'a>(
|
||||||
let opt_shorthand = None;
|
let opt_shorthand = None;
|
||||||
let filename = PathBuf::from(filename);
|
let filename = PathBuf::from(filename);
|
||||||
let parse_state = roc_parse::state::State::new(src_bytes.as_bytes());
|
let parse_state = roc_parse::state::State::new(src_bytes.as_bytes());
|
||||||
let parsed = roc_parse::module::parse_header(arena, parse_state.clone());
|
let parsed = roc_parse::header::parse_header(arena, parse_state.clone());
|
||||||
|
|
||||||
match parsed {
|
match parsed {
|
||||||
Ok((
|
Ok((
|
||||||
ast::Module {
|
ast::SpacesBefore {
|
||||||
header: ast::Header::Module(header),
|
item: ast::Header::Module(header),
|
||||||
comments,
|
before: comments,
|
||||||
},
|
},
|
||||||
parse_state,
|
parse_state,
|
||||||
)) => {
|
)) => {
|
||||||
|
|
@ -3787,7 +3787,7 @@ fn parse_header<'a>(
|
||||||
) -> Result<HeaderOutput<'a>, LoadingProblem<'a>> {
|
) -> Result<HeaderOutput<'a>, LoadingProblem<'a>> {
|
||||||
let parse_start = Instant::now();
|
let parse_start = Instant::now();
|
||||||
let parse_state = roc_parse::state::State::new(src_bytes);
|
let parse_state = roc_parse::state::State::new(src_bytes);
|
||||||
let parsed = roc_parse::module::parse_header(arena, parse_state.clone());
|
let parsed = roc_parse::header::parse_header(arena, parse_state.clone());
|
||||||
let parse_header_duration = parse_start.elapsed();
|
let parse_header_duration = parse_start.elapsed();
|
||||||
|
|
||||||
if let Err(problem) = ensure_roc_file(&filename, src_bytes) {
|
if let Err(problem) = ensure_roc_file(&filename, src_bytes) {
|
||||||
|
|
@ -3816,9 +3816,9 @@ fn parse_header<'a>(
|
||||||
|
|
||||||
match parsed {
|
match parsed {
|
||||||
Ok((
|
Ok((
|
||||||
ast::Module {
|
ast::SpacesBefore {
|
||||||
header: ast::Header::Module(header),
|
item: ast::Header::Module(header),
|
||||||
comments,
|
before: comments,
|
||||||
},
|
},
|
||||||
parse_state,
|
parse_state,
|
||||||
)) => {
|
)) => {
|
||||||
|
|
@ -3853,9 +3853,9 @@ fn parse_header<'a>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Ok((
|
Ok((
|
||||||
ast::Module {
|
ast::SpacesBefore {
|
||||||
header: ast::Header::Hosted(header),
|
item: ast::Header::Hosted(header),
|
||||||
comments,
|
before: comments,
|
||||||
},
|
},
|
||||||
parse_state,
|
parse_state,
|
||||||
)) => {
|
)) => {
|
||||||
|
|
@ -3882,9 +3882,9 @@ fn parse_header<'a>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Ok((
|
Ok((
|
||||||
ast::Module {
|
ast::SpacesBefore {
|
||||||
header: ast::Header::App(header),
|
item: ast::Header::App(header),
|
||||||
comments,
|
before: comments,
|
||||||
},
|
},
|
||||||
parse_state,
|
parse_state,
|
||||||
)) => {
|
)) => {
|
||||||
|
|
@ -3987,9 +3987,9 @@ fn parse_header<'a>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Ok((
|
Ok((
|
||||||
ast::Module {
|
ast::SpacesBefore {
|
||||||
header: ast::Header::Package(header),
|
item: ast::Header::Package(header),
|
||||||
comments,
|
before: comments,
|
||||||
},
|
},
|
||||||
parse_state,
|
parse_state,
|
||||||
)) => {
|
)) => {
|
||||||
|
|
@ -4014,9 +4014,9 @@ fn parse_header<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
ast::Module {
|
ast::SpacesBefore {
|
||||||
header: ast::Header::Platform(header),
|
item: ast::Header::Platform(header),
|
||||||
comments,
|
before: comments,
|
||||||
},
|
},
|
||||||
parse_state,
|
parse_state,
|
||||||
)) => {
|
)) => {
|
||||||
|
|
@ -4921,6 +4921,7 @@ fn build_platform_header<'a>(
|
||||||
.zip(requires.iter().copied()),
|
.zip(requires.iter().copied()),
|
||||||
arena,
|
arena,
|
||||||
);
|
);
|
||||||
|
let packages = unspace(arena, header.packages.item.items);
|
||||||
let exposes = bumpalo::collections::Vec::from_iter_in(
|
let exposes = bumpalo::collections::Vec::from_iter_in(
|
||||||
unspace(arena, header.exposes.item.items).iter().copied(),
|
unspace(arena, header.exposes.item.items).iter().copied(),
|
||||||
arena,
|
arena,
|
||||||
|
|
@ -4942,7 +4943,7 @@ fn build_platform_header<'a>(
|
||||||
filename,
|
filename,
|
||||||
is_root_module,
|
is_root_module,
|
||||||
opt_shorthand,
|
opt_shorthand,
|
||||||
packages: &[],
|
packages,
|
||||||
header_type,
|
header_type,
|
||||||
module_comments: comments,
|
module_comments: comments,
|
||||||
header_imports: Some(header.imports),
|
header_imports: Some(header.imports),
|
||||||
|
|
@ -5152,7 +5153,7 @@ fn parse<'a>(
|
||||||
let parse_state = header.parse_state;
|
let parse_state = header.parse_state;
|
||||||
|
|
||||||
let header_import_defs =
|
let header_import_defs =
|
||||||
roc_parse::ast::Module::header_imports_to_defs(arena, header.header_imports);
|
roc_parse::ast::Header::header_imports_to_defs(arena, header.header_imports);
|
||||||
|
|
||||||
let parsed_defs = match parse_module_defs(arena, parse_state.clone(), header_import_defs) {
|
let parsed_defs = match parse_module_defs(arena, parse_state.clone(), header_import_defs) {
|
||||||
Ok(success) => success,
|
Ok(success) => success,
|
||||||
|
|
|
||||||
|
|
@ -6140,7 +6140,7 @@ fn late_resolve_ability_specialization(
|
||||||
member,
|
member,
|
||||||
specialization_var,
|
specialization_var,
|
||||||
)
|
)
|
||||||
.expect("Ability specialization is unknown - code generation cannot proceed!");
|
.expect("Ability specialization is unknown. Tip: check out <https://roc.zulipchat.com/#narrow/stream/231634-beginners/topic/Non-Functions.20in.20Abilities/near/456068617>");
|
||||||
|
|
||||||
match specialization {
|
match specialization {
|
||||||
Resolved::Specialization(symbol) => symbol,
|
Resolved::Specialization(symbol) => symbol,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use bumpalo::Bump;
|
||||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||||
use roc_parse::{
|
use roc_parse::{
|
||||||
ast::Defs,
|
ast::Defs,
|
||||||
module::{self, parse_module_defs},
|
header::{self, parse_module_defs},
|
||||||
state::State,
|
state::State,
|
||||||
};
|
};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
@ -20,7 +20,7 @@ pub fn parse_benchmark(c: &mut Criterion) {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
|
|
||||||
let (_actual, state) =
|
let (_actual, state) =
|
||||||
module::parse_header(&arena, State::new(src.as_bytes())).unwrap();
|
header::parse_header(&arena, State::new(src.as_bytes())).unwrap();
|
||||||
|
|
||||||
let res = parse_module_defs(&arena, state, Defs::default()).unwrap();
|
let res = parse_module_defs(&arena, state, Defs::default()).unwrap();
|
||||||
|
|
||||||
|
|
@ -41,7 +41,7 @@ pub fn parse_benchmark(c: &mut Criterion) {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
|
|
||||||
let (_actual, state) =
|
let (_actual, state) =
|
||||||
module::parse_header(&arena, State::new(src.as_bytes())).unwrap();
|
header::parse_header(&arena, State::new(src.as_bytes())).unwrap();
|
||||||
|
|
||||||
let res = parse_module_defs(&arena, state, Defs::default()).unwrap();
|
let res = parse_module_defs(&arena, state, Defs::default()).unwrap();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,12 @@ use roc_module::called_via::{BinOp, CalledVia, UnaryOp};
|
||||||
use roc_module::ident::QualifiedModuleName;
|
use roc_module::ident::QualifiedModuleName;
|
||||||
use roc_region::all::{Loc, Position, Region};
|
use roc_region::all::{Loc, Position, Region};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct FullAst<'a> {
|
||||||
|
pub header: SpacesBefore<'a, Header<'a>>,
|
||||||
|
pub defs: Defs<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
pub struct Spaces<'a, T> {
|
pub struct Spaces<'a, T> {
|
||||||
pub before: &'a [CommentOrNewline<'a>],
|
pub before: &'a [CommentOrNewline<'a>],
|
||||||
|
|
@ -111,15 +117,9 @@ impl<'a, T: ExtractSpaces<'a>> ExtractSpaces<'a> for Loc<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
impl<'a> Header<'a> {
|
||||||
pub struct Module<'a> {
|
|
||||||
pub comments: &'a [CommentOrNewline<'a>],
|
|
||||||
pub header: Header<'a>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Module<'a> {
|
|
||||||
pub fn upgrade_header_imports(self, arena: &'a Bump) -> (Self, Defs<'a>) {
|
pub fn upgrade_header_imports(self, arena: &'a Bump) -> (Self, Defs<'a>) {
|
||||||
let (header, defs) = match self.header {
|
let (header, defs) = match self {
|
||||||
Header::Module(header) => (
|
Header::Module(header) => (
|
||||||
Header::Module(ModuleHeader {
|
Header::Module(ModuleHeader {
|
||||||
interface_imports: None,
|
interface_imports: None,
|
||||||
|
|
@ -134,12 +134,10 @@ impl<'a> Module<'a> {
|
||||||
}),
|
}),
|
||||||
Self::header_imports_to_defs(arena, header.old_imports),
|
Self::header_imports_to_defs(arena, header.old_imports),
|
||||||
),
|
),
|
||||||
Header::Package(_) | Header::Platform(_) | Header::Hosted(_) => {
|
Header::Package(_) | Header::Platform(_) | Header::Hosted(_) => (self, Defs::default()),
|
||||||
(self.header, Defs::default())
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
(Module { header, ..self }, defs)
|
(header, defs)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn header_imports_to_defs(
|
pub fn header_imports_to_defs(
|
||||||
|
|
@ -681,9 +679,9 @@ fn is_when_branch_suffixed(branch: &WhenBranch<'_>) -> bool {
|
||||||
|
|
||||||
fn is_assigned_value_suffixed<'a>(value: &AssignedField<'a, Expr<'a>>) -> bool {
|
fn is_assigned_value_suffixed<'a>(value: &AssignedField<'a, Expr<'a>>) -> bool {
|
||||||
match value {
|
match value {
|
||||||
AssignedField::RequiredValue(_, _, a) | AssignedField::OptionalValue(_, _, a) => {
|
AssignedField::RequiredValue(_, _, a)
|
||||||
is_expr_suffixed(&a.value)
|
| AssignedField::OptionalValue(_, _, a)
|
||||||
}
|
| AssignedField::IgnoredValue(_, _, a) => is_expr_suffixed(&a.value),
|
||||||
AssignedField::LabelOnly(_) => false,
|
AssignedField::LabelOnly(_) => false,
|
||||||
AssignedField::SpaceBefore(a, _) | AssignedField::SpaceAfter(a, _) => {
|
AssignedField::SpaceBefore(a, _) | AssignedField::SpaceAfter(a, _) => {
|
||||||
is_assigned_value_suffixed(a)
|
is_assigned_value_suffixed(a)
|
||||||
|
|
@ -869,9 +867,9 @@ impl<'a, 'b> RecursiveValueDefIter<'a, 'b> {
|
||||||
use AssignedField::*;
|
use AssignedField::*;
|
||||||
|
|
||||||
match current {
|
match current {
|
||||||
RequiredValue(_, _, loc_val) | OptionalValue(_, _, loc_val) => {
|
RequiredValue(_, _, loc_val)
|
||||||
break expr_stack.push(&loc_val.value)
|
| OptionalValue(_, _, loc_val)
|
||||||
}
|
| IgnoredValue(_, _, loc_val) => break expr_stack.push(&loc_val.value),
|
||||||
SpaceBefore(next, _) | SpaceAfter(next, _) => current = *next,
|
SpaceBefore(next, _) | SpaceAfter(next, _) => current = *next,
|
||||||
LabelOnly(_) | Malformed(_) => break,
|
LabelOnly(_) | Malformed(_) => break,
|
||||||
}
|
}
|
||||||
|
|
@ -1598,6 +1596,9 @@ pub enum AssignedField<'a, Val> {
|
||||||
// and in destructuring patterns (e.g. `{ name ? "blah" }`)
|
// and in destructuring patterns (e.g. `{ name ? "blah" }`)
|
||||||
OptionalValue(Loc<&'a str>, &'a [CommentOrNewline<'a>], &'a Loc<Val>),
|
OptionalValue(Loc<&'a str>, &'a [CommentOrNewline<'a>], &'a Loc<Val>),
|
||||||
|
|
||||||
|
// An ignored field, e.g. `{ _name: "blah" }` or `{ _ : Str }`
|
||||||
|
IgnoredValue(Loc<&'a str>, &'a [CommentOrNewline<'a>], &'a Loc<Val>),
|
||||||
|
|
||||||
// A label with no value, e.g. `{ name }` (this is sugar for { name: name })
|
// A label with no value, e.g. `{ name }` (this is sugar for { name: name })
|
||||||
LabelOnly(Loc<&'a str>),
|
LabelOnly(Loc<&'a str>),
|
||||||
|
|
||||||
|
|
@ -1615,7 +1616,9 @@ impl<'a, Val> AssignedField<'a, Val> {
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match current {
|
match current {
|
||||||
Self::RequiredValue(_, _, val) | Self::OptionalValue(_, _, val) => break Some(val),
|
Self::RequiredValue(_, _, val)
|
||||||
|
| Self::OptionalValue(_, _, val)
|
||||||
|
| Self::IgnoredValue(_, _, val) => break Some(val),
|
||||||
Self::LabelOnly(_) | Self::Malformed(_) => break None,
|
Self::LabelOnly(_) | Self::Malformed(_) => break None,
|
||||||
Self::SpaceBefore(next, _) | Self::SpaceAfter(next, _) => current = *next,
|
Self::SpaceBefore(next, _) | Self::SpaceAfter(next, _) => current = *next,
|
||||||
}
|
}
|
||||||
|
|
@ -2433,9 +2436,9 @@ pub trait Malformed {
|
||||||
fn is_malformed(&self) -> bool;
|
fn is_malformed(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Malformed for Module<'a> {
|
impl<'a> Malformed for FullAst<'a> {
|
||||||
fn is_malformed(&self) -> bool {
|
fn is_malformed(&self) -> bool {
|
||||||
self.header.is_malformed()
|
self.header.item.is_malformed() || self.defs.is_malformed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2457,6 +2460,12 @@ impl<'a, T: Malformed> Malformed for Spaces<'a, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Malformed> Malformed for SpacesBefore<'a, T> {
|
||||||
|
fn is_malformed(&self) -> bool {
|
||||||
|
self.item.is_malformed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Malformed for Expr<'a> {
|
impl<'a> Malformed for Expr<'a> {
|
||||||
fn is_malformed(&self) -> bool {
|
fn is_malformed(&self) -> bool {
|
||||||
use Expr::*;
|
use Expr::*;
|
||||||
|
|
@ -2577,9 +2586,9 @@ impl<T: Malformed> Malformed for Option<T> {
|
||||||
impl<'a, T: Malformed> Malformed for AssignedField<'a, T> {
|
impl<'a, T: Malformed> Malformed for AssignedField<'a, T> {
|
||||||
fn is_malformed(&self) -> bool {
|
fn is_malformed(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
AssignedField::RequiredValue(_, _, val) | AssignedField::OptionalValue(_, _, val) => {
|
AssignedField::RequiredValue(_, _, val)
|
||||||
val.is_malformed()
|
| AssignedField::OptionalValue(_, _, val)
|
||||||
}
|
| AssignedField::IgnoredValue(_, _, val) => val.is_malformed(),
|
||||||
AssignedField::LabelOnly(_) => false,
|
AssignedField::LabelOnly(_) => false,
|
||||||
AssignedField::SpaceBefore(field, _) | AssignedField::SpaceAfter(field, _) => {
|
AssignedField::SpaceBefore(field, _) | AssignedField::SpaceAfter(field, _) => {
|
||||||
field.is_malformed()
|
field.is_malformed()
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,10 @@ 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,
|
||||||
space0_before_optional_after, space0_e, spaces, spaces_around, spaces_before,
|
space0_before_optional_after, space0_e, spaces, spaces_around, spaces_before,
|
||||||
};
|
};
|
||||||
|
use crate::header::module_name_help;
|
||||||
use crate::ident::{
|
use crate::ident::{
|
||||||
integer_ident, lowercase_ident, parse_ident, unqualified_ident, Accessor, Ident, Suffix,
|
integer_ident, lowercase_ident, parse_ident, unqualified_ident, Accessor, Ident, Suffix,
|
||||||
};
|
};
|
||||||
use crate::module::module_name_help;
|
|
||||||
use crate::parser::{
|
use crate::parser::{
|
||||||
self, and, backtrackable, between, byte, byte_indent, collection_inner,
|
self, and, backtrackable, between, byte, byte_indent, collection_inner,
|
||||||
collection_trailing_sep_e, either, increment_min_indent, indented_seq_skip_first, loc, map,
|
collection_trailing_sep_e, either, increment_min_indent, indented_seq_skip_first, loc, map,
|
||||||
|
|
@ -24,8 +24,8 @@ use crate::parser::{
|
||||||
use crate::pattern::closure_param;
|
use crate::pattern::closure_param;
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
use crate::string_literal::{self, StrLikeLiteral};
|
use crate::string_literal::{self, StrLikeLiteral};
|
||||||
|
use crate::type_annotation;
|
||||||
use crate::{header, keyword};
|
use crate::{header, keyword};
|
||||||
use crate::{module, type_annotation};
|
|
||||||
use bumpalo::collections::Vec;
|
use bumpalo::collections::Vec;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_collections::soa::Slice;
|
use roc_collections::soa::Slice;
|
||||||
|
|
@ -914,6 +914,10 @@ fn import_params<'a>() -> impl Parser<'a, ModuleImportParams<'a>, EImportParams<
|
||||||
|
|
||||||
let params = record.fields.map_items_result(arena, |loc_field| {
|
let params = record.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(_, _, _)) => Err((
|
||||||
|
MadeProgress,
|
||||||
|
EImportParams::RecordIgnoredFieldFound(loc_field.region),
|
||||||
|
)),
|
||||||
Ok(field) => Ok(Loc::at(loc_field.region, field)),
|
Ok(field) => Ok(Loc::at(loc_field.region, field)),
|
||||||
Err(FoundApplyValue) => Err((
|
Err(FoundApplyValue) => Err((
|
||||||
MadeProgress,
|
MadeProgress,
|
||||||
|
|
@ -944,7 +948,7 @@ fn imported_module_name<'a>() -> impl Parser<'a, ImportedModuleName<'a>, EImport
|
||||||
fn import_as<'a>(
|
fn import_as<'a>(
|
||||||
) -> impl Parser<'a, header::KeywordItem<'a, ImportAsKeyword, Loc<ImportAlias<'a>>>, EImport<'a>> {
|
) -> impl Parser<'a, header::KeywordItem<'a, ImportAsKeyword, Loc<ImportAlias<'a>>>, EImport<'a>> {
|
||||||
record!(header::KeywordItem {
|
record!(header::KeywordItem {
|
||||||
keyword: module::spaces_around_keyword(
|
keyword: header::spaces_around_keyword(
|
||||||
ImportAsKeyword,
|
ImportAsKeyword,
|
||||||
EImport::As,
|
EImport::As,
|
||||||
EImport::IndentAs,
|
EImport::IndentAs,
|
||||||
|
|
@ -978,7 +982,7 @@ fn import_exposing<'a>() -> impl Parser<
|
||||||
EImport<'a>,
|
EImport<'a>,
|
||||||
> {
|
> {
|
||||||
record!(header::KeywordItem {
|
record!(header::KeywordItem {
|
||||||
keyword: module::spaces_around_keyword(
|
keyword: header::spaces_around_keyword(
|
||||||
ImportExposingKeyword,
|
ImportExposingKeyword,
|
||||||
EImport::Exposing,
|
EImport::Exposing,
|
||||||
EImport::IndentExposing,
|
EImport::IndentExposing,
|
||||||
|
|
@ -1023,7 +1027,7 @@ fn import_ingested_file_body<'a>() -> impl Parser<'a, ValueDef<'a>, EImport<'a>>
|
||||||
fn import_ingested_file_as<'a>(
|
fn import_ingested_file_as<'a>(
|
||||||
) -> impl Parser<'a, header::KeywordItem<'a, ImportAsKeyword, Loc<&'a str>>, EImport<'a>> {
|
) -> impl Parser<'a, header::KeywordItem<'a, ImportAsKeyword, Loc<&'a str>>, EImport<'a>> {
|
||||||
record!(header::KeywordItem {
|
record!(header::KeywordItem {
|
||||||
keyword: module::spaces_around_keyword(
|
keyword: header::spaces_around_keyword(
|
||||||
ImportAsKeyword,
|
ImportAsKeyword,
|
||||||
EImport::As,
|
EImport::As,
|
||||||
EImport::IndentAs,
|
EImport::IndentAs,
|
||||||
|
|
@ -2234,6 +2238,7 @@ fn assigned_expr_field_to_pattern_help<'a>(
|
||||||
spaces,
|
spaces,
|
||||||
),
|
),
|
||||||
AssignedField::Malformed(string) => Pattern::Malformed(string),
|
AssignedField::Malformed(string) => Pattern::Malformed(string),
|
||||||
|
AssignedField::IgnoredValue(_, _, _) => return Err(()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3322,6 +3327,7 @@ fn list_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EList<'a>> {
|
||||||
pub enum RecordField<'a> {
|
pub enum RecordField<'a> {
|
||||||
RequiredValue(Loc<&'a str>, &'a [CommentOrNewline<'a>], &'a Loc<Expr<'a>>),
|
RequiredValue(Loc<&'a str>, &'a [CommentOrNewline<'a>], &'a Loc<Expr<'a>>),
|
||||||
OptionalValue(Loc<&'a str>, &'a [CommentOrNewline<'a>], &'a Loc<Expr<'a>>),
|
OptionalValue(Loc<&'a str>, &'a [CommentOrNewline<'a>], &'a Loc<Expr<'a>>),
|
||||||
|
IgnoredValue(Loc<&'a str>, &'a [CommentOrNewline<'a>], &'a Loc<Expr<'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>]),
|
||||||
|
|
@ -3337,7 +3343,10 @@ pub enum RecordField<'a> {
|
||||||
pub struct FoundApplyValue;
|
pub struct FoundApplyValue;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct FoundOptionalValue;
|
pub enum NotOldBuilderFieldValue {
|
||||||
|
FoundOptionalValue,
|
||||||
|
FoundIgnoredValue,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> RecordField<'a> {
|
impl<'a> RecordField<'a> {
|
||||||
fn is_apply_value(&self) -> bool {
|
fn is_apply_value(&self) -> bool {
|
||||||
|
|
@ -3354,6 +3363,20 @@ impl<'a> RecordField<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_ignored_value(&self) -> bool {
|
||||||
|
let mut current = self;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match current {
|
||||||
|
RecordField::IgnoredValue(_, _, _) => break true,
|
||||||
|
RecordField::SpaceBefore(field, _) | RecordField::SpaceAfter(field, _) => {
|
||||||
|
current = *field;
|
||||||
|
}
|
||||||
|
_ => break false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn to_assigned_field(
|
pub fn to_assigned_field(
|
||||||
self,
|
self,
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
|
|
@ -3369,6 +3392,10 @@ impl<'a> RecordField<'a> {
|
||||||
Ok(OptionalValue(loc_label, spaces, loc_expr))
|
Ok(OptionalValue(loc_label, spaces, loc_expr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RecordField::IgnoredValue(loc_label, spaces, loc_expr) => {
|
||||||
|
Ok(IgnoredValue(loc_label, spaces, loc_expr))
|
||||||
|
}
|
||||||
|
|
||||||
RecordField::LabelOnly(loc_label) => Ok(LabelOnly(loc_label)),
|
RecordField::LabelOnly(loc_label) => Ok(LabelOnly(loc_label)),
|
||||||
|
|
||||||
RecordField::ApplyValue(_, _, _, _) => Err(FoundApplyValue),
|
RecordField::ApplyValue(_, _, _, _) => Err(FoundApplyValue),
|
||||||
|
|
@ -3390,7 +3417,7 @@ impl<'a> RecordField<'a> {
|
||||||
fn to_builder_field(
|
fn to_builder_field(
|
||||||
self,
|
self,
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
) -> Result<OldRecordBuilderField<'a>, FoundOptionalValue> {
|
) -> Result<OldRecordBuilderField<'a>, NotOldBuilderFieldValue> {
|
||||||
use OldRecordBuilderField::*;
|
use OldRecordBuilderField::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -3398,7 +3425,9 @@ impl<'a> RecordField<'a> {
|
||||||
Ok(Value(loc_label, spaces, loc_expr))
|
Ok(Value(loc_label, spaces, loc_expr))
|
||||||
}
|
}
|
||||||
|
|
||||||
RecordField::OptionalValue(_, _, _) => Err(FoundOptionalValue),
|
RecordField::OptionalValue(_, _, _) => Err(NotOldBuilderFieldValue::FoundOptionalValue),
|
||||||
|
|
||||||
|
RecordField::IgnoredValue(_, _, _) => Err(NotOldBuilderFieldValue::FoundIgnoredValue),
|
||||||
|
|
||||||
RecordField::LabelOnly(loc_label) => Ok(LabelOnly(loc_label)),
|
RecordField::LabelOnly(loc_label) => Ok(LabelOnly(loc_label)),
|
||||||
|
|
||||||
|
|
@ -3434,42 +3463,70 @@ pub fn record_field<'a>() -> impl Parser<'a, RecordField<'a>, ERecord<'a>> {
|
||||||
use RecordField::*;
|
use RecordField::*;
|
||||||
|
|
||||||
map_with_arena(
|
map_with_arena(
|
||||||
and(
|
either(
|
||||||
specialize_err(|_, pos| ERecord::Field(pos), loc(lowercase_ident())),
|
|
||||||
and(
|
and(
|
||||||
spaces(),
|
specialize_err(|_, pos| ERecord::Field(pos), loc(lowercase_ident())),
|
||||||
optional(either(
|
and(
|
||||||
and(byte(b':', ERecord::Colon), record_field_expr()),
|
spaces(),
|
||||||
and(
|
optional(either(
|
||||||
byte(b'?', ERecord::QuestionMark),
|
and(byte(b':', ERecord::Colon), record_field_expr()),
|
||||||
|
and(
|
||||||
|
byte(b'?', ERecord::QuestionMark),
|
||||||
|
spaces_before(specialize_err_ref(ERecord::Expr, loc_expr(false))),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
and(
|
||||||
|
loc(skip_first(
|
||||||
|
byte(b'_', ERecord::UnderscoreField),
|
||||||
|
optional(specialize_err(
|
||||||
|
|_, pos| ERecord::Field(pos),
|
||||||
|
lowercase_ident(),
|
||||||
|
)),
|
||||||
|
)),
|
||||||
|
and(
|
||||||
|
spaces(),
|
||||||
|
skip_first(
|
||||||
|
byte(b':', ERecord::Colon),
|
||||||
spaces_before(specialize_err_ref(ERecord::Expr, loc_expr(false))),
|
spaces_before(specialize_err_ref(ERecord::Expr, loc_expr(false))),
|
||||||
),
|
),
|
||||||
)),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|arena: &'a bumpalo::Bump, (loc_label, (spaces, opt_loc_val))| {
|
|arena: &'a bumpalo::Bump, field_data| {
|
||||||
match opt_loc_val {
|
match field_data {
|
||||||
Some(Either::First((_, RecordFieldExpr::Value(loc_val)))) => {
|
Either::First((loc_label, (spaces, opt_loc_val))) => {
|
||||||
RequiredValue(loc_label, spaces, arena.alloc(loc_val))
|
match opt_loc_val {
|
||||||
}
|
Some(Either::First((_, RecordFieldExpr::Value(loc_val)))) => {
|
||||||
|
RequiredValue(loc_label, spaces, arena.alloc(loc_val))
|
||||||
|
}
|
||||||
|
|
||||||
Some(Either::First((_, RecordFieldExpr::Apply(arrow_spaces, loc_val)))) => {
|
Some(Either::First((_, RecordFieldExpr::Apply(arrow_spaces, loc_val)))) => {
|
||||||
ApplyValue(loc_label, spaces, arrow_spaces, arena.alloc(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))
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no value was provided, record it as a Var.
|
// If no value was provided, record it as a Var.
|
||||||
// Canonicalize will know what to do with a Var later.
|
// Canonicalize will know what to do with a Var later.
|
||||||
None => {
|
None => {
|
||||||
if !spaces.is_empty() {
|
if !spaces.is_empty() {
|
||||||
SpaceAfter(arena.alloc(LabelOnly(loc_label)), spaces)
|
SpaceAfter(arena.alloc(LabelOnly(loc_label)), spaces)
|
||||||
} else {
|
} else {
|
||||||
LabelOnly(loc_label)
|
LabelOnly(loc_label)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Either::Second((loc_opt_label, (spaces, loc_val))) => {
|
||||||
|
let loc_label = loc_opt_label
|
||||||
|
.map(|opt_label| opt_label.unwrap_or_else(|| arena.alloc_str("")));
|
||||||
|
|
||||||
|
IgnoredValue(loc_label, spaces, arena.alloc(loc_val))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
@ -3573,20 +3630,23 @@ fn record_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
|
||||||
new_record_builder_help(arena, mapper, record.fields)
|
new_record_builder_help(arena, mapper, record.fields)
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let is_old_record_builder = record
|
let special_field_found = record.fields.iter().find_map(|field| {
|
||||||
.fields
|
if field.value.is_apply_value() {
|
||||||
.iter()
|
Some(old_record_builder_help(arena, record.fields))
|
||||||
.any(|field| field.value.is_apply_value());
|
} else if field.value.is_ignored_value() {
|
||||||
|
Some(Err(EExpr::RecordUpdateIgnoredField(field.region)))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if is_old_record_builder {
|
special_field_found.unwrap_or_else(|| {
|
||||||
old_record_builder_help(arena, record.fields)
|
|
||||||
} 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).unwrap())
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(Expr::Record(fields))
|
Ok(Expr::Record(fields))
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -3609,11 +3669,14 @@ 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(_, _, _)) => {
|
||||||
|
Err(EExpr::RecordUpdateIgnoredField(loc_field.region))
|
||||||
|
}
|
||||||
Ok(builder_field) => Ok(Loc {
|
Ok(builder_field) => Ok(Loc {
|
||||||
region: loc_field.region,
|
region: loc_field.region,
|
||||||
value: builder_field,
|
value: builder_field,
|
||||||
}),
|
}),
|
||||||
Err(FoundApplyValue) => Err(EExpr::RecordUpdateAccumulator(loc_field.region)),
|
Err(FoundApplyValue) => Err(EExpr::RecordUpdateOldBuilderField(loc_field.region)),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -3634,7 +3697,7 @@ fn new_record_builder_help<'a>(
|
||||||
region: loc_field.region,
|
region: loc_field.region,
|
||||||
value: builder_field,
|
value: builder_field,
|
||||||
}),
|
}),
|
||||||
Err(FoundApplyValue) => Err(EExpr::RecordBuilderAccumulator(loc_field.region)),
|
Err(FoundApplyValue) => Err(EExpr::RecordBuilderOldBuilderField(loc_field.region)),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -3654,7 +3717,12 @@ fn old_record_builder_help<'a>(
|
||||||
region: loc_field.region,
|
region: loc_field.region,
|
||||||
value: builder_field,
|
value: builder_field,
|
||||||
}),
|
}),
|
||||||
Err(FoundOptionalValue) => Err(EExpr::OptionalValueInRecordBuilder(loc_field.region)),
|
Err(NotOldBuilderFieldValue::FoundOptionalValue) => {
|
||||||
|
Err(EExpr::OptionalValueInOldRecordBuilder(loc_field.region))
|
||||||
|
}
|
||||||
|
Err(NotOldBuilderFieldValue::FoundIgnoredValue) => {
|
||||||
|
Err(EExpr::IgnoredValueInOldRecordBuilder(loc_field.region))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,949 @@
|
||||||
use crate::ast::{
|
|
||||||
Collection, CommentOrNewline, Malformed, Pattern, Spaced, Spaces, StrLiteral, TypeAnnotation,
|
|
||||||
};
|
|
||||||
use crate::blankspace::space0_e;
|
|
||||||
use crate::expr::merge_spaces;
|
|
||||||
use crate::ident::{lowercase_ident, UppercaseIdent};
|
|
||||||
use crate::parser::{
|
|
||||||
and, byte, loc, map_with_arena, skip_first, skip_second, specialize_err, EPackageEntry,
|
|
||||||
EPackageName, Parser,
|
|
||||||
};
|
|
||||||
use crate::parser::{optional, then};
|
|
||||||
use crate::string_literal;
|
|
||||||
use roc_module::symbol::ModuleId;
|
|
||||||
use roc_region::all::Loc;
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use crate::ast::{
|
||||||
|
Collection, CommentOrNewline, Defs, Header, Malformed, Pattern, Spaced, Spaces, SpacesBefore,
|
||||||
|
StrLiteral, TypeAnnotation,
|
||||||
|
};
|
||||||
|
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
|
||||||
|
use crate::expr::merge_spaces;
|
||||||
|
use crate::ident::{self, lowercase_ident, unqualified_ident, uppercase, 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,
|
||||||
|
then, two_bytes, zero_or_more, EExposes, EGenerates, EGeneratesWith, EHeader, EImports,
|
||||||
|
EPackageEntry, EPackageName, 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_module::symbol::{ModuleId, Symbol};
|
||||||
|
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<(SpacesBefore<'a, Header<'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, SpacesBefore<'a, Header<'a>>, EHeader<'a>> {
|
||||||
|
use crate::parser::keyword;
|
||||||
|
|
||||||
|
record!(SpacesBefore {
|
||||||
|
before: space0_e(EHeader::IndentStart),
|
||||||
|
item: 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()),
|
||||||
|
generates: specialize_err(EHeader::Generates, generates()),
|
||||||
|
generates_with: specialize_err(EHeader::GeneratesWith, generates_with()),
|
||||||
|
})
|
||||||
|
.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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn generates<'a>(
|
||||||
|
) -> impl Parser<'a, KeywordItem<'a, GeneratesKeyword, UppercaseIdent<'a>>, EGenerates> {
|
||||||
|
record!(KeywordItem {
|
||||||
|
keyword: spaces_around_keyword(
|
||||||
|
GeneratesKeyword,
|
||||||
|
EGenerates::Generates,
|
||||||
|
EGenerates::IndentGenerates,
|
||||||
|
EGenerates::IndentTypeStart
|
||||||
|
),
|
||||||
|
item: specialize_err(|(), pos| EGenerates::Identifier(pos), uppercase())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn generates_with<'a>() -> impl Parser<
|
||||||
|
'a,
|
||||||
|
KeywordItem<'a, WithKeyword, Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>>,
|
||||||
|
EGeneratesWith,
|
||||||
|
> {
|
||||||
|
record!(KeywordItem {
|
||||||
|
keyword: spaces_around_keyword(
|
||||||
|
WithKeyword,
|
||||||
|
EGeneratesWith::With,
|
||||||
|
EGeneratesWith::IndentWith,
|
||||||
|
EGeneratesWith::IndentListStart
|
||||||
|
),
|
||||||
|
item: collection_trailing_sep_e(
|
||||||
|
byte(b'[', EGeneratesWith::ListStart),
|
||||||
|
exposes_entry(EGeneratesWith::Identifier),
|
||||||
|
byte(b',', EGeneratesWith::ListEnd),
|
||||||
|
byte(b']', EGeneratesWith::ListEnd),
|
||||||
|
Spaced::SpaceBefore
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
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 -> Effect {}
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> HeaderType<'a> {
|
impl<'a> HeaderType<'a> {
|
||||||
pub fn exposed_or_provided_values(&'a self) -> &'a [Loc<ExposedName<'a>>] {
|
pub fn exposed_or_provided_values(&'a self) -> &'a [Loc<ExposedName<'a>>] {
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -173,7 +1103,7 @@ impl<'a> ModuleName<'a> {
|
||||||
ModuleName(name)
|
ModuleName(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn as_str(&'a self) -> &'a str {
|
pub const fn as_str(&self) -> &'a str {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ pub fn highlight(text: &str) -> Vec<Loc<Token>> {
|
||||||
let header_keywords = HEADER_KEYWORDS.iter().copied().collect::<HashSet<_>>();
|
let header_keywords = HEADER_KEYWORDS.iter().copied().collect::<HashSet<_>>();
|
||||||
let body_keywords = KEYWORDS.iter().copied().collect::<HashSet<_>>();
|
let body_keywords = KEYWORDS.iter().copied().collect::<HashSet<_>>();
|
||||||
|
|
||||||
if let Ok((_prog, _, new_state)) = crate::module::header().parse(&arena, state.clone(), 0) {
|
if let Ok((_prog, _, new_state)) = crate::header::header().parse(&arena, state.clone(), 0) {
|
||||||
let inner_state =
|
let inner_state =
|
||||||
State::new(text[..state.bytes().len() - new_state.bytes().len()].as_bytes());
|
State::new(text[..state.bytes().len() - new_state.bytes().len()].as_bytes());
|
||||||
highlight_inner(&arena, inner_state, &mut tokens, &header_keywords);
|
highlight_inner(&arena, inner_state, &mut tokens, &header_keywords);
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ pub mod header;
|
||||||
pub mod highlight;
|
pub mod highlight;
|
||||||
pub mod ident;
|
pub mod ident;
|
||||||
pub mod keyword;
|
pub mod keyword;
|
||||||
pub mod module;
|
|
||||||
pub mod number_literal;
|
pub mod number_literal;
|
||||||
pub mod pattern;
|
pub mod pattern;
|
||||||
pub mod problems;
|
pub mod problems;
|
||||||
|
|
|
||||||
|
|
@ -344,9 +344,11 @@ pub enum EExpr<'a> {
|
||||||
|
|
||||||
InParens(EInParens<'a>, Position),
|
InParens(EInParens<'a>, Position),
|
||||||
Record(ERecord<'a>, Position),
|
Record(ERecord<'a>, Position),
|
||||||
OptionalValueInRecordBuilder(Region),
|
OptionalValueInOldRecordBuilder(Region),
|
||||||
RecordUpdateAccumulator(Region),
|
IgnoredValueInOldRecordBuilder(Region),
|
||||||
RecordBuilderAccumulator(Region),
|
RecordUpdateOldBuilderField(Region),
|
||||||
|
RecordUpdateIgnoredField(Region),
|
||||||
|
RecordBuilderOldBuilderField(Region),
|
||||||
|
|
||||||
// SingleQuote errors are folded into the EString
|
// SingleQuote errors are folded into the EString
|
||||||
Str(EString<'a>, Position),
|
Str(EString<'a>, Position),
|
||||||
|
|
@ -400,6 +402,7 @@ pub enum ERecord<'a> {
|
||||||
|
|
||||||
Prefix(Position),
|
Prefix(Position),
|
||||||
Field(Position),
|
Field(Position),
|
||||||
|
UnderscoreField(Position),
|
||||||
Colon(Position),
|
Colon(Position),
|
||||||
QuestionMark(Position),
|
QuestionMark(Position),
|
||||||
Arrow(Position),
|
Arrow(Position),
|
||||||
|
|
@ -549,6 +552,7 @@ pub enum EImportParams<'a> {
|
||||||
RecordUpdateFound(Region),
|
RecordUpdateFound(Region),
|
||||||
RecordBuilderFound(Region),
|
RecordBuilderFound(Region),
|
||||||
RecordApplyFound(Region),
|
RecordApplyFound(Region),
|
||||||
|
RecordIgnoredFieldFound(Region),
|
||||||
Space(BadInputError, Position),
|
Space(BadInputError, Position),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -707,6 +711,7 @@ pub enum ETypeAbilityImpl<'a> {
|
||||||
Open(Position),
|
Open(Position),
|
||||||
|
|
||||||
Field(Position),
|
Field(Position),
|
||||||
|
UnderscoreField(Position),
|
||||||
Colon(Position),
|
Colon(Position),
|
||||||
Arrow(Position),
|
Arrow(Position),
|
||||||
Optional(Position),
|
Optional(Position),
|
||||||
|
|
@ -728,6 +733,7 @@ impl<'a> From<ERecord<'a>> for ETypeAbilityImpl<'a> {
|
||||||
ERecord::End(p) => ETypeAbilityImpl::End(p),
|
ERecord::End(p) => ETypeAbilityImpl::End(p),
|
||||||
ERecord::Open(p) => ETypeAbilityImpl::Open(p),
|
ERecord::Open(p) => ETypeAbilityImpl::Open(p),
|
||||||
ERecord::Field(p) => ETypeAbilityImpl::Field(p),
|
ERecord::Field(p) => ETypeAbilityImpl::Field(p),
|
||||||
|
ERecord::UnderscoreField(p) => ETypeAbilityImpl::UnderscoreField(p),
|
||||||
ERecord::Colon(p) => ETypeAbilityImpl::Colon(p),
|
ERecord::Colon(p) => ETypeAbilityImpl::Colon(p),
|
||||||
ERecord::Arrow(p) => ETypeAbilityImpl::Arrow(p),
|
ERecord::Arrow(p) => ETypeAbilityImpl::Arrow(p),
|
||||||
ERecord::Space(s, p) => ETypeAbilityImpl::Space(s, p),
|
ERecord::Space(s, p) => ETypeAbilityImpl::Space(s, p),
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,12 @@ use roc_region::all::{Loc, Position, Region};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{
|
ast::{
|
||||||
AbilityImpls, AbilityMember, AssignedField, Collection, Defs, Expr, Header, Implements,
|
AbilityImpls, AbilityMember, AssignedField, Collection, Defs, Expr, FullAst, Header,
|
||||||
ImplementsAbilities, ImplementsAbility, ImplementsClause, ImportAlias, ImportAsKeyword,
|
Implements, ImplementsAbilities, ImplementsAbility, ImplementsClause, ImportAlias,
|
||||||
ImportExposingKeyword, ImportedModuleName, IngestedFileAnnotation, IngestedFileImport,
|
ImportAsKeyword, ImportExposingKeyword, ImportedModuleName, IngestedFileAnnotation,
|
||||||
Module, ModuleImport, ModuleImportParams, OldRecordBuilderField, Pattern, PatternAs,
|
IngestedFileImport, ModuleImport, ModuleImportParams, OldRecordBuilderField, Pattern,
|
||||||
Spaced, Spaces, StrLiteral, StrSegment, Tag, TypeAnnotation, TypeDef, TypeHeader, ValueDef,
|
PatternAs, Spaced, Spaces, SpacesBefore, StrLiteral, StrSegment, Tag, TypeAnnotation,
|
||||||
WhenBranch,
|
TypeDef, TypeHeader, ValueDef, WhenBranch,
|
||||||
},
|
},
|
||||||
header::{
|
header::{
|
||||||
AppHeader, ExposedName, ExposesKeyword, HostedHeader, ImportsEntry, ImportsKeyword,
|
AppHeader, ExposedName, ExposesKeyword, HostedHeader, ImportsEntry, ImportsKeyword,
|
||||||
|
|
@ -99,6 +99,24 @@ impl<'a, V: RemoveSpaces<'a>> RemoveSpaces<'a> for Spaces<'a, V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, V: RemoveSpaces<'a>> RemoveSpaces<'a> for SpacesBefore<'a, V> {
|
||||||
|
fn remove_spaces(&self, arena: &'a Bump) -> Self {
|
||||||
|
SpacesBefore {
|
||||||
|
before: &[],
|
||||||
|
item: self.item.remove_spaces(arena),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> RemoveSpaces<'a> for FullAst<'a> {
|
||||||
|
fn remove_spaces(&self, arena: &'a Bump) -> Self {
|
||||||
|
FullAst {
|
||||||
|
header: self.header.remove_spaces(arena),
|
||||||
|
defs: self.defs.remove_spaces(arena),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, K: RemoveSpaces<'a>, V: RemoveSpaces<'a>> RemoveSpaces<'a> for KeywordItem<'a, K, V> {
|
impl<'a, K: RemoveSpaces<'a>, V: RemoveSpaces<'a>> RemoveSpaces<'a> for KeywordItem<'a, K, V> {
|
||||||
fn remove_spaces(&self, arena: &'a Bump) -> Self {
|
fn remove_spaces(&self, arena: &'a Bump) -> Self {
|
||||||
KeywordItem {
|
KeywordItem {
|
||||||
|
|
@ -120,9 +138,9 @@ impl<'a> RemoveSpaces<'a> for ProvidesTo<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RemoveSpaces<'a> for Module<'a> {
|
impl<'a> RemoveSpaces<'a> for Header<'a> {
|
||||||
fn remove_spaces(&self, arena: &'a Bump) -> Self {
|
fn remove_spaces(&self, arena: &'a Bump) -> Self {
|
||||||
let header = match &self.header {
|
match self {
|
||||||
Header::Module(header) => Header::Module(ModuleHeader {
|
Header::Module(header) => Header::Module(ModuleHeader {
|
||||||
after_keyword: &[],
|
after_keyword: &[],
|
||||||
params: header.params.remove_spaces(arena),
|
params: header.params.remove_spaces(arena),
|
||||||
|
|
@ -160,10 +178,6 @@ impl<'a> RemoveSpaces<'a> for Module<'a> {
|
||||||
exposes: header.exposes.remove_spaces(arena),
|
exposes: header.exposes.remove_spaces(arena),
|
||||||
imports: header.imports.remove_spaces(arena),
|
imports: header.imports.remove_spaces(arena),
|
||||||
}),
|
}),
|
||||||
};
|
|
||||||
Module {
|
|
||||||
comments: &[],
|
|
||||||
header,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -538,6 +552,11 @@ impl<'a, T: RemoveSpaces<'a> + Copy + std::fmt::Debug> RemoveSpaces<'a> for Assi
|
||||||
arena.alloc([]),
|
arena.alloc([]),
|
||||||
arena.alloc(c.remove_spaces(arena)),
|
arena.alloc(c.remove_spaces(arena)),
|
||||||
),
|
),
|
||||||
|
AssignedField::IgnoredValue(a, _, c) => AssignedField::IgnoredValue(
|
||||||
|
a.remove_spaces(arena),
|
||||||
|
arena.alloc([]),
|
||||||
|
arena.alloc(c.remove_spaces(arena)),
|
||||||
|
),
|
||||||
AssignedField::LabelOnly(a) => AssignedField::LabelOnly(a.remove_spaces(arena)),
|
AssignedField::LabelOnly(a) => AssignedField::LabelOnly(a.remove_spaces(arena)),
|
||||||
AssignedField::Malformed(a) => AssignedField::Malformed(a),
|
AssignedField::Malformed(a) => AssignedField::Malformed(a),
|
||||||
AssignedField::SpaceBefore(a, _) => a.remove_spaces(arena),
|
AssignedField::SpaceBefore(a, _) => a.remove_spaces(arena),
|
||||||
|
|
@ -978,8 +997,11 @@ impl<'a> RemoveSpaces<'a> for EExpr<'a> {
|
||||||
EExpr::Record(inner_err, _pos) => {
|
EExpr::Record(inner_err, _pos) => {
|
||||||
EExpr::Record(inner_err.remove_spaces(arena), Position::zero())
|
EExpr::Record(inner_err.remove_spaces(arena), Position::zero())
|
||||||
}
|
}
|
||||||
EExpr::OptionalValueInRecordBuilder(_pos) => {
|
EExpr::OptionalValueInOldRecordBuilder(_pos) => {
|
||||||
EExpr::OptionalValueInRecordBuilder(Region::zero())
|
EExpr::OptionalValueInOldRecordBuilder(Region::zero())
|
||||||
|
}
|
||||||
|
EExpr::IgnoredValueInOldRecordBuilder(_pos) => {
|
||||||
|
EExpr::OptionalValueInOldRecordBuilder(Region::zero())
|
||||||
}
|
}
|
||||||
EExpr::Str(inner_err, _pos) => {
|
EExpr::Str(inner_err, _pos) => {
|
||||||
EExpr::Str(inner_err.remove_spaces(arena), Position::zero())
|
EExpr::Str(inner_err.remove_spaces(arena), Position::zero())
|
||||||
|
|
@ -993,8 +1015,15 @@ impl<'a> RemoveSpaces<'a> for EExpr<'a> {
|
||||||
EExpr::UnexpectedComma(_pos) => EExpr::UnexpectedComma(Position::zero()),
|
EExpr::UnexpectedComma(_pos) => EExpr::UnexpectedComma(Position::zero()),
|
||||||
EExpr::UnexpectedTopLevelExpr(_pos) => EExpr::UnexpectedTopLevelExpr(Position::zero()),
|
EExpr::UnexpectedTopLevelExpr(_pos) => EExpr::UnexpectedTopLevelExpr(Position::zero()),
|
||||||
EExpr::StmtAfterExpr(_pos) => EExpr::StmtAfterExpr(Position::zero()),
|
EExpr::StmtAfterExpr(_pos) => EExpr::StmtAfterExpr(Position::zero()),
|
||||||
EExpr::RecordUpdateAccumulator(_) => EExpr::RecordUpdateAccumulator(Region::zero()),
|
EExpr::RecordUpdateOldBuilderField(_pos) => {
|
||||||
EExpr::RecordBuilderAccumulator(_) => EExpr::RecordBuilderAccumulator(Region::zero()),
|
EExpr::RecordUpdateOldBuilderField(Region::zero())
|
||||||
|
}
|
||||||
|
EExpr::RecordUpdateIgnoredField(_pos) => {
|
||||||
|
EExpr::RecordUpdateIgnoredField(Region::zero())
|
||||||
|
}
|
||||||
|
EExpr::RecordBuilderOldBuilderField(_pos) => {
|
||||||
|
EExpr::RecordBuilderOldBuilderField(Region::zero())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1084,6 +1113,7 @@ impl<'a> RemoveSpaces<'a> for ERecord<'a> {
|
||||||
ERecord::End(_) => ERecord::End(Position::zero()),
|
ERecord::End(_) => ERecord::End(Position::zero()),
|
||||||
ERecord::Open(_) => ERecord::Open(Position::zero()),
|
ERecord::Open(_) => ERecord::Open(Position::zero()),
|
||||||
ERecord::Field(_pos) => ERecord::Field(Position::zero()),
|
ERecord::Field(_pos) => ERecord::Field(Position::zero()),
|
||||||
|
ERecord::UnderscoreField(_pos) => ERecord::Field(Position::zero()),
|
||||||
ERecord::Colon(_) => ERecord::Colon(Position::zero()),
|
ERecord::Colon(_) => ERecord::Colon(Position::zero()),
|
||||||
ERecord::QuestionMark(_) => ERecord::QuestionMark(Position::zero()),
|
ERecord::QuestionMark(_) => ERecord::QuestionMark(Position::zero()),
|
||||||
ERecord::Arrow(_) => ERecord::Arrow(Position::zero()),
|
ERecord::Arrow(_) => ERecord::Arrow(Position::zero()),
|
||||||
|
|
@ -1212,6 +1242,9 @@ impl<'a> RemoveSpaces<'a> for EImportParams<'a> {
|
||||||
}
|
}
|
||||||
EImportParams::RecordUpdateFound(_) => EImportParams::RecordUpdateFound(Region::zero()),
|
EImportParams::RecordUpdateFound(_) => EImportParams::RecordUpdateFound(Region::zero()),
|
||||||
EImportParams::RecordApplyFound(_) => EImportParams::RecordApplyFound(Region::zero()),
|
EImportParams::RecordApplyFound(_) => EImportParams::RecordApplyFound(Region::zero()),
|
||||||
|
EImportParams::RecordIgnoredFieldFound(_) => {
|
||||||
|
EImportParams::RecordIgnoredFieldFound(Region::zero())
|
||||||
|
}
|
||||||
EImportParams::Space(inner_err, _) => {
|
EImportParams::Space(inner_err, _) => {
|
||||||
EImportParams::Space(*inner_err, Position::zero())
|
EImportParams::Space(*inner_err, Position::zero())
|
||||||
}
|
}
|
||||||
|
|
@ -1243,6 +1276,9 @@ impl<'a> RemoveSpaces<'a> for ETypeAbilityImpl<'a> {
|
||||||
ETypeAbilityImpl::End(_) => ETypeAbilityImpl::End(Position::zero()),
|
ETypeAbilityImpl::End(_) => ETypeAbilityImpl::End(Position::zero()),
|
||||||
ETypeAbilityImpl::Open(_) => ETypeAbilityImpl::Open(Position::zero()),
|
ETypeAbilityImpl::Open(_) => ETypeAbilityImpl::Open(Position::zero()),
|
||||||
ETypeAbilityImpl::Field(_) => ETypeAbilityImpl::Field(Position::zero()),
|
ETypeAbilityImpl::Field(_) => ETypeAbilityImpl::Field(Position::zero()),
|
||||||
|
ETypeAbilityImpl::UnderscoreField(_) => {
|
||||||
|
ETypeAbilityImpl::UnderscoreField(Position::zero())
|
||||||
|
}
|
||||||
ETypeAbilityImpl::Colon(_) => ETypeAbilityImpl::Colon(Position::zero()),
|
ETypeAbilityImpl::Colon(_) => ETypeAbilityImpl::Colon(Position::zero()),
|
||||||
ETypeAbilityImpl::Arrow(_) => ETypeAbilityImpl::Arrow(Position::zero()),
|
ETypeAbilityImpl::Arrow(_) => ETypeAbilityImpl::Arrow(Position::zero()),
|
||||||
ETypeAbilityImpl::Optional(_) => ETypeAbilityImpl::Optional(Position::zero()),
|
ETypeAbilityImpl::Optional(_) => ETypeAbilityImpl::Optional(Position::zero()),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
use crate::ast;
|
use crate::ast;
|
||||||
use crate::ast::Defs;
|
use crate::ast::Defs;
|
||||||
use crate::module::parse_module_defs;
|
use crate::ast::Header;
|
||||||
|
use crate::ast::SpacesBefore;
|
||||||
|
use crate::header::parse_module_defs;
|
||||||
use crate::parser::SourceError;
|
use crate::parser::SourceError;
|
||||||
use crate::parser::SyntaxError;
|
use crate::parser::SyntaxError;
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
|
|
@ -39,10 +41,10 @@ pub fn parse_defs_with<'a>(arena: &'a Bump, input: &'a str) -> Result<Defs<'a>,
|
||||||
pub fn parse_header_with<'a>(
|
pub fn parse_header_with<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
input: &'a str,
|
input: &'a str,
|
||||||
) -> Result<ast::Module<'a>, SyntaxError<'a>> {
|
) -> Result<SpacesBefore<'a, Header<'a>>, SyntaxError<'a>> {
|
||||||
let state = State::new(input.as_bytes());
|
let state = State::new(input.as_bytes());
|
||||||
|
|
||||||
match crate::module::parse_header(arena, state.clone()) {
|
match crate::header::parse_header(arena, state.clone()) {
|
||||||
Ok((header, _)) => Ok(header),
|
Ok((header, _)) => Ok(header),
|
||||||
Err(fail) => Err(SyntaxError::Header(fail.problem)),
|
Err(fail) => Err(SyntaxError::Header(fail.problem)),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -565,6 +565,9 @@ 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(_, _, _)) => {
|
||||||
|
Err((MadeProgress, ERecord::Field(state.pos())))
|
||||||
|
}
|
||||||
Ok(assigned_field) => Ok((MadeProgress, assigned_field, state)),
|
Ok(assigned_field) => Ok((MadeProgress, assigned_field, state)),
|
||||||
Err(FoundApplyValue) => Err((MadeProgress, ERecord::Field(state.pos()))),
|
Err(FoundApplyValue) => Err((MadeProgress, ERecord::Field(state.pos()))),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ mod test_parse {
|
||||||
use roc_parse::ast::StrSegment::*;
|
use roc_parse::ast::StrSegment::*;
|
||||||
use roc_parse::ast::{self, EscapedChar};
|
use roc_parse::ast::{self, EscapedChar};
|
||||||
use roc_parse::ast::{CommentOrNewline, StrLiteral::*};
|
use roc_parse::ast::{CommentOrNewline, StrLiteral::*};
|
||||||
use roc_parse::module::parse_module_defs;
|
use roc_parse::header::parse_module_defs;
|
||||||
use roc_parse::parser::SyntaxError;
|
use roc_parse::parser::SyntaxError;
|
||||||
use roc_parse::state::State;
|
use roc_parse::state::State;
|
||||||
use roc_parse::test_helpers::parse_expr_with;
|
use roc_parse::test_helpers::parse_expr_with;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_fmt::{annotation::Formattable, module::fmt_module};
|
use roc_fmt::{annotation::Formattable, header::fmt_header};
|
||||||
use roc_parse::{
|
use roc_parse::{
|
||||||
ast::{Defs, Expr, Malformed, Module},
|
ast::{Defs, Expr, FullAst, Header, Malformed, SpacesBefore},
|
||||||
module::parse_module_defs,
|
header::parse_module_defs,
|
||||||
parser::{Parser, SyntaxError},
|
parser::{Parser, SyntaxError},
|
||||||
remove_spaces::RemoveSpaces,
|
remove_spaces::RemoveSpaces,
|
||||||
state::State,
|
state::State,
|
||||||
|
|
@ -70,16 +70,13 @@ impl InputOwned {
|
||||||
/// Output AST of a successful parse
|
/// Output AST of a successful parse
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Output<'a> {
|
pub enum Output<'a> {
|
||||||
Header(Module<'a>),
|
Header(SpacesBefore<'a, Header<'a>>),
|
||||||
|
|
||||||
ModuleDefs(Defs<'a>),
|
ModuleDefs(Defs<'a>),
|
||||||
|
|
||||||
Expr(Expr<'a>),
|
Expr(Expr<'a>),
|
||||||
|
|
||||||
Full {
|
Full(FullAst<'a>),
|
||||||
header: Module<'a>,
|
|
||||||
module_defs: Defs<'a>,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Output<'a> {
|
impl<'a> Output<'a> {
|
||||||
|
|
@ -88,7 +85,7 @@ impl<'a> Output<'a> {
|
||||||
let mut buf = Buf::new_in(&arena);
|
let mut buf = Buf::new_in(&arena);
|
||||||
match self {
|
match self {
|
||||||
Output::Header(header) => {
|
Output::Header(header) => {
|
||||||
fmt_module(&mut buf, header);
|
fmt_header(&mut buf, header);
|
||||||
buf.fmt_end_of_file();
|
buf.fmt_end_of_file();
|
||||||
InputOwned::Header(buf.as_str().to_string())
|
InputOwned::Header(buf.as_str().to_string())
|
||||||
}
|
}
|
||||||
|
|
@ -101,12 +98,9 @@ impl<'a> Output<'a> {
|
||||||
expr.format(&mut buf, 0);
|
expr.format(&mut buf, 0);
|
||||||
InputOwned::Expr(buf.as_str().to_string())
|
InputOwned::Expr(buf.as_str().to_string())
|
||||||
}
|
}
|
||||||
Output::Full {
|
Output::Full(full) => {
|
||||||
header,
|
fmt_header(&mut buf, &full.header);
|
||||||
module_defs,
|
full.defs.format(&mut buf, 0);
|
||||||
} => {
|
|
||||||
fmt_module(&mut buf, header);
|
|
||||||
module_defs.format(&mut buf, 0);
|
|
||||||
buf.fmt_end_of_file();
|
buf.fmt_end_of_file();
|
||||||
InputOwned::Full(buf.as_str().to_string())
|
InputOwned::Full(buf.as_str().to_string())
|
||||||
}
|
}
|
||||||
|
|
@ -129,10 +123,7 @@ impl<'a> Malformed for Output<'a> {
|
||||||
Output::Header(header) => header.is_malformed(),
|
Output::Header(header) => header.is_malformed(),
|
||||||
Output::ModuleDefs(defs) => defs.is_malformed(),
|
Output::ModuleDefs(defs) => defs.is_malformed(),
|
||||||
Output::Expr(expr) => expr.is_malformed(),
|
Output::Expr(expr) => expr.is_malformed(),
|
||||||
Output::Full {
|
Output::Full(full) => full.is_malformed(),
|
||||||
header,
|
|
||||||
module_defs,
|
|
||||||
} => header.is_malformed() || module_defs.is_malformed(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -143,13 +134,7 @@ impl<'a> RemoveSpaces<'a> for Output<'a> {
|
||||||
Output::Header(header) => Output::Header(header.remove_spaces(arena)),
|
Output::Header(header) => Output::Header(header.remove_spaces(arena)),
|
||||||
Output::ModuleDefs(defs) => Output::ModuleDefs(defs.remove_spaces(arena)),
|
Output::ModuleDefs(defs) => Output::ModuleDefs(defs.remove_spaces(arena)),
|
||||||
Output::Expr(expr) => Output::Expr(expr.remove_spaces(arena)),
|
Output::Expr(expr) => Output::Expr(expr.remove_spaces(arena)),
|
||||||
Output::Full {
|
Output::Full(full) => Output::Full(full.remove_spaces(arena)),
|
||||||
header,
|
|
||||||
module_defs,
|
|
||||||
} => Output::Full {
|
|
||||||
header: header.remove_spaces(arena),
|
|
||||||
module_defs: module_defs.remove_spaces(arena),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -185,18 +170,19 @@ impl<'a> Input<'a> {
|
||||||
let state = State::new(input.as_bytes());
|
let state = State::new(input.as_bytes());
|
||||||
|
|
||||||
let min_indent = 0;
|
let min_indent = 0;
|
||||||
let (_, header, state) = roc_parse::module::header()
|
let (_, header, state) = roc_parse::header::header()
|
||||||
.parse(arena, state.clone(), min_indent)
|
.parse(arena, state.clone(), min_indent)
|
||||||
.map_err(|(_, fail)| SyntaxError::Header(fail))?;
|
.map_err(|(_, fail)| SyntaxError::Header(fail))?;
|
||||||
|
|
||||||
let (header, defs) = header.upgrade_header_imports(arena);
|
let (new_header, defs) = header.item.upgrade_header_imports(arena);
|
||||||
|
let header = SpacesBefore {
|
||||||
|
before: header.before,
|
||||||
|
item: new_header,
|
||||||
|
};
|
||||||
|
|
||||||
let module_defs = parse_module_defs(arena, state, defs)?;
|
let defs = parse_module_defs(arena, state, defs)?;
|
||||||
|
|
||||||
Ok(Output::Full {
|
Ok(Output::Full(FullAst { header, defs }))
|
||||||
header,
|
|
||||||
module_defs,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
Module {
|
SpacesBefore {
|
||||||
comments: [],
|
before: [],
|
||||||
header: App(
|
item: App(
|
||||||
AppHeader {
|
AppHeader {
|
||||||
before_provides: [],
|
before_provides: [],
|
||||||
provides: [],
|
provides: [],
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
Module {
|
SpacesBefore {
|
||||||
comments: [],
|
before: [],
|
||||||
header: Hosted(
|
item: Hosted(
|
||||||
HostedHeader {
|
HostedHeader {
|
||||||
before_name: [],
|
before_name: [],
|
||||||
name: @7-10 ModuleName(
|
name: @7-10 ModuleName(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
Module {
|
SpacesBefore {
|
||||||
comments: [],
|
before: [],
|
||||||
header: Module(
|
item: Module(
|
||||||
ModuleHeader {
|
ModuleHeader {
|
||||||
after_keyword: [],
|
after_keyword: [],
|
||||||
params: None,
|
params: None,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
Module {
|
SpacesBefore {
|
||||||
comments: [],
|
before: [],
|
||||||
header: Package(
|
item: Package(
|
||||||
PackageHeader {
|
PackageHeader {
|
||||||
before_exposes: [],
|
before_exposes: [],
|
||||||
exposes: [],
|
exposes: [],
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
Module {
|
SpacesBefore {
|
||||||
comments: [],
|
before: [],
|
||||||
header: Platform(
|
item: Platform(
|
||||||
PlatformHeader {
|
PlatformHeader {
|
||||||
before_name: [],
|
before_name: [],
|
||||||
name: @9-25 PackageName(
|
name: @9-25 PackageName(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
Module {
|
SpacesBefore {
|
||||||
comments: [],
|
before: [],
|
||||||
header: App(
|
item: App(
|
||||||
AppHeader {
|
AppHeader {
|
||||||
before_provides: [],
|
before_provides: [],
|
||||||
provides: [
|
provides: [
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
Module {
|
SpacesBefore {
|
||||||
comments: [],
|
before: [],
|
||||||
header: App(
|
item: App(
|
||||||
AppHeader {
|
AppHeader {
|
||||||
before_provides: [],
|
before_provides: [],
|
||||||
provides: [
|
provides: [
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
Module {
|
SpacesBefore {
|
||||||
comments: [],
|
before: [],
|
||||||
header: Platform(
|
item: Platform(
|
||||||
PlatformHeader {
|
PlatformHeader {
|
||||||
before_name: [],
|
before_name: [],
|
||||||
name: @9-14 PackageName(
|
name: @9-14 PackageName(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
Module {
|
SpacesBefore {
|
||||||
comments: [],
|
before: [],
|
||||||
header: App(
|
item: App(
|
||||||
AppHeader {
|
AppHeader {
|
||||||
before_provides: [],
|
before_provides: [],
|
||||||
provides: [],
|
provides: [],
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
Module {
|
SpacesBefore {
|
||||||
comments: [],
|
before: [],
|
||||||
header: Module(
|
item: Module(
|
||||||
ModuleHeader {
|
ModuleHeader {
|
||||||
after_keyword: [],
|
after_keyword: [],
|
||||||
params: None,
|
params: None,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
Module {
|
SpacesBefore {
|
||||||
comments: [],
|
before: [],
|
||||||
header: Module(
|
item: Module(
|
||||||
ModuleHeader {
|
ModuleHeader {
|
||||||
after_keyword: [],
|
after_keyword: [],
|
||||||
params: Some(
|
params: Some(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
Module {
|
SpacesBefore {
|
||||||
comments: [],
|
before: [],
|
||||||
header: Module(
|
item: Module(
|
||||||
ModuleHeader {
|
ModuleHeader {
|
||||||
after_keyword: [],
|
after_keyword: [],
|
||||||
params: None,
|
params: None,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
Module {
|
SpacesBefore {
|
||||||
comments: [],
|
before: [],
|
||||||
header: Module(
|
item: Module(
|
||||||
ModuleHeader {
|
ModuleHeader {
|
||||||
after_keyword: [],
|
after_keyword: [],
|
||||||
params: Some(
|
params: Some(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
Module {
|
SpacesBefore {
|
||||||
comments: [],
|
before: [],
|
||||||
header: Module(
|
item: Module(
|
||||||
ModuleHeader {
|
ModuleHeader {
|
||||||
after_keyword: [],
|
after_keyword: [],
|
||||||
params: Some(
|
params: Some(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
Module {
|
SpacesBefore {
|
||||||
comments: [],
|
before: [],
|
||||||
header: Module(
|
item: Module(
|
||||||
ModuleHeader {
|
ModuleHeader {
|
||||||
after_keyword: [],
|
after_keyword: [],
|
||||||
params: Some(
|
params: Some(
|
||||||
|
|
|
||||||
|
|
@ -1,81 +1,83 @@
|
||||||
Full {
|
Full(
|
||||||
header: Module {
|
FullAst {
|
||||||
comments: [],
|
header: SpacesBefore {
|
||||||
header: App(
|
before: [],
|
||||||
AppHeader {
|
item: App(
|
||||||
before_provides: [],
|
AppHeader {
|
||||||
provides: [
|
before_provides: [],
|
||||||
@5-9 ExposedName(
|
provides: [
|
||||||
"main",
|
@5-9 ExposedName(
|
||||||
),
|
"main",
|
||||||
],
|
),
|
||||||
before_packages: [],
|
],
|
||||||
packages: @11-134 [
|
before_packages: [],
|
||||||
@13-132 SpaceAfter(
|
packages: @11-134 [
|
||||||
PackageEntry {
|
@13-132 SpaceAfter(
|
||||||
shorthand: "pf",
|
PackageEntry {
|
||||||
spaces_after_shorthand: [
|
shorthand: "pf",
|
||||||
|
spaces_after_shorthand: [
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
platform_marker: None,
|
||||||
|
package_name: @17-132 PackageName(
|
||||||
|
"https://github.com/roc-lang/basic-cli/releases/download/0.12.0/Lb8EgiejTUzbggO2HVVuPJFkwvvsfW6LojkLR20kTVE.tar.br",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
[
|
||||||
Newline,
|
Newline,
|
||||||
],
|
],
|
||||||
platform_marker: None,
|
),
|
||||||
package_name: @17-132 PackageName(
|
],
|
||||||
"https://github.com/roc-lang/basic-cli/releases/download/0.12.0/Lb8EgiejTUzbggO2HVVuPJFkwvvsfW6LojkLR20kTVE.tar.br",
|
old_imports: None,
|
||||||
),
|
old_provides_to_new_package: None,
|
||||||
},
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
defs: Defs {
|
||||||
|
tags: [
|
||||||
|
Index(2147483648),
|
||||||
|
],
|
||||||
|
regions: [
|
||||||
|
@136-183,
|
||||||
|
],
|
||||||
|
space_before: [
|
||||||
|
Slice(start = 0, length = 2),
|
||||||
|
],
|
||||||
|
space_after: [
|
||||||
|
Slice(start = 2, length = 1),
|
||||||
|
],
|
||||||
|
spaces: [
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
type_defs: [],
|
||||||
|
value_defs: [
|
||||||
|
Body(
|
||||||
|
@136-140 Identifier {
|
||||||
|
ident: "main",
|
||||||
|
},
|
||||||
|
@147-183 SpaceBefore(
|
||||||
|
Apply(
|
||||||
|
@147-158 Var {
|
||||||
|
module_name: "Stdout",
|
||||||
|
ident: "line",
|
||||||
|
},
|
||||||
|
[
|
||||||
|
@159-183 Str(
|
||||||
|
PlainLine(
|
||||||
|
"I'm a Roc application!",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
Space,
|
||||||
|
),
|
||||||
[
|
[
|
||||||
Newline,
|
Newline,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
|
||||||
old_imports: None,
|
|
||||||
old_provides_to_new_package: None,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
},
|
|
||||||
module_defs: Defs {
|
|
||||||
tags: [
|
|
||||||
Index(2147483648),
|
|
||||||
],
|
|
||||||
regions: [
|
|
||||||
@136-183,
|
|
||||||
],
|
|
||||||
space_before: [
|
|
||||||
Slice(start = 0, length = 2),
|
|
||||||
],
|
|
||||||
space_after: [
|
|
||||||
Slice(start = 2, length = 1),
|
|
||||||
],
|
|
||||||
spaces: [
|
|
||||||
Newline,
|
|
||||||
Newline,
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
type_defs: [],
|
|
||||||
value_defs: [
|
|
||||||
Body(
|
|
||||||
@136-140 Identifier {
|
|
||||||
ident: "main",
|
|
||||||
},
|
|
||||||
@147-183 SpaceBefore(
|
|
||||||
Apply(
|
|
||||||
@147-158 Var {
|
|
||||||
module_name: "Stdout",
|
|
||||||
ident: "line",
|
|
||||||
},
|
|
||||||
[
|
|
||||||
@159-183 Str(
|
|
||||||
PlainLine(
|
|
||||||
"I'm a Roc application!",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
Space,
|
|
||||||
),
|
|
||||||
[
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
},
|
||||||
},
|
},
|
||||||
}
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
Module {
|
SpacesBefore {
|
||||||
comments: [],
|
before: [],
|
||||||
header: Hosted(
|
item: Hosted(
|
||||||
HostedHeader {
|
HostedHeader {
|
||||||
before_name: [],
|
before_name: [],
|
||||||
name: @7-10 ModuleName(
|
name: @7-10 ModuleName(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
Module {
|
SpacesBefore {
|
||||||
comments: [],
|
before: [],
|
||||||
header: Package(
|
item: Package(
|
||||||
PackageHeader {
|
PackageHeader {
|
||||||
before_exposes: [],
|
before_exposes: [],
|
||||||
exposes: [
|
exposes: [
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
Module {
|
SpacesBefore {
|
||||||
comments: [],
|
before: [],
|
||||||
header: Platform(
|
item: Platform(
|
||||||
PlatformHeader {
|
PlatformHeader {
|
||||||
before_name: [],
|
before_name: [],
|
||||||
name: @9-21 PackageName(
|
name: @9-21 PackageName(
|
||||||
|
|
|
||||||
|
|
@ -1,117 +1,119 @@
|
||||||
Full {
|
Full(
|
||||||
header: Module {
|
FullAst {
|
||||||
comments: [],
|
header: SpacesBefore {
|
||||||
header: App(
|
before: [],
|
||||||
AppHeader {
|
item: App(
|
||||||
before_provides: [
|
AppHeader {
|
||||||
Newline,
|
before_provides: [
|
||||||
],
|
|
||||||
provides: [
|
|
||||||
@143-147 ExposedName(
|
|
||||||
"main",
|
|
||||||
),
|
|
||||||
],
|
|
||||||
before_packages: [
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
packages: @20-88 Collection {
|
|
||||||
items: [
|
|
||||||
@44-81 SpaceBefore(
|
|
||||||
PackageEntry {
|
|
||||||
shorthand: "cli",
|
|
||||||
spaces_after_shorthand: [],
|
|
||||||
platform_marker: Some(
|
|
||||||
[],
|
|
||||||
),
|
|
||||||
package_name: @49-81 PackageName(
|
|
||||||
"../basic-cli/platform/main.roc",
|
|
||||||
),
|
|
||||||
},
|
|
||||||
[
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
final_comments: [
|
|
||||||
Newline,
|
Newline,
|
||||||
],
|
],
|
||||||
},
|
provides: [
|
||||||
old_imports: None,
|
@143-147 ExposedName(
|
||||||
old_provides_to_new_package: None,
|
"main",
|
||||||
},
|
|
||||||
),
|
|
||||||
},
|
|
||||||
module_defs: Defs {
|
|
||||||
tags: [
|
|
||||||
Index(2147483648),
|
|
||||||
Index(2147483649),
|
|
||||||
],
|
|
||||||
regions: [
|
|
||||||
@111-121,
|
|
||||||
@157-187,
|
|
||||||
],
|
|
||||||
space_before: [
|
|
||||||
Slice(start = 0, length = 3),
|
|
||||||
Slice(start = 6, length = 2),
|
|
||||||
],
|
|
||||||
space_after: [
|
|
||||||
Slice(start = 3, length = 3),
|
|
||||||
Slice(start = 8, length = 2),
|
|
||||||
],
|
|
||||||
spaces: [
|
|
||||||
Newline,
|
|
||||||
Newline,
|
|
||||||
Newline,
|
|
||||||
Newline,
|
|
||||||
Newline,
|
|
||||||
Newline,
|
|
||||||
Newline,
|
|
||||||
Newline,
|
|
||||||
Newline,
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
type_defs: [],
|
|
||||||
value_defs: [
|
|
||||||
ModuleImport(
|
|
||||||
ModuleImport {
|
|
||||||
before_name: [],
|
|
||||||
name: @111-121 ImportedModuleName {
|
|
||||||
package: Some(
|
|
||||||
"cli",
|
|
||||||
),
|
),
|
||||||
name: ModuleName(
|
],
|
||||||
"Stdout",
|
before_packages: [
|
||||||
),
|
Newline,
|
||||||
},
|
],
|
||||||
params: None,
|
packages: @20-88 Collection {
|
||||||
alias: None,
|
items: [
|
||||||
exposed: None,
|
@44-81 SpaceBefore(
|
||||||
},
|
PackageEntry {
|
||||||
),
|
shorthand: "cli",
|
||||||
Body(
|
spaces_after_shorthand: [],
|
||||||
@157-161 Identifier {
|
platform_marker: Some(
|
||||||
ident: "main",
|
[],
|
||||||
},
|
),
|
||||||
@168-187 SpaceBefore(
|
package_name: @49-81 PackageName(
|
||||||
Apply(
|
"../basic-cli/platform/main.roc",
|
||||||
@168-179 Var {
|
),
|
||||||
module_name: "Stdout",
|
},
|
||||||
ident: "line",
|
[
|
||||||
},
|
Newline,
|
||||||
[
|
],
|
||||||
@180-187 Str(
|
|
||||||
PlainLine(
|
|
||||||
"hello",
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
Space,
|
final_comments: [
|
||||||
),
|
Newline,
|
||||||
[
|
],
|
||||||
Newline,
|
},
|
||||||
],
|
old_imports: None,
|
||||||
),
|
old_provides_to_new_package: None,
|
||||||
|
},
|
||||||
),
|
),
|
||||||
],
|
},
|
||||||
|
defs: Defs {
|
||||||
|
tags: [
|
||||||
|
Index(2147483648),
|
||||||
|
Index(2147483649),
|
||||||
|
],
|
||||||
|
regions: [
|
||||||
|
@111-121,
|
||||||
|
@157-187,
|
||||||
|
],
|
||||||
|
space_before: [
|
||||||
|
Slice(start = 0, length = 3),
|
||||||
|
Slice(start = 6, length = 2),
|
||||||
|
],
|
||||||
|
space_after: [
|
||||||
|
Slice(start = 3, length = 3),
|
||||||
|
Slice(start = 8, length = 2),
|
||||||
|
],
|
||||||
|
spaces: [
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
type_defs: [],
|
||||||
|
value_defs: [
|
||||||
|
ModuleImport(
|
||||||
|
ModuleImport {
|
||||||
|
before_name: [],
|
||||||
|
name: @111-121 ImportedModuleName {
|
||||||
|
package: Some(
|
||||||
|
"cli",
|
||||||
|
),
|
||||||
|
name: ModuleName(
|
||||||
|
"Stdout",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
params: None,
|
||||||
|
alias: None,
|
||||||
|
exposed: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Body(
|
||||||
|
@157-161 Identifier {
|
||||||
|
ident: "main",
|
||||||
|
},
|
||||||
|
@168-187 SpaceBefore(
|
||||||
|
Apply(
|
||||||
|
@168-179 Var {
|
||||||
|
module_name: "Stdout",
|
||||||
|
ident: "line",
|
||||||
|
},
|
||||||
|
[
|
||||||
|
@180-187 Str(
|
||||||
|
PlainLine(
|
||||||
|
"hello",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
Space,
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
Module {
|
SpacesBefore {
|
||||||
comments: [],
|
before: [],
|
||||||
header: Module(
|
item: Module(
|
||||||
ModuleHeader {
|
ModuleHeader {
|
||||||
after_keyword: [],
|
after_keyword: [],
|
||||||
params: None,
|
params: None,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
Module {
|
SpacesBefore {
|
||||||
comments: [],
|
before: [],
|
||||||
header: App(
|
item: App(
|
||||||
AppHeader {
|
AppHeader {
|
||||||
before_provides: [],
|
before_provides: [],
|
||||||
provides: [
|
provides: [
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
{ Foo.Bar.baz <-
|
||||||
|
x: 5,
|
||||||
|
y: 0,
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
SpaceAfter(
|
||||||
|
RecordBuilder {
|
||||||
|
mapper: @2-13 Var {
|
||||||
|
module_name: "Foo.Bar",
|
||||||
|
ident: "baz",
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
@17-21 RequiredValue(
|
||||||
|
@17-18 "x",
|
||||||
|
[],
|
||||||
|
@20-21 Num(
|
||||||
|
"5",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
@23-27 SpaceAfter(
|
||||||
|
RequiredValue(
|
||||||
|
@23-24 "y",
|
||||||
|
[],
|
||||||
|
@26-27 Num(
|
||||||
|
"0",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
{ Foo.Bar.baz <- x: 5, y: 0
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
{ Foo.Bar.baz <-
|
||||||
|
x: 5,
|
||||||
|
y: 0,
|
||||||
|
_z: 3,
|
||||||
|
_: 2,
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
SpaceAfter(
|
||||||
|
RecordBuilder {
|
||||||
|
mapper: @2-13 Var {
|
||||||
|
module_name: "Foo.Bar",
|
||||||
|
ident: "baz",
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
@17-21 RequiredValue(
|
||||||
|
@17-18 "x",
|
||||||
|
[],
|
||||||
|
@20-21 Num(
|
||||||
|
"5",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
@23-27 RequiredValue(
|
||||||
|
@23-24 "y",
|
||||||
|
[],
|
||||||
|
@26-27 Num(
|
||||||
|
"0",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
@29-34 IgnoredValue(
|
||||||
|
@29-31 "z",
|
||||||
|
[],
|
||||||
|
@33-34 Num(
|
||||||
|
"3",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
@36-40 SpaceAfter(
|
||||||
|
IgnoredValue(
|
||||||
|
@36-37 "",
|
||||||
|
[],
|
||||||
|
@39-40 Num(
|
||||||
|
"2",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
{ Foo.Bar.baz <- x: 5, y: 0, _z: 3, _: 2
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
Module {
|
SpacesBefore {
|
||||||
comments: [],
|
before: [],
|
||||||
header: Platform(
|
item: Platform(
|
||||||
PlatformHeader {
|
PlatformHeader {
|
||||||
before_name: [],
|
before_name: [],
|
||||||
name: @9-21 PackageName(
|
name: @9-21 PackageName(
|
||||||
|
|
|
||||||
|
|
@ -1,71 +1,73 @@
|
||||||
Full {
|
Full(
|
||||||
header: Module {
|
FullAst {
|
||||||
comments: [],
|
header: SpacesBefore {
|
||||||
header: App(
|
before: [],
|
||||||
AppHeader {
|
item: App(
|
||||||
before_provides: [],
|
AppHeader {
|
||||||
provides: [
|
before_provides: [],
|
||||||
@6-10 ExposedName(
|
provides: [
|
||||||
"main",
|
@6-10 ExposedName(
|
||||||
),
|
"main",
|
||||||
],
|
|
||||||
before_packages: [],
|
|
||||||
packages: @13-37 [
|
|
||||||
@15-35 PackageEntry {
|
|
||||||
shorthand: "pf",
|
|
||||||
spaces_after_shorthand: [],
|
|
||||||
platform_marker: Some(
|
|
||||||
[],
|
|
||||||
),
|
|
||||||
package_name: @29-35 PackageName(
|
|
||||||
"path",
|
|
||||||
),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
old_imports: None,
|
|
||||||
old_provides_to_new_package: None,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
},
|
|
||||||
module_defs: Defs {
|
|
||||||
tags: [
|
|
||||||
Index(2147483648),
|
|
||||||
],
|
|
||||||
regions: [
|
|
||||||
@39-65,
|
|
||||||
],
|
|
||||||
space_before: [
|
|
||||||
Slice(start = 0, length = 2),
|
|
||||||
],
|
|
||||||
space_after: [
|
|
||||||
Slice(start = 2, length = 1),
|
|
||||||
],
|
|
||||||
spaces: [
|
|
||||||
Newline,
|
|
||||||
Newline,
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
type_defs: [],
|
|
||||||
value_defs: [
|
|
||||||
Body(
|
|
||||||
@39-43 Identifier {
|
|
||||||
ident: "main",
|
|
||||||
},
|
|
||||||
@46-65 Apply(
|
|
||||||
@46-57 Var {
|
|
||||||
module_name: "Stdout",
|
|
||||||
ident: "line",
|
|
||||||
},
|
|
||||||
[
|
|
||||||
@58-65 Str(
|
|
||||||
PlainLine(
|
|
||||||
"Hello",
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
Space,
|
before_packages: [],
|
||||||
),
|
packages: @13-37 [
|
||||||
|
@15-35 PackageEntry {
|
||||||
|
shorthand: "pf",
|
||||||
|
spaces_after_shorthand: [],
|
||||||
|
platform_marker: Some(
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
package_name: @29-35 PackageName(
|
||||||
|
"path",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
old_imports: None,
|
||||||
|
old_provides_to_new_package: None,
|
||||||
|
},
|
||||||
),
|
),
|
||||||
],
|
},
|
||||||
|
defs: Defs {
|
||||||
|
tags: [
|
||||||
|
Index(2147483648),
|
||||||
|
],
|
||||||
|
regions: [
|
||||||
|
@39-65,
|
||||||
|
],
|
||||||
|
space_before: [
|
||||||
|
Slice(start = 0, length = 2),
|
||||||
|
],
|
||||||
|
space_after: [
|
||||||
|
Slice(start = 2, length = 1),
|
||||||
|
],
|
||||||
|
spaces: [
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
type_defs: [],
|
||||||
|
value_defs: [
|
||||||
|
Body(
|
||||||
|
@39-43 Identifier {
|
||||||
|
ident: "main",
|
||||||
|
},
|
||||||
|
@46-65 Apply(
|
||||||
|
@46-57 Var {
|
||||||
|
module_name: "Stdout",
|
||||||
|
ident: "line",
|
||||||
|
},
|
||||||
|
[
|
||||||
|
@58-65 Str(
|
||||||
|
PlainLine(
|
||||||
|
"Hello",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
Space,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,209 +1,211 @@
|
||||||
Full {
|
Full(
|
||||||
header: Module {
|
FullAst {
|
||||||
comments: [],
|
header: SpacesBefore {
|
||||||
header: App(
|
before: [],
|
||||||
AppHeader {
|
item: App(
|
||||||
before_provides: [],
|
AppHeader {
|
||||||
provides: [
|
before_provides: [],
|
||||||
@5-9 ExposedName(
|
provides: [
|
||||||
"main",
|
@5-9 ExposedName(
|
||||||
),
|
"main",
|
||||||
],
|
|
||||||
before_packages: [],
|
|
||||||
packages: @11-55 Collection {
|
|
||||||
items: [
|
|
||||||
@15-52 SpaceBefore(
|
|
||||||
PackageEntry {
|
|
||||||
shorthand: "cli",
|
|
||||||
spaces_after_shorthand: [],
|
|
||||||
platform_marker: None,
|
|
||||||
package_name: @20-52 PackageName(
|
|
||||||
"../basic-cli/platform/main.roc",
|
|
||||||
),
|
|
||||||
},
|
|
||||||
[
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
final_comments: [
|
before_packages: [],
|
||||||
Newline,
|
packages: @11-55 Collection {
|
||||||
],
|
items: [
|
||||||
},
|
@15-52 SpaceBefore(
|
||||||
old_imports: None,
|
PackageEntry {
|
||||||
old_provides_to_new_package: None,
|
shorthand: "cli",
|
||||||
},
|
spaces_after_shorthand: [],
|
||||||
),
|
platform_marker: None,
|
||||||
},
|
package_name: @20-52 PackageName(
|
||||||
module_defs: Defs {
|
"../basic-cli/platform/main.roc",
|
||||||
tags: [
|
|
||||||
Index(2147483648),
|
|
||||||
Index(2147483649),
|
|
||||||
],
|
|
||||||
regions: [
|
|
||||||
@57-74,
|
|
||||||
@76-220,
|
|
||||||
],
|
|
||||||
space_before: [
|
|
||||||
Slice(start = 0, length = 2),
|
|
||||||
Slice(start = 2, length = 2),
|
|
||||||
],
|
|
||||||
space_after: [
|
|
||||||
Slice(start = 2, length = 0),
|
|
||||||
Slice(start = 4, length = 2),
|
|
||||||
],
|
|
||||||
spaces: [
|
|
||||||
Newline,
|
|
||||||
Newline,
|
|
||||||
Newline,
|
|
||||||
Newline,
|
|
||||||
Newline,
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
type_defs: [],
|
|
||||||
value_defs: [
|
|
||||||
ModuleImport(
|
|
||||||
ModuleImport {
|
|
||||||
before_name: [],
|
|
||||||
name: @64-74 ImportedModuleName {
|
|
||||||
package: Some(
|
|
||||||
"cli",
|
|
||||||
),
|
|
||||||
name: ModuleName(
|
|
||||||
"Stdout",
|
|
||||||
),
|
|
||||||
},
|
|
||||||
params: None,
|
|
||||||
alias: None,
|
|
||||||
exposed: None,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Body(
|
|
||||||
@76-80 Identifier {
|
|
||||||
ident: "main",
|
|
||||||
},
|
|
||||||
@120-220 SpaceBefore(
|
|
||||||
Defs(
|
|
||||||
Defs {
|
|
||||||
tags: [
|
|
||||||
Index(2147483648),
|
|
||||||
Index(2147483649),
|
|
||||||
],
|
|
||||||
regions: [
|
|
||||||
@120-133,
|
|
||||||
@162-205,
|
|
||||||
],
|
|
||||||
space_before: [
|
|
||||||
Slice(start = 0, length = 0),
|
|
||||||
Slice(start = 0, length = 3),
|
|
||||||
],
|
|
||||||
space_after: [
|
|
||||||
Slice(start = 0, length = 0),
|
|
||||||
Slice(start = 3, length = 0),
|
|
||||||
],
|
|
||||||
spaces: [
|
|
||||||
Newline,
|
|
||||||
Newline,
|
|
||||||
LineComment(
|
|
||||||
" what about this?",
|
|
||||||
),
|
|
||||||
],
|
|
||||||
type_defs: [],
|
|
||||||
value_defs: [
|
|
||||||
Stmt(
|
|
||||||
@120-133 BinOps(
|
|
||||||
[
|
|
||||||
(
|
|
||||||
@120-125 Str(
|
|
||||||
PlainLine(
|
|
||||||
"Foo",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
@126-128 Pizza,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
@129-132 TaskAwaitBang(
|
|
||||||
Var {
|
|
||||||
module_name: "A",
|
|
||||||
ident: "x",
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
|
||||||
Stmt(
|
|
||||||
@162-205 BinOps(
|
|
||||||
[
|
|
||||||
(
|
|
||||||
@162-167 Str(
|
|
||||||
PlainLine(
|
|
||||||
"Bar",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
@168-170 Pizza,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
@171-205 Apply(
|
|
||||||
@171-174 TaskAwaitBang(
|
|
||||||
Var {
|
|
||||||
module_name: "B",
|
|
||||||
ident: "y",
|
|
||||||
},
|
|
||||||
),
|
|
||||||
[
|
|
||||||
@185-205 SpaceBefore(
|
|
||||||
Record(
|
|
||||||
[
|
|
||||||
@187-203 RequiredValue(
|
|
||||||
@187-193 "config",
|
|
||||||
[],
|
|
||||||
@195-203 Str(
|
|
||||||
PlainLine(
|
|
||||||
"config",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
[
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
Space,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
@211-220 SpaceBefore(
|
|
||||||
Apply(
|
|
||||||
@211-214 Var {
|
|
||||||
module_name: "C",
|
|
||||||
ident: "z",
|
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
@215-220 Str(
|
Newline,
|
||||||
PlainLine(
|
],
|
||||||
"Bar",
|
),
|
||||||
|
],
|
||||||
|
final_comments: [
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
old_imports: None,
|
||||||
|
old_provides_to_new_package: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
defs: Defs {
|
||||||
|
tags: [
|
||||||
|
Index(2147483648),
|
||||||
|
Index(2147483649),
|
||||||
|
],
|
||||||
|
regions: [
|
||||||
|
@57-74,
|
||||||
|
@76-220,
|
||||||
|
],
|
||||||
|
space_before: [
|
||||||
|
Slice(start = 0, length = 2),
|
||||||
|
Slice(start = 2, length = 2),
|
||||||
|
],
|
||||||
|
space_after: [
|
||||||
|
Slice(start = 2, length = 0),
|
||||||
|
Slice(start = 4, length = 2),
|
||||||
|
],
|
||||||
|
spaces: [
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
type_defs: [],
|
||||||
|
value_defs: [
|
||||||
|
ModuleImport(
|
||||||
|
ModuleImport {
|
||||||
|
before_name: [],
|
||||||
|
name: @64-74 ImportedModuleName {
|
||||||
|
package: Some(
|
||||||
|
"cli",
|
||||||
|
),
|
||||||
|
name: ModuleName(
|
||||||
|
"Stdout",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
params: None,
|
||||||
|
alias: None,
|
||||||
|
exposed: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Body(
|
||||||
|
@76-80 Identifier {
|
||||||
|
ident: "main",
|
||||||
|
},
|
||||||
|
@120-220 SpaceBefore(
|
||||||
|
Defs(
|
||||||
|
Defs {
|
||||||
|
tags: [
|
||||||
|
Index(2147483648),
|
||||||
|
Index(2147483649),
|
||||||
|
],
|
||||||
|
regions: [
|
||||||
|
@120-133,
|
||||||
|
@162-205,
|
||||||
|
],
|
||||||
|
space_before: [
|
||||||
|
Slice(start = 0, length = 0),
|
||||||
|
Slice(start = 0, length = 3),
|
||||||
|
],
|
||||||
|
space_after: [
|
||||||
|
Slice(start = 0, length = 0),
|
||||||
|
Slice(start = 3, length = 0),
|
||||||
|
],
|
||||||
|
spaces: [
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
LineComment(
|
||||||
|
" what about this?",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
type_defs: [],
|
||||||
|
value_defs: [
|
||||||
|
Stmt(
|
||||||
|
@120-133 BinOps(
|
||||||
|
[
|
||||||
|
(
|
||||||
|
@120-125 Str(
|
||||||
|
PlainLine(
|
||||||
|
"Foo",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
@126-128 Pizza,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
@129-132 TaskAwaitBang(
|
||||||
|
Var {
|
||||||
|
module_name: "A",
|
||||||
|
ident: "x",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Stmt(
|
||||||
|
@162-205 BinOps(
|
||||||
|
[
|
||||||
|
(
|
||||||
|
@162-167 Str(
|
||||||
|
PlainLine(
|
||||||
|
"Bar",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
@168-170 Pizza,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
@171-205 Apply(
|
||||||
|
@171-174 TaskAwaitBang(
|
||||||
|
Var {
|
||||||
|
module_name: "B",
|
||||||
|
ident: "y",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
[
|
||||||
|
@185-205 SpaceBefore(
|
||||||
|
Record(
|
||||||
|
[
|
||||||
|
@187-203 RequiredValue(
|
||||||
|
@187-193 "config",
|
||||||
|
[],
|
||||||
|
@195-203 Str(
|
||||||
|
PlainLine(
|
||||||
|
"config",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
Space,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
Space,
|
},
|
||||||
|
@211-220 SpaceBefore(
|
||||||
|
Apply(
|
||||||
|
@211-214 Var {
|
||||||
|
module_name: "C",
|
||||||
|
ident: "z",
|
||||||
|
},
|
||||||
|
[
|
||||||
|
@215-220 Str(
|
||||||
|
PlainLine(
|
||||||
|
"Bar",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
Space,
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
),
|
),
|
||||||
[
|
|
||||||
Newline,
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
LineComment(
|
||||||
|
" is this a valid statement?",
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
[
|
|
||||||
Newline,
|
|
||||||
LineComment(
|
|
||||||
" is this a valid statement?",
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
},
|
||||||
},
|
},
|
||||||
}
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,131 +1,133 @@
|
||||||
Full {
|
Full(
|
||||||
header: Module {
|
FullAst {
|
||||||
comments: [],
|
header: SpacesBefore {
|
||||||
header: App(
|
before: [],
|
||||||
AppHeader {
|
item: App(
|
||||||
before_provides: [
|
AppHeader {
|
||||||
Newline,
|
before_provides: [
|
||||||
],
|
|
||||||
provides: [
|
|
||||||
@74-78 ExposedName(
|
|
||||||
"main",
|
|
||||||
),
|
|
||||||
],
|
|
||||||
before_packages: [
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
packages: @6-44 Collection {
|
|
||||||
items: [
|
|
||||||
@30-37 SpaceBefore(
|
|
||||||
PackageEntry {
|
|
||||||
shorthand: "cli",
|
|
||||||
spaces_after_shorthand: [],
|
|
||||||
platform_marker: Some(
|
|
||||||
[],
|
|
||||||
),
|
|
||||||
package_name: @35-37 PackageName(
|
|
||||||
"",
|
|
||||||
),
|
|
||||||
},
|
|
||||||
[
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
final_comments: [
|
|
||||||
Newline,
|
Newline,
|
||||||
],
|
],
|
||||||
},
|
provides: [
|
||||||
old_imports: None,
|
@74-78 ExposedName(
|
||||||
old_provides_to_new_package: None,
|
"main",
|
||||||
},
|
),
|
||||||
),
|
],
|
||||||
},
|
before_packages: [
|
||||||
module_defs: Defs {
|
Newline,
|
||||||
tags: [
|
],
|
||||||
Index(2147483648),
|
packages: @6-44 Collection {
|
||||||
],
|
items: [
|
||||||
regions: [
|
@30-37 SpaceBefore(
|
||||||
@88-202,
|
PackageEntry {
|
||||||
],
|
shorthand: "cli",
|
||||||
space_before: [
|
spaces_after_shorthand: [],
|
||||||
Slice(start = 0, length = 2),
|
platform_marker: Some(
|
||||||
],
|
[],
|
||||||
space_after: [
|
|
||||||
Slice(start = 2, length = 1),
|
|
||||||
],
|
|
||||||
spaces: [
|
|
||||||
Newline,
|
|
||||||
Newline,
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
type_defs: [],
|
|
||||||
value_defs: [
|
|
||||||
Body(
|
|
||||||
@88-92 Identifier {
|
|
||||||
ident: "main",
|
|
||||||
},
|
|
||||||
@100-202 SpaceBefore(
|
|
||||||
BinOps(
|
|
||||||
[
|
|
||||||
(
|
|
||||||
@100-114 SpaceAfter(
|
|
||||||
Str(
|
|
||||||
PlainLine(
|
|
||||||
"jq --version",
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
[
|
package_name: @35-37 PackageName(
|
||||||
Newline,
|
"",
|
||||||
],
|
),
|
||||||
),
|
},
|
||||||
@123-125 Pizza,
|
[
|
||||||
),
|
Newline,
|
||||||
(
|
],
|
||||||
@126-133 SpaceAfter(
|
|
||||||
Var {
|
|
||||||
module_name: "Cmd",
|
|
||||||
ident: "new",
|
|
||||||
},
|
|
||||||
[
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
@142-144 Pizza,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
@145-155 SpaceAfter(
|
|
||||||
Var {
|
|
||||||
module_name: "Cmd",
|
|
||||||
ident: "status",
|
|
||||||
},
|
|
||||||
[
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
@164-166 Pizza,
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@167-202 Apply(
|
final_comments: [
|
||||||
@167-178 TaskAwaitBang(
|
Newline,
|
||||||
Var {
|
],
|
||||||
module_name: "Task",
|
},
|
||||||
ident: "mapErr",
|
old_imports: None,
|
||||||
},
|
old_provides_to_new_package: None,
|
||||||
),
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
defs: Defs {
|
||||||
|
tags: [
|
||||||
|
Index(2147483648),
|
||||||
|
],
|
||||||
|
regions: [
|
||||||
|
@88-202,
|
||||||
|
],
|
||||||
|
space_before: [
|
||||||
|
Slice(start = 0, length = 2),
|
||||||
|
],
|
||||||
|
space_after: [
|
||||||
|
Slice(start = 2, length = 1),
|
||||||
|
],
|
||||||
|
spaces: [
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
type_defs: [],
|
||||||
|
value_defs: [
|
||||||
|
Body(
|
||||||
|
@88-92 Identifier {
|
||||||
|
ident: "main",
|
||||||
|
},
|
||||||
|
@100-202 SpaceBefore(
|
||||||
|
BinOps(
|
||||||
[
|
[
|
||||||
@180-202 Tag(
|
(
|
||||||
"UnableToCheckJQVersion",
|
@100-114 SpaceAfter(
|
||||||
|
Str(
|
||||||
|
PlainLine(
|
||||||
|
"jq --version",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@123-125 Pizza,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
@126-133 SpaceAfter(
|
||||||
|
Var {
|
||||||
|
module_name: "Cmd",
|
||||||
|
ident: "new",
|
||||||
|
},
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@142-144 Pizza,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
@145-155 SpaceAfter(
|
||||||
|
Var {
|
||||||
|
module_name: "Cmd",
|
||||||
|
ident: "status",
|
||||||
|
},
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@164-166 Pizza,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
Space,
|
@167-202 Apply(
|
||||||
|
@167-178 TaskAwaitBang(
|
||||||
|
Var {
|
||||||
|
module_name: "Task",
|
||||||
|
ident: "mapErr",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
[
|
||||||
|
@180-202 Tag(
|
||||||
|
"UnableToCheckJQVersion",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
Space,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
),
|
),
|
||||||
[
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
},
|
||||||
},
|
},
|
||||||
}
|
)
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@ extern crate indoc;
|
||||||
mod test_fmt {
|
mod test_fmt {
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_fmt::def::fmt_defs;
|
use roc_fmt::def::fmt_defs;
|
||||||
use roc_fmt::module::fmt_module;
|
use roc_fmt::header::fmt_header;
|
||||||
use roc_fmt::Buf;
|
use roc_fmt::Buf;
|
||||||
use roc_parse::ast::{Defs, Module};
|
use roc_parse::ast::{Defs, Header, SpacesBefore};
|
||||||
use roc_parse::module::{self, parse_module_defs};
|
use roc_parse::header::{self, parse_module_defs};
|
||||||
use roc_parse::state::State;
|
use roc_parse::state::State;
|
||||||
use roc_test_utils::assert_multiline_str_eq;
|
use roc_test_utils::assert_multiline_str_eq;
|
||||||
use roc_test_utils_dir::workspace_root;
|
use roc_test_utils_dir::workspace_root;
|
||||||
|
|
@ -32,11 +32,11 @@ mod test_fmt {
|
||||||
fn fmt_module_and_defs<'a>(
|
fn fmt_module_and_defs<'a>(
|
||||||
arena: &Bump,
|
arena: &Bump,
|
||||||
src: &str,
|
src: &str,
|
||||||
module: &Module<'a>,
|
header: &SpacesBefore<'a, Header<'a>>,
|
||||||
state: State<'a>,
|
state: State<'a>,
|
||||||
buf: &mut Buf<'_>,
|
buf: &mut Buf<'_>,
|
||||||
) {
|
) {
|
||||||
fmt_module(buf, module);
|
fmt_header(buf, header);
|
||||||
|
|
||||||
match parse_module_defs(arena, state, Defs::default()) {
|
match parse_module_defs(arena, state, Defs::default()) {
|
||||||
Ok(loc_defs) => {
|
Ok(loc_defs) => {
|
||||||
|
|
@ -61,7 +61,7 @@ mod test_fmt {
|
||||||
let src = src.trim();
|
let src = src.trim();
|
||||||
let expected = expected.trim();
|
let expected = expected.trim();
|
||||||
|
|
||||||
match module::parse_header(&arena, State::new(src.as_bytes())) {
|
match header::parse_header(&arena, State::new(src.as_bytes())) {
|
||||||
Ok((actual, state)) => {
|
Ok((actual, state)) => {
|
||||||
use roc_parse::remove_spaces::RemoveSpaces;
|
use roc_parse::remove_spaces::RemoveSpaces;
|
||||||
|
|
||||||
|
|
@ -71,7 +71,7 @@ mod test_fmt {
|
||||||
|
|
||||||
let output = buf.as_str().trim();
|
let output = buf.as_str().trim();
|
||||||
|
|
||||||
let (reparsed_ast, state) = module::parse_header(&arena, State::new(output.as_bytes())).unwrap_or_else(|err| {
|
let (reparsed_ast, state) = header::parse_header(&arena, State::new(output.as_bytes())).unwrap_or_else(|err| {
|
||||||
panic!(
|
panic!(
|
||||||
"After formatting, the source code no longer parsed!\n\nParse error was: {err:?}\n\nThe code that failed to parse:\n\n{output}\n\n"
|
"After formatting, the source code no longer parsed!\n\nParse error was: {err:?}\n\nThe code that failed to parse:\n\n{output}\n\n"
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -449,6 +449,8 @@ mod test_snapshots {
|
||||||
pass/qualified_field.expr,
|
pass/qualified_field.expr,
|
||||||
pass/qualified_var.expr,
|
pass/qualified_var.expr,
|
||||||
pass/record_access_after_tuple.expr,
|
pass/record_access_after_tuple.expr,
|
||||||
|
pass/record_builder.expr,
|
||||||
|
pass/record_builder_ignored_fields.expr,
|
||||||
pass/record_destructure_def.expr,
|
pass/record_destructure_def.expr,
|
||||||
pass/record_func_type_decl.expr,
|
pass/record_func_type_decl.expr,
|
||||||
pass/record_type_with_function.expr,
|
pass/record_type_with_function.expr,
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_fmt::Buf;
|
use roc_fmt::Buf;
|
||||||
use roc_parse::{
|
use roc_parse::{
|
||||||
ast::{Defs, Module},
|
ast::{Defs, Header, SpacesBefore},
|
||||||
module::parse_module_defs,
|
header::parse_module_defs,
|
||||||
parser::SyntaxError,
|
parser::SyntaxError,
|
||||||
};
|
};
|
||||||
use roc_region::all::Loc;
|
use roc_region::all::Loc;
|
||||||
|
|
@ -15,23 +15,26 @@ mod format;
|
||||||
|
|
||||||
pub struct Ast<'a> {
|
pub struct Ast<'a> {
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
module: Module<'a>,
|
module: SpacesBefore<'a, Header<'a>>,
|
||||||
defs: Defs<'a>,
|
defs: Defs<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Ast<'a> {
|
impl<'a> Ast<'a> {
|
||||||
pub fn parse(arena: &'a Bump, src: &'a str) -> Result<Ast<'a>, SyntaxError<'a>> {
|
pub fn parse(arena: &'a Bump, src: &'a str) -> Result<Ast<'a>, SyntaxError<'a>> {
|
||||||
use roc_parse::{module::parse_header, state::State};
|
use roc_parse::{header::parse_header, state::State};
|
||||||
|
|
||||||
let (module, state) = parse_header(arena, State::new(src.as_bytes()))
|
let (module, state) = parse_header(arena, State::new(src.as_bytes()))
|
||||||
.map_err(|e| SyntaxError::Header(e.problem))?;
|
.map_err(|e| SyntaxError::Header(e.problem))?;
|
||||||
|
|
||||||
let (module, defs) = module.upgrade_header_imports(arena);
|
let (header, defs) = module.item.upgrade_header_imports(arena);
|
||||||
|
|
||||||
let defs = parse_module_defs(arena, state, defs)?;
|
let defs = parse_module_defs(arena, state, defs)?;
|
||||||
|
|
||||||
Ok(Ast {
|
Ok(Ast {
|
||||||
module,
|
module: SpacesBefore {
|
||||||
|
before: module.before,
|
||||||
|
item: header,
|
||||||
|
},
|
||||||
defs,
|
defs,
|
||||||
arena,
|
arena,
|
||||||
})
|
})
|
||||||
|
|
@ -40,7 +43,7 @@ impl<'a> Ast<'a> {
|
||||||
pub fn fmt(&self) -> FormattedAst<'a> {
|
pub fn fmt(&self) -> FormattedAst<'a> {
|
||||||
let mut buf = Buf::new_in(self.arena);
|
let mut buf = Buf::new_in(self.arena);
|
||||||
|
|
||||||
roc_fmt::module::fmt_module(&mut buf, &self.module);
|
roc_fmt::header::fmt_header(&mut buf, &self.module);
|
||||||
|
|
||||||
roc_fmt::def::fmt_defs(&mut buf, &self.defs, 0);
|
roc_fmt::def::fmt_defs(&mut buf, &self.defs, 0);
|
||||||
|
|
||||||
|
|
@ -50,7 +53,7 @@ impl<'a> Ast<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn semantic_tokens(&self) -> impl IntoIterator<Item = Loc<Token>> + '_ {
|
pub fn semantic_tokens(&self) -> impl IntoIterator<Item = Loc<Token>> + '_ {
|
||||||
let header_tokens = self.module.iter_tokens(self.arena);
|
let header_tokens = self.module.item.iter_tokens(self.arena);
|
||||||
let body_tokens = self.defs.iter_tokens(self.arena);
|
let body_tokens = self.defs.iter_tokens(self.arena);
|
||||||
|
|
||||||
header_tokens.into_iter().chain(body_tokens)
|
header_tokens.into_iter().chain(body_tokens)
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ use roc_module::called_via::{BinOp, UnaryOp};
|
||||||
use roc_parse::{
|
use roc_parse::{
|
||||||
ast::{
|
ast::{
|
||||||
AbilityImpls, AbilityMember, AssignedField, Collection, Defs, Expr, Header, Implements,
|
AbilityImpls, AbilityMember, AssignedField, Collection, Defs, Expr, Header, Implements,
|
||||||
ImplementsAbilities, ImplementsAbility, ImplementsClause, Module, OldRecordBuilderField,
|
ImplementsAbilities, ImplementsAbility, ImplementsClause, OldRecordBuilderField, Pattern,
|
||||||
Pattern, PatternAs, Spaced, StrLiteral, Tag, TypeAnnotation, TypeDef, TypeHeader, ValueDef,
|
PatternAs, Spaced, StrLiteral, Tag, TypeAnnotation, TypeDef, TypeHeader, ValueDef,
|
||||||
WhenBranch,
|
WhenBranch,
|
||||||
},
|
},
|
||||||
header::{
|
header::{
|
||||||
|
|
@ -189,16 +189,6 @@ impl<T: IterTokens, U: IterTokens> IterTokens for (T, U) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IterTokens for Module<'_> {
|
|
||||||
fn iter_tokens<'a>(&self, arena: &'a Bump) -> BumpVec<'a, Loc<Token>> {
|
|
||||||
let Self {
|
|
||||||
comments: _,
|
|
||||||
header,
|
|
||||||
} = self;
|
|
||||||
header.iter_tokens(arena)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IterTokens for Header<'_> {
|
impl IterTokens for Header<'_> {
|
||||||
fn iter_tokens<'a>(&self, arena: &'a Bump) -> BumpVec<'a, Loc<Token>> {
|
fn iter_tokens<'a>(&self, arena: &'a Bump) -> BumpVec<'a, Loc<Token>> {
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -443,7 +433,8 @@ where
|
||||||
fn iter_tokens<'a>(&self, arena: &'a Bump) -> BumpVec<'a, Loc<Token>> {
|
fn iter_tokens<'a>(&self, arena: &'a Bump) -> BumpVec<'a, Loc<Token>> {
|
||||||
match self {
|
match self {
|
||||||
AssignedField::RequiredValue(field, _, ty)
|
AssignedField::RequiredValue(field, _, ty)
|
||||||
| AssignedField::OptionalValue(field, _, ty) => (field_token(field.region, arena)
|
| AssignedField::OptionalValue(field, _, ty)
|
||||||
|
| AssignedField::IgnoredValue(field, _, ty) => (field_token(field.region, arena)
|
||||||
.into_iter())
|
.into_iter())
|
||||||
.chain(ty.iter_tokens(arena))
|
.chain(ty.iter_tokens(arena))
|
||||||
.collect_in(arena),
|
.collect_in(arena),
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@ use brotli::enc::BrotliEncoderParams;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use flate2::write::GzEncoder;
|
use flate2::write::GzEncoder;
|
||||||
use roc_parse::ast::{
|
use roc_parse::ast::{
|
||||||
Header, IngestedFileImport, Module, RecursiveValueDefIter, StrLiteral, ValueDef,
|
Header, IngestedFileImport, RecursiveValueDefIter, SpacesBefore, StrLiteral, ValueDef,
|
||||||
};
|
};
|
||||||
use roc_parse::header::PlatformHeader;
|
use roc_parse::header::PlatformHeader;
|
||||||
use roc_parse::module::{parse_header, parse_module_defs};
|
use roc_parse::header::{parse_header, parse_module_defs};
|
||||||
use roc_parse::state::State;
|
use roc_parse::state::State;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
|
@ -129,7 +129,7 @@ fn write_archive<W: Write>(path: &Path, writer: W) -> io::Result<()> {
|
||||||
|
|
||||||
// TODO use this when finding .roc files by discovering them from the root module.
|
// TODO use this when finding .roc files by discovering them from the root module.
|
||||||
// let other_modules: &[Module<'_>] =
|
// let other_modules: &[Module<'_>] =
|
||||||
match read_header(&arena, &mut buf, path)?.0.header {
|
match read_header(&arena, &mut buf, path)?.0.item {
|
||||||
Header::Module(_) => {
|
Header::Module(_) => {
|
||||||
todo!();
|
todo!();
|
||||||
// TODO report error
|
// TODO report error
|
||||||
|
|
@ -261,7 +261,7 @@ fn read_header<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
buf: &'a mut Vec<u8>,
|
buf: &'a mut Vec<u8>,
|
||||||
path: &'a Path,
|
path: &'a Path,
|
||||||
) -> io::Result<(Module<'a>, State<'a>)> {
|
) -> io::Result<(SpacesBefore<'a, Header<'a>>, State<'a>)> {
|
||||||
// Read all the bytes into the buffer.
|
// Read all the bytes into the buffer.
|
||||||
{
|
{
|
||||||
let mut file = File::open(path)?;
|
let mut file = File::open(path)?;
|
||||||
|
|
@ -287,8 +287,8 @@ fn add_ingested_files<W: Write>(
|
||||||
builder: &mut tar::Builder<W>,
|
builder: &mut tar::Builder<W>,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
let (module, state) = read_header(arena, &mut buf, dot_roc_path)?;
|
let (header, state) = read_header(arena, &mut buf, dot_roc_path)?;
|
||||||
let (_, defs) = module.upgrade_header_imports(arena);
|
let (_, defs) = header.item.upgrade_header_imports(arena);
|
||||||
|
|
||||||
let defs = parse_module_defs(arena, state, defs).unwrap_or_else(|err| {
|
let defs = parse_module_defs(arena, state, defs).unwrap_or_else(|err| {
|
||||||
panic!("{} failed to parse: {:?}", dot_roc_path.display(), err);
|
panic!("{} failed to parse: {:?}", dot_roc_path.display(), err);
|
||||||
|
|
|
||||||
|
|
@ -545,7 +545,7 @@ fn to_expr_report<'a>(
|
||||||
to_record_report(alloc, lines, filename, erecord, *pos, start)
|
to_record_report(alloc, lines, filename, erecord, *pos, start)
|
||||||
}
|
}
|
||||||
|
|
||||||
EExpr::OptionalValueInRecordBuilder(region) => {
|
EExpr::OptionalValueInOldRecordBuilder(region) => {
|
||||||
let surroundings = Region::new(start, region.end());
|
let surroundings = Region::new(start, region.end());
|
||||||
let region = lines.convert_region(*region);
|
let region = lines.convert_region(*region);
|
||||||
|
|
||||||
|
|
@ -565,7 +565,7 @@ fn to_expr_report<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EExpr::RecordUpdateAccumulator(region) => {
|
EExpr::RecordUpdateOldBuilderField(region) => {
|
||||||
let surroundings = Region::new(start, region.end());
|
let surroundings = Region::new(start, region.end());
|
||||||
let region = lines.convert_region(*region);
|
let region = lines.convert_region(*region);
|
||||||
|
|
||||||
|
|
@ -1580,6 +1580,25 @@ fn to_import_report<'a>(
|
||||||
severity,
|
severity,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Params(EImportParams::RecordIgnoredFieldFound(region), _) => {
|
||||||
|
let surroundings = Region::new(start, region.end());
|
||||||
|
let region = lines.convert_region(*region);
|
||||||
|
|
||||||
|
let doc = alloc.stack([
|
||||||
|
alloc.reflow("I was partway through parsing module params, but I got stuck here:"),
|
||||||
|
alloc.region_with_subregion(lines.convert_region(surroundings), region, severity),
|
||||||
|
alloc.reflow(
|
||||||
|
"This is an ignored record field, but those are not allowed in module params.",
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename,
|
||||||
|
doc,
|
||||||
|
title: "IGNORED RECORD FIELD IN MODULE PARAMS".to_string(),
|
||||||
|
severity,
|
||||||
|
}
|
||||||
|
}
|
||||||
Params(EImportParams::RecordUpdateFound(region), _) => {
|
Params(EImportParams::RecordUpdateFound(region), _) => {
|
||||||
let surroundings = Region::new(start, region.end());
|
let surroundings = Region::new(start, region.end());
|
||||||
let region = lines.convert_region(*region);
|
let region = lines.convert_region(*region);
|
||||||
|
|
|
||||||
17
devtools/debug_tips.md
Normal file
17
devtools/debug_tips.md
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Debug Tips
|
||||||
|
|
||||||
|
## General
|
||||||
|
|
||||||
|
- When using github search to find similar errors/issues use `org:roc-lang`, for example: `org:roc-lang valgrind unrecognised instruction`. This will search in basic-cli, basic-webserver, ... as well. Just using `roc` instead of `org:roc-lang` may yield useful results as well.
|
||||||
|
- Use a debug build of the compiler. We have many asserts enabled in the debug compiler that can alert you to something going wrong. When building from source, build the debug compiler with `cargo build --bin roc`, the binary is at `roc/target/debug/roc`. When using roc through a nix flake like in [basic-cli](https://github.com/roc-lang/basic-cli), use `rocPkgs.cli-debug` instead of `rocPkgs.cli`.
|
||||||
|
- At the bottom of [.cargo/config.toml](https://github.com/roc-lang/roc/blob/main/.cargo/config.toml) we have useful debug flags that activate certain debug prints and extra checks.
|
||||||
|
- For Roc code; minimize the code that produces the issue.
|
||||||
|
- If you plan to look at the data used and produced inside the compiler, try to reproduce your issue with a very simple platform like our [minimal Rust platform](https://github.com/roc-lang/roc/tree/main/examples/platform-switching/rust-platform) instead of for example basic-cli.
|
||||||
|
|
||||||
|
## Segmentation Faults
|
||||||
|
|
||||||
|
- In general we recommend using linux to investigate, it has better tools for this.
|
||||||
|
- If your segfault also happens when using `--linker=legacy`, use it to improve valgrind output. For example: `roc build myApp.roc --linker=legacy` followed by `valgrind ./myApp`.
|
||||||
|
- Use gdb to step through the code, [this gdb script](https://roc.zulipchat.com/#narrow/stream/395097-compiler-development/topic/gdb.20script/near/424422545) can be helpful.
|
||||||
|
- Use objdump to look at the assembly of the code, for example `objdump -d -M intel ./examples/Arithmetic/main`. Replace `-M intel` with the appropriate flag for your CPU.
|
||||||
|
- Inspect the generated LLVM IR (`roc build myApp.roc --emit-llvm-ir`) between Roc code that encounters the segfault and code that doesn't.
|
||||||
|
|
@ -931,6 +931,8 @@ foo 1 2 if something then 3 else 4
|
||||||
|
|
||||||
## Backpassing
|
## Backpassing
|
||||||
|
|
||||||
|
Note: the backpassing syntax will likely be removed from the language. The [`!` suffix](https://www.roc-lang.org/tutorial#the-!-suffix) can instead be used for `Task.await` and the `?` suffix is [planned](https://github.com/roc-lang/roc/issues/6828) for use with `Result.try`.
|
||||||
|
|
||||||
Suppose I'm using a platform for making a CLI, and I want to run several
|
Suppose I'm using a platform for making a CLI, and I want to run several
|
||||||
`Task`s in a row which read some files from the disk. Here's one way I could do
|
`Task`s in a row which read some files from the disk. Here's one way I could do
|
||||||
that, assuming `Task.await` is like Elm's `Task.andThen` with arguments flipped:
|
that, assuming `Task.await` is like Elm's `Task.andThen` with arguments flipped:
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ Here's a code sample that shows a few different aspects of Roc:
|
||||||
- File I/O and HTTP requests
|
- File I/O and HTTP requests
|
||||||
- Pattern matching for error handling
|
- Pattern matching for error handling
|
||||||
- JSON deserialization via type inference
|
- JSON deserialization via type inference
|
||||||
- Common syntax sugar: string interpolation, pipelines, and backpassing
|
- Common syntax sugar: pipelines, the `!` operator, and string interpolation
|
||||||
|
|
||||||
The [tutorial](/tutorial) introduces these gradually and in more depth, but this gives a brief overview.
|
The [tutorial](/tutorial) introduces these gradually and in more depth, but this gives a brief overview.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,14 +16,6 @@ As an example, we had [a discussion](https://roc.zulipchat.com/#narrow/stream/30
|
||||||
|
|
||||||
This has been consistently happening a few times per year. It's hard to predict exactly what the next one will be, but it's a safe bet that it will happen again.
|
This has been consistently happening a few times per year. It's hard to predict exactly what the next one will be, but it's a safe bet that it will happen again.
|
||||||
|
|
||||||
### [Glue](#glue) {#glue}
|
|
||||||
|
|
||||||
This one only applies to platform authors.
|
|
||||||
|
|
||||||
Much like with builtins, we periodically make changes to code generation or to the `roc glue` API that aren't backwards compatible. When this happens, relevant glue scripts need to be updated and then `roc glue` needs to be re-run on platforms to regenerate their host glue.
|
|
||||||
|
|
||||||
As with builtins, it's hard to predict when these will happen and what they'll be, but right now it's a safe bet that they will happen from time to time.
|
|
||||||
|
|
||||||
### [Import syntax](#import-syntax) {#import-syntax}
|
### [Import syntax](#import-syntax) {#import-syntax}
|
||||||
|
|
||||||
Implementing the very important [module params](https://docs.google.com/document/d/110MwQi7Dpo1Y69ECFXyyvDWzF4OYv1BLojIm08qDTvg/edit?usp=sharing) feature requires a breaking syntax change to how imports work. This plan is not at all tentative; there is a high degree of confidence that it will happen!
|
Implementing the very important [module params](https://docs.google.com/document/d/110MwQi7Dpo1Y69ECFXyyvDWzF4OYv1BLojIm08qDTvg/edit?usp=sharing) feature requires a breaking syntax change to how imports work. This plan is not at all tentative; there is a high degree of confidence that it will happen!
|
||||||
|
|
|
||||||
|
|
@ -818,6 +818,30 @@ Result.isOk (List.get ["a", "b", "c"] 1)
|
||||||
# Note: There's a Result.isErr function that works similarly.
|
# Note: There's a Result.isErr function that works similarly.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```roc
|
||||||
|
# Running this will produce `Ok "c"`
|
||||||
|
Result.try (Str.toU64 "2") listGet
|
||||||
|
|
||||||
|
listGet : U64 -> Result Str [OutOfBounds]
|
||||||
|
listGet = \index ->
|
||||||
|
List.get ["a", "b", "c", "d"] index
|
||||||
|
|
||||||
|
# Notes:
|
||||||
|
# - `Str.toU64 "2"` parses the string "2" to the integer 2, and returns `Ok 2` (more on
|
||||||
|
# integer types later)
|
||||||
|
# - since parsing is successful, `Result.try` passes 2 to the `listGet` function
|
||||||
|
# - passing "abc" or "1000" instead of "2" would have resulted in `Err InvalidNumStr`
|
||||||
|
# or `Err OutOfBounds` respectively
|
||||||
|
```
|
||||||
|
|
||||||
|
`Result.try` is often used to chain two functions that return `Result` (as in the example above). This prevents you from needing to add error handling code at every intermediate step.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Upcoming feature</summary>
|
||||||
|
|
||||||
|
We plan to introduce syntax sugar to make `Result.try` nicer to use, follow [this issue](https://github.com/roc-lang/roc/issues/6828) for more.
|
||||||
|
</details>
|
||||||
|
|
||||||
### [Walking the elements in a list](#walking-the-elements-in-a-list) {#walking-the-elements-in-a-list}
|
### [Walking the elements in a list](#walking-the-elements-in-a-list) {#walking-the-elements-in-a-list}
|
||||||
|
|
||||||
We've now seen a few different ways you can transform lists. Sometimes, though, there's nothing
|
We've now seen a few different ways you can transform lists. Sometimes, though, there's nothing
|
||||||
|
|
@ -1587,7 +1611,7 @@ main =
|
||||||
Stdout.line! "Hello, World!"
|
Stdout.line! "Hello, World!"
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Stdout.line` function takes a `Str` and writes it to [standard output](<https://en.wikipedia.org/wiki/Standard_streams#Standard_output_(stdout)>). (We'll discuss the `!` part later.) `Stdout.line` has this type:
|
The `Stdout.line` function takes a `Str` and writes it to [standard output](<https://en.wikipedia.org/wiki/Standard_streams#Standard_output_(stdout)>), we'll [discuss the `!` part later](https://www.roc-lang.org/tutorial#the-!-suffix). `Stdout.line` has this type:
|
||||||
|
|
||||||
```roc
|
```roc
|
||||||
Stdout.line : Str -> Task {} *
|
Stdout.line : Str -> Task {} *
|
||||||
|
|
@ -2236,9 +2260,13 @@ See the [Record Builder Example](https://www.roc-lang.org/examples/RecordBuilder
|
||||||
|
|
||||||
### [Reserved Keywords](#reserved-keywords) {#reserved-keywords}
|
### [Reserved Keywords](#reserved-keywords) {#reserved-keywords}
|
||||||
|
|
||||||
These are all the reserved keywords in Roc. You can't choose any of these as names, except as record field names.
|
These are reserved keywords in Roc. You can't choose any of them as names, except as record field names.
|
||||||
|
|
||||||
`if`, `then`, `else`, `when`, `as`, `is`, `dbg`, `import`, `expect`, `expect-fx`, `crash`, `module`, `app`, `package`, `platform`, `hosted`, `exposes`, `with`, `generates`, `packages`, `requires`
|
`as`, `crash`, `dbg`, `else`, `expect`, `expect-fx`, `if`, `import`, `is`, `then`, `when`
|
||||||
|
|
||||||
|
Other keywords are used only in specific places, so they are not reserved. This includes:
|
||||||
|
|
||||||
|
`app`, `exposes`, `exposing`, `generates`, `implements`, `module`, `package`, `packages`, `platform`, `requires`, `where`, `with`
|
||||||
|
|
||||||
## [Operator Desugaring Table](#operator-desugaring-table) {#operator-desugaring-table}
|
## [Operator Desugaring Table](#operator-desugaring-table) {#operator-desugaring-table}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue