mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
Merge remote-tracking branch 'remote/main' into remove-json
This commit is contained in:
commit
092676c4b7
92 changed files with 2039 additions and 417 deletions
11
Cargo.lock
generated
11
Cargo.lock
generated
|
@ -358,6 +358,16 @@ version = "3.12.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b"
|
checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byte-unit"
|
||||||
|
version = "4.0.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da78b32057b8fdfc352504708feeba7216dcd65a2c9ab02978cbd288d1279b6c"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"utf8-width",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck"
|
name = "bytemuck"
|
||||||
version = "1.13.1"
|
version = "1.13.1"
|
||||||
|
@ -3850,6 +3860,7 @@ name = "roc_reporting"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
|
"byte-unit",
|
||||||
"distance",
|
"distance",
|
||||||
"indoc",
|
"indoc",
|
||||||
"insta",
|
"insta",
|
||||||
|
|
|
@ -121,16 +121,18 @@ impl<'a> Env<'a> {
|
||||||
|
|
||||||
Ok(symbol)
|
Ok(symbol)
|
||||||
}
|
}
|
||||||
None => Err(RuntimeError::LookupNotInScope(
|
None => Err(RuntimeError::LookupNotInScope {
|
||||||
Loc {
|
loc_name: Loc {
|
||||||
value: Ident::from(ident),
|
value: Ident::from(ident),
|
||||||
region,
|
region,
|
||||||
},
|
},
|
||||||
self.ident_ids
|
suggestion_options: self
|
||||||
|
.ident_ids
|
||||||
.ident_strs()
|
.ident_strs()
|
||||||
.map(|(_, string)| string.into())
|
.map(|(_, string)| string.into())
|
||||||
.collect(),
|
.collect(),
|
||||||
)),
|
underscored_suggestion_region: None,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match self.dep_idents.get(&module_id) {
|
match self.dep_idents.get(&module_id) {
|
||||||
|
|
|
@ -203,13 +203,14 @@ impl Scope {
|
||||||
pub fn lookup(&mut self, ident: &Ident, region: Region) -> Result<Symbol, RuntimeError> {
|
pub fn lookup(&mut self, ident: &Ident, region: Region) -> Result<Symbol, RuntimeError> {
|
||||||
match self.idents.get(ident) {
|
match self.idents.get(ident) {
|
||||||
Some((symbol, _)) => Ok(*symbol),
|
Some((symbol, _)) => Ok(*symbol),
|
||||||
None => Err(RuntimeError::LookupNotInScope(
|
None => Err(RuntimeError::LookupNotInScope {
|
||||||
Loc {
|
loc_name: Loc {
|
||||||
region,
|
region,
|
||||||
value: ident.clone().into(),
|
value: ident.clone().into(),
|
||||||
},
|
},
|
||||||
self.idents.keys().map(|v| v.as_ref().into()).collect(),
|
suggestion_options: self.idents.keys().map(|v| v.as_ref().into()).collect(),
|
||||||
)),
|
underscored_suggestion_region: None,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,10 +48,6 @@ export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
|
||||||
free(@alignCast(16, @ptrCast([*]u8, c_ptr)));
|
free(@alignCast(16, @ptrCast([*]u8, c_ptr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn roc_memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void {
|
|
||||||
return memcpy(dst, src, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
||||||
return memset(dst, value, size);
|
return memset(dst, value, size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,10 +47,6 @@ export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
|
||||||
free(@alignCast(16, @ptrCast([*]u8, c_ptr)));
|
free(@alignCast(16, @ptrCast([*]u8, c_ptr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn roc_memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void {
|
|
||||||
return memcpy(dst, src, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
||||||
return memset(dst, value, size);
|
return memset(dst, value, size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,10 +48,6 @@ export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
|
||||||
free(@alignCast(16, @ptrCast([*]u8, c_ptr)));
|
free(@alignCast(16, @ptrCast([*]u8, c_ptr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn roc_memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void {
|
|
||||||
return memcpy(dst, src, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
||||||
return memset(dst, value, size);
|
return memset(dst, value, size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,10 +73,6 @@ export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void {
|
||||||
std.process.exit(0);
|
std.process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn roc_memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void {
|
|
||||||
return memcpy(dst, src, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
||||||
return memset(dst, value, size);
|
return memset(dst, value, size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,10 +72,6 @@ export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void {
|
||||||
std.process.exit(0);
|
std.process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn roc_memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void {
|
|
||||||
return memcpy(dst, src, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
||||||
return memset(dst, value, size);
|
return memset(dst, value, size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,10 +77,6 @@ export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void {
|
||||||
std.process.exit(0);
|
std.process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn roc_memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void {
|
|
||||||
return memcpy(dst, src, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
||||||
return memset(dst, value, size);
|
return memset(dst, value, size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,10 +67,6 @@ export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void {
|
||||||
std.process.exit(0);
|
std.process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn roc_memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void {
|
|
||||||
return memcpy(dst, src, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
||||||
return memset(dst, value, size);
|
return memset(dst, value, size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,9 @@ pub const DEFAULT_ROC_FILENAME: &str = "main.roc";
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub struct CodeGenTiming {
|
pub struct CodeGenTiming {
|
||||||
pub code_gen: Duration,
|
pub generate_final_ir: Duration,
|
||||||
|
pub code_gen_object: Duration,
|
||||||
|
pub total: Duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn report_problems_monomorphized(loaded: &mut MonomorphizedModule) -> Problems {
|
pub fn report_problems_monomorphized(loaded: &mut MonomorphizedModule) -> Problems {
|
||||||
|
@ -144,7 +146,7 @@ fn gen_from_mono_module_llvm<'a>(
|
||||||
use inkwell::module::Linkage;
|
use inkwell::module::Linkage;
|
||||||
use inkwell::targets::{FileType, RelocMode};
|
use inkwell::targets::{FileType, RelocMode};
|
||||||
|
|
||||||
let code_gen_start = Instant::now();
|
let all_code_gen_start = Instant::now();
|
||||||
|
|
||||||
// Generate the binary
|
// Generate the binary
|
||||||
let target_info = roc_target::TargetInfo::from(target);
|
let target_info = roc_target::TargetInfo::from(target);
|
||||||
|
@ -238,6 +240,10 @@ fn gen_from_mono_module_llvm<'a>(
|
||||||
&loaded.glue_layouts,
|
&loaded.glue_layouts,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// We are now finished building the LLVM IR.
|
||||||
|
let generate_final_ir = all_code_gen_start.elapsed();
|
||||||
|
let code_gen_object_start = Instant::now();
|
||||||
|
|
||||||
env.dibuilder.finalize();
|
env.dibuilder.finalize();
|
||||||
|
|
||||||
// we don't use the debug info, and it causes weird errors.
|
// we don't use the debug info, and it causes weird errors.
|
||||||
|
@ -439,11 +445,16 @@ fn gen_from_mono_module_llvm<'a>(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let code_gen = code_gen_start.elapsed();
|
let code_gen_object = code_gen_object_start.elapsed();
|
||||||
|
let total = all_code_gen_start.elapsed();
|
||||||
|
|
||||||
(
|
(
|
||||||
CodeObject::MemoryBuffer(memory_buffer),
|
CodeObject::MemoryBuffer(memory_buffer),
|
||||||
CodeGenTiming { code_gen },
|
CodeGenTiming {
|
||||||
|
generate_final_ir,
|
||||||
|
code_gen_object,
|
||||||
|
total,
|
||||||
|
},
|
||||||
ExpectMetadata {
|
ExpectMetadata {
|
||||||
interns: env.interns,
|
interns: env.interns,
|
||||||
layout_interner: loaded.layout_interner,
|
layout_interner: loaded.layout_interner,
|
||||||
|
@ -503,7 +514,7 @@ fn gen_from_mono_module_dev_wasm32<'a>(
|
||||||
preprocessed_host_path: &Path,
|
preprocessed_host_path: &Path,
|
||||||
wasm_dev_stack_bytes: Option<u32>,
|
wasm_dev_stack_bytes: Option<u32>,
|
||||||
) -> GenFromMono<'a> {
|
) -> GenFromMono<'a> {
|
||||||
let code_gen_start = Instant::now();
|
let all_code_gen_start = Instant::now();
|
||||||
let MonomorphizedModule {
|
let MonomorphizedModule {
|
||||||
module_id,
|
module_id,
|
||||||
procedures,
|
procedures,
|
||||||
|
@ -550,11 +561,18 @@ fn gen_from_mono_module_dev_wasm32<'a>(
|
||||||
procedures,
|
procedures,
|
||||||
);
|
);
|
||||||
|
|
||||||
let code_gen = code_gen_start.elapsed();
|
let generate_final_ir = all_code_gen_start.elapsed();
|
||||||
|
let code_gen_object_start = Instant::now();
|
||||||
|
let code_gen_object = code_gen_object_start.elapsed();
|
||||||
|
let total = all_code_gen_start.elapsed();
|
||||||
|
|
||||||
(
|
(
|
||||||
CodeObject::Vector(final_binary_bytes),
|
CodeObject::Vector(final_binary_bytes),
|
||||||
CodeGenTiming { code_gen },
|
CodeGenTiming {
|
||||||
|
generate_final_ir,
|
||||||
|
code_gen_object,
|
||||||
|
total,
|
||||||
|
},
|
||||||
ExpectMetadata {
|
ExpectMetadata {
|
||||||
interns,
|
interns,
|
||||||
layout_interner,
|
layout_interner,
|
||||||
|
@ -569,7 +587,7 @@ fn gen_from_mono_module_dev_assembly<'a>(
|
||||||
target: &target_lexicon::Triple,
|
target: &target_lexicon::Triple,
|
||||||
backend_mode: AssemblyBackendMode,
|
backend_mode: AssemblyBackendMode,
|
||||||
) -> GenFromMono<'a> {
|
) -> GenFromMono<'a> {
|
||||||
let code_gen_start = Instant::now();
|
let all_code_gen_start = Instant::now();
|
||||||
|
|
||||||
let lazy_literals = true;
|
let lazy_literals = true;
|
||||||
|
|
||||||
|
@ -593,15 +611,23 @@ fn gen_from_mono_module_dev_assembly<'a>(
|
||||||
let module_object =
|
let module_object =
|
||||||
roc_gen_dev::build_module(&env, &mut interns, &mut layout_interner, target, procedures);
|
roc_gen_dev::build_module(&env, &mut interns, &mut layout_interner, target, procedures);
|
||||||
|
|
||||||
let code_gen = code_gen_start.elapsed();
|
let generate_final_ir = all_code_gen_start.elapsed();
|
||||||
|
let code_gen_object_start = Instant::now();
|
||||||
|
|
||||||
let module_out = module_object
|
let module_out = module_object
|
||||||
.write()
|
.write()
|
||||||
.expect("failed to build output object");
|
.expect("failed to build output object");
|
||||||
|
|
||||||
|
let code_gen_object = code_gen_object_start.elapsed();
|
||||||
|
let total = all_code_gen_start.elapsed();
|
||||||
|
|
||||||
(
|
(
|
||||||
CodeObject::Vector(module_out),
|
CodeObject::Vector(module_out),
|
||||||
CodeGenTiming { code_gen },
|
CodeGenTiming {
|
||||||
|
generate_final_ir,
|
||||||
|
code_gen_object,
|
||||||
|
total,
|
||||||
|
},
|
||||||
ExpectMetadata {
|
ExpectMetadata {
|
||||||
interns,
|
interns,
|
||||||
layout_interner,
|
layout_interner,
|
||||||
|
@ -919,9 +945,12 @@ fn build_loaded_file<'a>(
|
||||||
|
|
||||||
report_timing(
|
report_timing(
|
||||||
buf,
|
buf,
|
||||||
"Generate Assembly from Mono IR",
|
"Generate final IR from Mono IR",
|
||||||
code_gen_timing.code_gen,
|
code_gen_timing.generate_final_ir,
|
||||||
);
|
);
|
||||||
|
report_timing(buf, "Generate object", code_gen_timing.code_gen_object);
|
||||||
|
buf.push('\n');
|
||||||
|
report_timing(buf, "Total", code_gen_timing.total);
|
||||||
|
|
||||||
let compilation_end = compilation_start.elapsed();
|
let compilation_end = compilation_start.elapsed();
|
||||||
let size = roc_app_bytes.len();
|
let size = roc_app_bytes.len();
|
||||||
|
|
80
crates/compiler/builtins/bitcode/src/libc.zig
Normal file
80
crates/compiler/builtins/bitcode/src/libc.zig
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const arch = builtin.cpu.arch;
|
||||||
|
const musl = @import("libc/musl.zig");
|
||||||
|
const folly = @import("libc/folly.zig");
|
||||||
|
const cpuid = @import("libc/cpuid.zig");
|
||||||
|
|
||||||
|
comptime {
|
||||||
|
// TODO: remove this workaround.
|
||||||
|
// Our wasm llvm pipeline always links in memcpy.
|
||||||
|
// As such, our impl will conflict.
|
||||||
|
if (arch != .wasm32) {
|
||||||
|
@export(memcpy, .{ .name = "memcpy", .linkage = .Strong });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Memcpy = fn (noalias [*]u8, noalias [*]const u8, len: usize) callconv(.C) [*]u8;
|
||||||
|
|
||||||
|
pub var memcpy_target: Memcpy = switch (arch) {
|
||||||
|
.x86_64 => dispatch_memcpy,
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn memcpy(noalias dest: [*]u8, noalias src: [*]const u8, len: usize) callconv(.C) [*]u8 {
|
||||||
|
switch (arch) {
|
||||||
|
// x86_64 has a special optimized memcpy that can use avx2.
|
||||||
|
.x86_64 => {
|
||||||
|
return memcpy_target(dest, src, len);
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
return musl.memcpy(dest, src, len);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const MemcpyDecision = enum {
|
||||||
|
uninitialized,
|
||||||
|
folly_prefetchw,
|
||||||
|
folly_prefetcht0,
|
||||||
|
musl,
|
||||||
|
};
|
||||||
|
|
||||||
|
var memcpy_decision: MemcpyDecision = .uninitialized;
|
||||||
|
|
||||||
|
fn dispatch_memcpy(noalias dest: [*]u8, noalias src: [*]const u8, len: usize) callconv(.C) [*]u8 {
|
||||||
|
switch (arch) {
|
||||||
|
.x86_64 => {
|
||||||
|
// TODO: Switch this to overwrite the memcpy_target pointer once the surgical linker can support it.
|
||||||
|
// Then dispatch will just happen on the first call instead of every call.
|
||||||
|
// if (cpuid.supports_avx2()) {
|
||||||
|
// if (cpuid.supports_prefetchw()) {
|
||||||
|
// memcpy_target = folly.memcpy_prefetchw;
|
||||||
|
// } else {
|
||||||
|
// memcpy_target = folly.memcpy_prefetcht0;
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// memcpy_target = musl.memcpy;
|
||||||
|
// }
|
||||||
|
// return memcpy_target(dest, src, len);
|
||||||
|
switch (memcpy_decision) {
|
||||||
|
.uninitialized => {
|
||||||
|
if (cpuid.supports_avx2()) {
|
||||||
|
if (cpuid.supports_prefetchw()) {
|
||||||
|
memcpy_decision = .folly_prefetchw;
|
||||||
|
} else {
|
||||||
|
memcpy_decision = .folly_prefetcht0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
memcpy_decision = .musl;
|
||||||
|
}
|
||||||
|
return dispatch_memcpy(dest, src, len);
|
||||||
|
},
|
||||||
|
.folly_prefetchw => return folly.memcpy_prefetchw(dest, src, len),
|
||||||
|
.folly_prefetcht0 => return folly.memcpy_prefetcht0(dest, src, len),
|
||||||
|
.musl => return musl.memcpy(dest, src, len),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const os = builtin.os;
|
||||||
|
|
||||||
|
pub const function_prefix = switch (os.tag) {
|
||||||
|
.macos => "_",
|
||||||
|
else => "",
|
||||||
|
};
|
53
crates/compiler/builtins/bitcode/src/libc/cpuid.S
Normal file
53
crates/compiler/builtins/bitcode/src/libc/cpuid.S
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
// Check if AVX2 is supported.
|
||||||
|
// Returns 1 if AVX2 is supported, 0 otherwise.
|
||||||
|
.global {[function_prefix]s}supports_avx2;
|
||||||
|
{[function_prefix]s}supports_avx2:
|
||||||
|
// Save the EBX register.
|
||||||
|
push %rbx
|
||||||
|
|
||||||
|
// Call the CPUID instruction with the EAX register set to 7 and ECX set to 0.
|
||||||
|
// This will get the CPUID information for the current CPU.
|
||||||
|
mov $7, %eax
|
||||||
|
mov $0, %ecx
|
||||||
|
cpuid
|
||||||
|
|
||||||
|
// The AVX2 feature flag is located in the EBX register at bit 5.
|
||||||
|
bt $5, %ebx
|
||||||
|
jc .avx2_supported
|
||||||
|
|
||||||
|
// AVX2 is not supported.
|
||||||
|
pop %rbx
|
||||||
|
mov $0, %eax
|
||||||
|
ret
|
||||||
|
|
||||||
|
.avx2_supported:
|
||||||
|
pop %rbx
|
||||||
|
mov $1, %eax
|
||||||
|
ret
|
||||||
|
|
||||||
|
// Check if prefetchw is supported.
|
||||||
|
// Returns 1 if the prefetchw instruction is supported, 0 otherwise.
|
||||||
|
.global {[function_prefix]s}supports_prefetchw;
|
||||||
|
{[function_prefix]s}supports_prefetchw:
|
||||||
|
// Save the EBX register.
|
||||||
|
push %rbx
|
||||||
|
|
||||||
|
// Call the CPUID instruction with the EAX register set to 0x80000001 and ECX set to 0.
|
||||||
|
// This will get the CPUID information for the current CPU.
|
||||||
|
mov $0x80000001, %eax
|
||||||
|
mov $0, %ecx
|
||||||
|
cpuid
|
||||||
|
|
||||||
|
// The prefetchw feature flag is located in the ECX register at bit 8.
|
||||||
|
bt $8, %ecx
|
||||||
|
jc .prefetchw_supported
|
||||||
|
|
||||||
|
// AVX2 is not supported.
|
||||||
|
pop %rbx
|
||||||
|
mov $0, %eax
|
||||||
|
ret
|
||||||
|
|
||||||
|
.prefetchw_supported:
|
||||||
|
pop %rbx
|
||||||
|
mov $1, %eax
|
||||||
|
ret
|
18
crates/compiler/builtins/bitcode/src/libc/cpuid.zig
Normal file
18
crates/compiler/builtins/bitcode/src/libc/cpuid.zig
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const arch = builtin.cpu.arch;
|
||||||
|
const function_prefix = @import("assembly_util.zig").function_prefix;
|
||||||
|
|
||||||
|
// I couldn't manage to define this in a PIE friendly way with inline assembly.
|
||||||
|
// Instead, I am defining it as global assembly functions.
|
||||||
|
comptime {
|
||||||
|
switch (arch) {
|
||||||
|
.x86_64 => {
|
||||||
|
asm (std.fmt.comptimePrint(@embedFile("cpuid.S"), .{ .function_prefix = function_prefix }));
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub extern fn supports_avx2() bool;
|
||||||
|
pub extern fn supports_prefetchw() bool;
|
2
crates/compiler/builtins/bitcode/src/libc/folly.zig
Normal file
2
crates/compiler/builtins/bitcode/src/libc/folly.zig
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
pub const memcpy_prefetchw = @import("folly/memcpy.zig").__folly_memcpy_prefetchw;
|
||||||
|
pub const memcpy_prefetcht0 = @import("folly/memcpy.zig").__folly_memcpy_prefetcht0;
|
437
crates/compiler/builtins/bitcode/src/libc/folly/memcpy-x86_64.S
Normal file
437
crates/compiler/builtins/bitcode/src/libc/folly/memcpy-x86_64.S
Normal file
|
@ -0,0 +1,437 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* __folly_memcpy: An optimized memcpy implementation that uses prefetch and
|
||||||
|
* AVX2 instructions.
|
||||||
|
*
|
||||||
|
* This implementation of memcpy acts as a memmove: while overlapping copies
|
||||||
|
* are undefined in memcpy, in some implementations they're the same function and
|
||||||
|
* legacy programs rely on this behavior.
|
||||||
|
*
|
||||||
|
* This implementation uses prefetch to avoid dtlb misses. This can
|
||||||
|
* substantially reduce dtlb store misses in cases where the destination
|
||||||
|
* location is absent from L1 cache and where the copy size is small enough
|
||||||
|
* that the hardware prefetcher doesn't have a large impact.
|
||||||
|
*
|
||||||
|
* The number of branches is limited by the use of overlapping loads & stores.
|
||||||
|
* This helps with copies where the source and destination cache lines are already
|
||||||
|
* present in L1 because there are fewer instructions to execute and fewer
|
||||||
|
* branches to potentially mispredict.
|
||||||
|
* e.g. to copy the last 4 <= n <= 7 bytes: copy the first & last 4 bytes (overlapped):
|
||||||
|
* movl (%rsi), %r8d
|
||||||
|
* movl -4(%rsi,%rdx), %r9d
|
||||||
|
* movl %r8d, (%rdi)
|
||||||
|
* movl %r9d, -4(%rdi,%rdx)
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* For sizes up to 256 all source data is first read into registers and then written:
|
||||||
|
* - n <= 16: overlapping movs
|
||||||
|
* - n <= 32: overlapping unaligned 16-byte SSE XMM load/stores
|
||||||
|
* - n <= 256: overlapping unaligned 32-byte AVX YMM load/stores
|
||||||
|
*
|
||||||
|
* Large copies (> 256 bytes) use unaligned loads + aligned stores.
|
||||||
|
* This is observed to always be faster than rep movsb, so the rep movsb
|
||||||
|
* instruction is not used.
|
||||||
|
* - The head & tail may be unaligned => they're always written using unaligned stores.
|
||||||
|
*
|
||||||
|
* If the copy size is humongous (> 32 KiB) and the source and destination are both
|
||||||
|
* aligned, this memcpy will use non-temporal operations (AVX2). This can have
|
||||||
|
* a substantial speedup for copies where data is absent from L1, but it
|
||||||
|
* is significantly slower if the source and destination data were already
|
||||||
|
* in L1. The use of non-temporal operations also has the effect that after
|
||||||
|
* the copy is complete, the data will be moved out of L1, even if the data was
|
||||||
|
* present before the copy started.
|
||||||
|
*
|
||||||
|
* For n > 256 and overlapping src & dst buffers (memmove):
|
||||||
|
* - use unaligned loads + aligned stores, but not non-temporal stores
|
||||||
|
* - for dst < src forward copy in 128 byte batches:
|
||||||
|
* - unaligned load the first 32 bytes & last 4 x 32 bytes
|
||||||
|
* - forward copy (unaligned load + aligned stores) 4 x 32 bytes at a time
|
||||||
|
* - unaligned store the first 32 bytes & last 4 x 32 bytes
|
||||||
|
* - for dst > src backward copy in 128 byte batches:
|
||||||
|
* - unaligned load the first 4 x 32 bytes & last 32 bytes
|
||||||
|
* - backward copy (unaligned load + aligned stores) 4 x 32 bytes at a time
|
||||||
|
* - unaligned store the first 4 x 32 bytes & last 32 bytes
|
||||||
|
*
|
||||||
|
* @author Logan Evans <lpe@fb.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// .type {[function_prefix]s}__folly_memcpy_short_{[prefetch]s}, @function not supported by windows
|
||||||
|
{[function_prefix]s}__folly_memcpy_short_{[prefetch]s}:
|
||||||
|
.cfi_startproc
|
||||||
|
|
||||||
|
.L_GE1_LE7_{[prefetch]s}:
|
||||||
|
cmp $1, %rdx
|
||||||
|
je .L_EQ1_{[prefetch]s}
|
||||||
|
|
||||||
|
cmp $4, %rdx
|
||||||
|
jae .L_GE4_LE7_{[prefetch]s}
|
||||||
|
|
||||||
|
.L_GE2_LE3_{[prefetch]s}:
|
||||||
|
movw (%rsi), %r8w
|
||||||
|
movw -2(%rsi,%rdx), %r9w
|
||||||
|
movw %r8w, (%rdi)
|
||||||
|
movw %r9w, -2(%rdi,%rdx)
|
||||||
|
ret
|
||||||
|
|
||||||
|
.balign 2
|
||||||
|
.L_EQ1_{[prefetch]s}:
|
||||||
|
movb (%rsi), %r8b
|
||||||
|
movb %r8b, (%rdi)
|
||||||
|
ret
|
||||||
|
|
||||||
|
// Aligning the target of a jump to an even address has a measurable
|
||||||
|
// speedup in microbenchmarks.
|
||||||
|
.balign 2
|
||||||
|
.L_GE4_LE7_{[prefetch]s}:
|
||||||
|
movl (%rsi), %r8d
|
||||||
|
movl -4(%rsi,%rdx), %r9d
|
||||||
|
movl %r8d, (%rdi)
|
||||||
|
movl %r9d, -4(%rdi,%rdx)
|
||||||
|
ret
|
||||||
|
|
||||||
|
.cfi_endproc
|
||||||
|
// .size {[function_prefix]s}__folly_memcpy_short_{[prefetch]s}, .-{[function_prefix]s}__folly_memcpy_short_{[prefetch]s} not supported by windows
|
||||||
|
|
||||||
|
// memcpy is an alternative entrypoint into the function named __folly_memcpy.
|
||||||
|
// The compiler is able to call memcpy since the name is global while
|
||||||
|
// stacktraces will show __folly_memcpy since that is the name of the function.
|
||||||
|
// This is intended to aid in debugging by making it obvious which version of
|
||||||
|
// memcpy is being used.
|
||||||
|
.balign 64
|
||||||
|
.globl {[function_prefix]s}__folly_memcpy_{[prefetch]s}
|
||||||
|
// .type {[function_prefix]s}__folly_memcpy_{[prefetch]s}, @function not supported by windows
|
||||||
|
|
||||||
|
{[function_prefix]s}__folly_memcpy_{[prefetch]s}:
|
||||||
|
.cfi_startproc
|
||||||
|
|
||||||
|
mov %rdi, %rax // return: $rdi
|
||||||
|
|
||||||
|
test %rdx, %rdx
|
||||||
|
je .L_EQ0_{[prefetch]s}
|
||||||
|
|
||||||
|
{[prefetch]s} (%rdi)
|
||||||
|
{[prefetch]s} -1(%rdi,%rdx)
|
||||||
|
|
||||||
|
cmp $8, %rdx
|
||||||
|
jb .L_GE1_LE7_{[prefetch]s}
|
||||||
|
|
||||||
|
.L_GE8_{[prefetch]s}:
|
||||||
|
cmp $32, %rdx
|
||||||
|
ja .L_GE33_{[prefetch]s}
|
||||||
|
|
||||||
|
.L_GE8_LE32_{[prefetch]s}:
|
||||||
|
cmp $16, %rdx
|
||||||
|
ja .L_GE17_LE32_{[prefetch]s}
|
||||||
|
|
||||||
|
.L_GE8_LE16_{[prefetch]s}:
|
||||||
|
mov (%rsi), %r8
|
||||||
|
mov -8(%rsi,%rdx), %r9
|
||||||
|
mov %r8, (%rdi)
|
||||||
|
mov %r9, -8(%rdi,%rdx)
|
||||||
|
.L_EQ0_{[prefetch]s}:
|
||||||
|
ret
|
||||||
|
|
||||||
|
.balign 2
|
||||||
|
.L_GE17_LE32_{[prefetch]s}:
|
||||||
|
movdqu (%rsi), %xmm0
|
||||||
|
movdqu -16(%rsi,%rdx), %xmm1
|
||||||
|
movdqu %xmm0, (%rdi)
|
||||||
|
movdqu %xmm1, -16(%rdi,%rdx)
|
||||||
|
ret
|
||||||
|
|
||||||
|
.balign 2
|
||||||
|
.L_GE193_LE256_{[prefetch]s}:
|
||||||
|
vmovdqu %ymm3, 96(%rdi)
|
||||||
|
vmovdqu %ymm4, -128(%rdi,%rdx)
|
||||||
|
|
||||||
|
.L_GE129_LE192_{[prefetch]s}:
|
||||||
|
vmovdqu %ymm2, 64(%rdi)
|
||||||
|
vmovdqu %ymm5, -96(%rdi,%rdx)
|
||||||
|
|
||||||
|
.L_GE65_LE128_{[prefetch]s}:
|
||||||
|
vmovdqu %ymm1, 32(%rdi)
|
||||||
|
vmovdqu %ymm6, -64(%rdi,%rdx)
|
||||||
|
|
||||||
|
.L_GE33_LE64_{[prefetch]s}:
|
||||||
|
vmovdqu %ymm0, (%rdi)
|
||||||
|
vmovdqu %ymm7, -32(%rdi,%rdx)
|
||||||
|
|
||||||
|
vzeroupper
|
||||||
|
ret
|
||||||
|
|
||||||
|
.balign 2
|
||||||
|
.L_GE33_{[prefetch]s}:
|
||||||
|
vmovdqu (%rsi), %ymm0
|
||||||
|
vmovdqu -32(%rsi,%rdx), %ymm7
|
||||||
|
|
||||||
|
cmp $64, %rdx
|
||||||
|
jbe .L_GE33_LE64_{[prefetch]s}
|
||||||
|
|
||||||
|
{[prefetch]s} 64(%rdi)
|
||||||
|
|
||||||
|
vmovdqu 32(%rsi), %ymm1
|
||||||
|
vmovdqu -64(%rsi,%rdx), %ymm6
|
||||||
|
|
||||||
|
cmp $128, %rdx
|
||||||
|
jbe .L_GE65_LE128_{[prefetch]s}
|
||||||
|
|
||||||
|
{[prefetch]s} 128(%rdi)
|
||||||
|
|
||||||
|
vmovdqu 64(%rsi), %ymm2
|
||||||
|
vmovdqu -96(%rsi,%rdx), %ymm5
|
||||||
|
|
||||||
|
cmp $192, %rdx
|
||||||
|
jbe .L_GE129_LE192_{[prefetch]s}
|
||||||
|
|
||||||
|
{[prefetch]s} 192(%rdi)
|
||||||
|
|
||||||
|
vmovdqu 96(%rsi), %ymm3
|
||||||
|
vmovdqu -128(%rsi,%rdx), %ymm4
|
||||||
|
|
||||||
|
cmp $256, %rdx
|
||||||
|
jbe .L_GE193_LE256_{[prefetch]s}
|
||||||
|
|
||||||
|
.L_GE257_{[prefetch]s}:
|
||||||
|
{[prefetch]s} 256(%rdi)
|
||||||
|
|
||||||
|
// Check if there is an overlap. If there is an overlap then the caller
|
||||||
|
// has a bug since this is undefined behavior. However, for legacy
|
||||||
|
// reasons this behavior is expected by some callers.
|
||||||
|
//
|
||||||
|
// All copies through 256 bytes will operate as a memmove since for
|
||||||
|
// those sizes all reads are performed before any writes.
|
||||||
|
//
|
||||||
|
// This check uses the idea that there is an overlap if
|
||||||
|
// (%rdi < (%rsi + %rdx)) && (%rsi < (%rdi + %rdx)),
|
||||||
|
// or equivalently, there is no overlap if
|
||||||
|
// ((%rsi + %rdx) <= %rdi) || ((%rdi + %rdx) <= %rsi).
|
||||||
|
//
|
||||||
|
// %r9 will be used after .L_ALIGNED_DST_LOOP to calculate how many
|
||||||
|
// bytes remain to be copied.
|
||||||
|
|
||||||
|
// (%rsi + %rdx <= %rdi) => no overlap
|
||||||
|
lea (%rsi,%rdx), %r9
|
||||||
|
cmp %rdi, %r9
|
||||||
|
jbe .L_NO_OVERLAP_{[prefetch]s}
|
||||||
|
|
||||||
|
// (%rdi + %rdx <= %rsi) => no overlap
|
||||||
|
lea (%rdi,%rdx), %r8
|
||||||
|
cmp %rsi, %r8
|
||||||
|
// If no info is available in branch predictor's cache, Intel CPUs assume
|
||||||
|
// forward jumps are not taken. Use a forward jump as overlapping buffers
|
||||||
|
// are unlikely.
|
||||||
|
ja .L_OVERLAP_{[prefetch]s}
|
||||||
|
|
||||||
|
.balign 2
|
||||||
|
.L_NO_OVERLAP_{[prefetch]s}:
|
||||||
|
vmovdqu %ymm0, (%rdi)
|
||||||
|
vmovdqu %ymm1, 32(%rdi)
|
||||||
|
vmovdqu %ymm2, 64(%rdi)
|
||||||
|
vmovdqu %ymm3, 96(%rdi)
|
||||||
|
|
||||||
|
// Align %rdi to a 32 byte boundary.
|
||||||
|
// %rcx = 128 - 31 & %rdi
|
||||||
|
mov $128, %rcx
|
||||||
|
and $31, %rdi
|
||||||
|
sub %rdi, %rcx
|
||||||
|
|
||||||
|
lea (%rsi,%rcx), %rsi
|
||||||
|
lea (%rax,%rcx), %rdi
|
||||||
|
sub %rcx, %rdx
|
||||||
|
|
||||||
|
// %r8 is the end condition for the loop.
|
||||||
|
lea -128(%rsi,%rdx), %r8
|
||||||
|
|
||||||
|
// This threshold is half of L1 cache on a Skylake machine, which means that
|
||||||
|
// potentially all of L1 will be populated by this copy once it is executed
|
||||||
|
// (dst and src are cached for temporal copies).
|
||||||
|
// NON_TEMPORAL_STORE_THRESHOLD = $32768
|
||||||
|
// cmp NON_TEMPORAL_STORE_THRESHOLD, %rdx
|
||||||
|
cmp $32768, %rdx
|
||||||
|
jae .L_NON_TEMPORAL_LOOP_{[prefetch]s}
|
||||||
|
|
||||||
|
.balign 2
|
||||||
|
.L_ALIGNED_DST_LOOP_{[prefetch]s}:
|
||||||
|
{[prefetch]s} 128(%rdi)
|
||||||
|
{[prefetch]s} 192(%rdi)
|
||||||
|
|
||||||
|
vmovdqu (%rsi), %ymm0
|
||||||
|
vmovdqu 32(%rsi), %ymm1
|
||||||
|
vmovdqu 64(%rsi), %ymm2
|
||||||
|
vmovdqu 96(%rsi), %ymm3
|
||||||
|
add $128, %rsi
|
||||||
|
|
||||||
|
vmovdqa %ymm0, (%rdi)
|
||||||
|
vmovdqa %ymm1, 32(%rdi)
|
||||||
|
vmovdqa %ymm2, 64(%rdi)
|
||||||
|
vmovdqa %ymm3, 96(%rdi)
|
||||||
|
add $128, %rdi
|
||||||
|
|
||||||
|
cmp %r8, %rsi
|
||||||
|
jb .L_ALIGNED_DST_LOOP_{[prefetch]s}
|
||||||
|
|
||||||
|
.L_ALIGNED_DST_LOOP_END_{[prefetch]s}:
|
||||||
|
sub %rsi, %r9
|
||||||
|
mov %r9, %rdx
|
||||||
|
|
||||||
|
vmovdqu %ymm4, -128(%rdi,%rdx)
|
||||||
|
vmovdqu %ymm5, -96(%rdi,%rdx)
|
||||||
|
vmovdqu %ymm6, -64(%rdi,%rdx)
|
||||||
|
vmovdqu %ymm7, -32(%rdi,%rdx)
|
||||||
|
|
||||||
|
vzeroupper
|
||||||
|
ret
|
||||||
|
|
||||||
|
.balign 2
|
||||||
|
.L_NON_TEMPORAL_LOOP_{[prefetch]s}:
|
||||||
|
testb $31, %sil
|
||||||
|
jne .L_ALIGNED_DST_LOOP_{[prefetch]s}
|
||||||
|
// This is prefetching the source data unlike ALIGNED_DST_LOOP which
|
||||||
|
// prefetches the destination data. This choice is again informed by
|
||||||
|
// benchmarks. With a non-temporal store the entirety of the cache line
|
||||||
|
// is being written so the previous data can be discarded without being
|
||||||
|
// fetched.
|
||||||
|
prefetchnta 128(%rsi)
|
||||||
|
prefetchnta 196(%rsi)
|
||||||
|
|
||||||
|
vmovntdqa (%rsi), %ymm0
|
||||||
|
vmovntdqa 32(%rsi), %ymm1
|
||||||
|
vmovntdqa 64(%rsi), %ymm2
|
||||||
|
vmovntdqa 96(%rsi), %ymm3
|
||||||
|
add $128, %rsi
|
||||||
|
|
||||||
|
vmovntdq %ymm0, (%rdi)
|
||||||
|
vmovntdq %ymm1, 32(%rdi)
|
||||||
|
vmovntdq %ymm2, 64(%rdi)
|
||||||
|
vmovntdq %ymm3, 96(%rdi)
|
||||||
|
add $128, %rdi
|
||||||
|
|
||||||
|
cmp %r8, %rsi
|
||||||
|
jb .L_NON_TEMPORAL_LOOP_{[prefetch]s}
|
||||||
|
|
||||||
|
sfence
|
||||||
|
jmp .L_ALIGNED_DST_LOOP_END_{[prefetch]s}
|
||||||
|
|
||||||
|
|
||||||
|
.L_OVERLAP_{[prefetch]s}:
|
||||||
|
.balign 2
|
||||||
|
cmp %rdi, %rsi
|
||||||
|
jb .L_OVERLAP_BWD_{[prefetch]s} // %rsi < %rdi => backward-copy
|
||||||
|
je .L_RET_{[prefetch]s} // %rsi == %rdi => return, nothing to copy
|
||||||
|
|
||||||
|
// Source & destination buffers overlap. Forward copy.
|
||||||
|
|
||||||
|
vmovdqu (%rsi), %ymm8
|
||||||
|
|
||||||
|
// Align %rdi to a 32 byte boundary.
|
||||||
|
// %rcx = 32 - 31 & %rdi
|
||||||
|
mov $32, %rcx
|
||||||
|
and $31, %rdi
|
||||||
|
sub %rdi, %rcx
|
||||||
|
|
||||||
|
lea (%rsi,%rcx), %rsi
|
||||||
|
lea (%rax,%rcx), %rdi
|
||||||
|
sub %rcx, %rdx
|
||||||
|
|
||||||
|
// %r8 is the end condition for the loop.
|
||||||
|
lea -128(%rsi,%rdx), %r8
|
||||||
|
|
||||||
|
|
||||||
|
.L_OVERLAP_FWD_ALIGNED_DST_LOOP_{[prefetch]s}:
|
||||||
|
{[prefetch]s} 128(%rdi)
|
||||||
|
{[prefetch]s} 192(%rdi)
|
||||||
|
|
||||||
|
vmovdqu (%rsi), %ymm0
|
||||||
|
vmovdqu 32(%rsi), %ymm1
|
||||||
|
vmovdqu 64(%rsi), %ymm2
|
||||||
|
vmovdqu 96(%rsi), %ymm3
|
||||||
|
add $128, %rsi
|
||||||
|
|
||||||
|
vmovdqa %ymm0, (%rdi)
|
||||||
|
vmovdqa %ymm1, 32(%rdi)
|
||||||
|
vmovdqa %ymm2, 64(%rdi)
|
||||||
|
vmovdqa %ymm3, 96(%rdi)
|
||||||
|
add $128, %rdi
|
||||||
|
|
||||||
|
cmp %r8, %rsi
|
||||||
|
jb .L_OVERLAP_FWD_ALIGNED_DST_LOOP_{[prefetch]s}
|
||||||
|
|
||||||
|
sub %rsi, %r9
|
||||||
|
mov %r9, %rdx
|
||||||
|
|
||||||
|
vmovdqu %ymm4, -128(%rdi,%rdx)
|
||||||
|
vmovdqu %ymm5, -96(%rdi,%rdx)
|
||||||
|
vmovdqu %ymm6, -64(%rdi,%rdx)
|
||||||
|
vmovdqu %ymm7, -32(%rdi,%rdx)
|
||||||
|
vmovdqu %ymm8, (%rax) // %rax == the original (unaligned) %rdi
|
||||||
|
|
||||||
|
vzeroupper
|
||||||
|
|
||||||
|
.L_RET_{[prefetch]s}:
|
||||||
|
ret
|
||||||
|
|
||||||
|
.L_OVERLAP_BWD_{[prefetch]s}:
|
||||||
|
// Save last 32 bytes.
|
||||||
|
vmovdqu -32(%rsi, %rdx), %ymm8
|
||||||
|
lea -32(%rdi, %rdx), %r9
|
||||||
|
|
||||||
|
|
||||||
|
// %r8 is the end condition for the loop.
|
||||||
|
lea 128(%rsi), %r8
|
||||||
|
|
||||||
|
// Align %rdi+%rdx (destination end) to a 32 byte boundary.
|
||||||
|
// %rcx = (%rdi + %rdx - 32) & 31
|
||||||
|
mov %r9, %rcx
|
||||||
|
and $31, %rcx
|
||||||
|
// Set %rsi & %rdi to the end of the 32 byte aligned range.
|
||||||
|
sub %rcx, %rdx
|
||||||
|
add %rdx, %rsi
|
||||||
|
add %rdx, %rdi
|
||||||
|
|
||||||
|
|
||||||
|
.L_OVERLAP_BWD_ALIGNED_DST_LOOP_{[prefetch]s}:
|
||||||
|
{[prefetch]s} -128(%rdi)
|
||||||
|
{[prefetch]s} -192(%rdi)
|
||||||
|
|
||||||
|
vmovdqu -32(%rsi), %ymm4
|
||||||
|
vmovdqu -64(%rsi), %ymm5
|
||||||
|
vmovdqu -96(%rsi), %ymm6
|
||||||
|
vmovdqu -128(%rsi), %ymm7
|
||||||
|
sub $128, %rsi
|
||||||
|
|
||||||
|
vmovdqa %ymm4, -32(%rdi)
|
||||||
|
vmovdqa %ymm5, -64(%rdi)
|
||||||
|
vmovdqa %ymm6, -96(%rdi)
|
||||||
|
vmovdqa %ymm7, -128(%rdi)
|
||||||
|
sub $128, %rdi
|
||||||
|
|
||||||
|
cmp %r8, %rsi
|
||||||
|
ja .L_OVERLAP_BWD_ALIGNED_DST_LOOP_{[prefetch]s}
|
||||||
|
|
||||||
|
vmovdqu %ymm0, (%rax) // %rax == the original unaligned %rdi
|
||||||
|
vmovdqu %ymm1, 32(%rax)
|
||||||
|
vmovdqu %ymm2, 64(%rax)
|
||||||
|
vmovdqu %ymm3, 96(%rax)
|
||||||
|
vmovdqu %ymm8, (%r9)
|
||||||
|
|
||||||
|
vzeroupper
|
||||||
|
ret
|
||||||
|
|
||||||
|
.cfi_endproc
|
||||||
|
// .size {[function_prefix]s}__folly_memcpy_{[prefetch]s}, .-{[function_prefix]s}__folly_memcpy_{[prefetch]s} not supported by windows
|
18
crates/compiler/builtins/bitcode/src/libc/folly/memcpy.zig
Normal file
18
crates/compiler/builtins/bitcode/src/libc/folly/memcpy.zig
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const arch = builtin.cpu.arch;
|
||||||
|
const function_prefix = @import("../assembly_util.zig").function_prefix;
|
||||||
|
|
||||||
|
comptime {
|
||||||
|
switch (arch) {
|
||||||
|
.x86_64 => {
|
||||||
|
inline for ([_][]const u8{ "prefetchw", "prefetcht0" }) |prefetch| {
|
||||||
|
asm (std.fmt.comptimePrint(@embedFile("memcpy-x86_64.S"), .{ .prefetch = prefetch, .function_prefix = function_prefix }));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub extern fn __folly_memcpy_prefetchw(noalias dest: [*]u8, noalias src: [*]const u8, len: usize) callconv(.C) [*]u8;
|
||||||
|
pub extern fn __folly_memcpy_prefetcht0(noalias dest: [*]u8, noalias src: [*]const u8, len: usize) callconv(.C) [*]u8;
|
1
crates/compiler/builtins/bitcode/src/libc/musl.zig
Normal file
1
crates/compiler/builtins/bitcode/src/libc/musl.zig
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub const memcpy = @import("musl/memcpy.zig").memcpy;
|
193
crates/compiler/builtins/bitcode/src/libc/musl/COPYRIGHT
Normal file
193
crates/compiler/builtins/bitcode/src/libc/musl/COPYRIGHT
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
musl as a whole is licensed under the following standard MIT license:
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
Copyright © 2005-2020 Rich Felker, et al.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Authors/contributors include:
|
||||||
|
|
||||||
|
A. Wilcox
|
||||||
|
Ada Worcester
|
||||||
|
Alex Dowad
|
||||||
|
Alex Suykov
|
||||||
|
Alexander Monakov
|
||||||
|
Andre McCurdy
|
||||||
|
Andrew Kelley
|
||||||
|
Anthony G. Basile
|
||||||
|
Aric Belsito
|
||||||
|
Arvid Picciani
|
||||||
|
Bartosz Brachaczek
|
||||||
|
Benjamin Peterson
|
||||||
|
Bobby Bingham
|
||||||
|
Boris Brezillon
|
||||||
|
Brent Cook
|
||||||
|
Chris Spiegel
|
||||||
|
Clément Vasseur
|
||||||
|
Daniel Micay
|
||||||
|
Daniel Sabogal
|
||||||
|
Daurnimator
|
||||||
|
David Carlier
|
||||||
|
David Edelsohn
|
||||||
|
Denys Vlasenko
|
||||||
|
Dmitry Ivanov
|
||||||
|
Dmitry V. Levin
|
||||||
|
Drew DeVault
|
||||||
|
Emil Renner Berthing
|
||||||
|
Fangrui Song
|
||||||
|
Felix Fietkau
|
||||||
|
Felix Janda
|
||||||
|
Gianluca Anzolin
|
||||||
|
Hauke Mehrtens
|
||||||
|
He X
|
||||||
|
Hiltjo Posthuma
|
||||||
|
Isaac Dunham
|
||||||
|
Jaydeep Patil
|
||||||
|
Jens Gustedt
|
||||||
|
Jeremy Huntwork
|
||||||
|
Jo-Philipp Wich
|
||||||
|
Joakim Sindholt
|
||||||
|
John Spencer
|
||||||
|
Julien Ramseier
|
||||||
|
Justin Cormack
|
||||||
|
Kaarle Ritvanen
|
||||||
|
Khem Raj
|
||||||
|
Kylie McClain
|
||||||
|
Leah Neukirchen
|
||||||
|
Luca Barbato
|
||||||
|
Luka Perkov
|
||||||
|
M Farkas-Dyck (Strake)
|
||||||
|
Mahesh Bodapati
|
||||||
|
Markus Wichmann
|
||||||
|
Masanori Ogino
|
||||||
|
Michael Clark
|
||||||
|
Michael Forney
|
||||||
|
Mikhail Kremnyov
|
||||||
|
Natanael Copa
|
||||||
|
Nicholas J. Kain
|
||||||
|
orc
|
||||||
|
Pascal Cuoq
|
||||||
|
Patrick Oppenlander
|
||||||
|
Petr Hosek
|
||||||
|
Petr Skocik
|
||||||
|
Pierre Carrier
|
||||||
|
Reini Urban
|
||||||
|
Rich Felker
|
||||||
|
Richard Pennington
|
||||||
|
Ryan Fairfax
|
||||||
|
Samuel Holland
|
||||||
|
Segev Finer
|
||||||
|
Shiz
|
||||||
|
sin
|
||||||
|
Solar Designer
|
||||||
|
Stefan Kristiansson
|
||||||
|
Stefan O'Rear
|
||||||
|
Szabolcs Nagy
|
||||||
|
Timo Teräs
|
||||||
|
Trutz Behn
|
||||||
|
Valentin Ochs
|
||||||
|
Will Dietz
|
||||||
|
William Haddon
|
||||||
|
William Pitcock
|
||||||
|
|
||||||
|
Portions of this software are derived from third-party works licensed
|
||||||
|
under terms compatible with the above MIT license:
|
||||||
|
|
||||||
|
The TRE regular expression implementation (src/regex/reg* and
|
||||||
|
src/regex/tre*) is Copyright © 2001-2008 Ville Laurikari and licensed
|
||||||
|
under a 2-clause BSD license (license text in the source files). The
|
||||||
|
included version has been heavily modified by Rich Felker in 2012, in
|
||||||
|
the interests of size, simplicity, and namespace cleanliness.
|
||||||
|
|
||||||
|
Much of the math library code (src/math/* and src/complex/*) is
|
||||||
|
Copyright © 1993,2004 Sun Microsystems or
|
||||||
|
Copyright © 2003-2011 David Schultz or
|
||||||
|
Copyright © 2003-2009 Steven G. Kargl or
|
||||||
|
Copyright © 2003-2009 Bruce D. Evans or
|
||||||
|
Copyright © 2008 Stephen L. Moshier or
|
||||||
|
Copyright © 2017-2018 Arm Limited
|
||||||
|
and labelled as such in comments in the individual source files. All
|
||||||
|
have been licensed under extremely permissive terms.
|
||||||
|
|
||||||
|
The ARM memcpy code (src/string/arm/memcpy.S) is Copyright © 2008
|
||||||
|
The Android Open Source Project and is licensed under a two-clause BSD
|
||||||
|
license. It was taken from Bionic libc, used on Android.
|
||||||
|
|
||||||
|
The AArch64 memcpy and memset code (src/string/aarch64/*) are
|
||||||
|
Copyright © 1999-2019, Arm Limited.
|
||||||
|
|
||||||
|
The implementation of DES for crypt (src/crypt/crypt_des.c) is
|
||||||
|
Copyright © 1994 David Burren. It is licensed under a BSD license.
|
||||||
|
|
||||||
|
The implementation of blowfish crypt (src/crypt/crypt_blowfish.c) was
|
||||||
|
originally written by Solar Designer and placed into the public
|
||||||
|
domain. The code also comes with a fallback permissive license for use
|
||||||
|
in jurisdictions that may not recognize the public domain.
|
||||||
|
|
||||||
|
The smoothsort implementation (src/stdlib/qsort.c) is Copyright © 2011
|
||||||
|
Valentin Ochs and is licensed under an MIT-style license.
|
||||||
|
|
||||||
|
The x86_64 port was written by Nicholas J. Kain and is licensed under
|
||||||
|
the standard MIT terms.
|
||||||
|
|
||||||
|
The mips and microblaze ports were originally written by Richard
|
||||||
|
Pennington for use in the ellcc project. The original code was adapted
|
||||||
|
by Rich Felker for build system and code conventions during upstream
|
||||||
|
integration. It is licensed under the standard MIT terms.
|
||||||
|
|
||||||
|
The mips64 port was contributed by Imagination Technologies and is
|
||||||
|
licensed under the standard MIT terms.
|
||||||
|
|
||||||
|
The powerpc port was also originally written by Richard Pennington,
|
||||||
|
and later supplemented and integrated by John Spencer. It is licensed
|
||||||
|
under the standard MIT terms.
|
||||||
|
|
||||||
|
All other files which have no copyright comments are original works
|
||||||
|
produced specifically for use as part of this library, written either
|
||||||
|
by Rich Felker, the main author of the library, or by one or more
|
||||||
|
contibutors listed above. Details on authorship of individual files
|
||||||
|
can be found in the git version control history of the project. The
|
||||||
|
omission of copyright and license comments in each file is in the
|
||||||
|
interest of source tree size.
|
||||||
|
|
||||||
|
In addition, permission is hereby granted for all public header files
|
||||||
|
(include/* and arch/*/bits/*) and crt files intended to be linked into
|
||||||
|
applications (crt/*, ldso/dlstart.c, and arch/*/crt_arch.h) to omit
|
||||||
|
the copyright notice and permission notice otherwise required by the
|
||||||
|
license, and to use these files without any requirement of
|
||||||
|
attribution. These files include substantial contributions from:
|
||||||
|
|
||||||
|
Bobby Bingham
|
||||||
|
John Spencer
|
||||||
|
Nicholas J. Kain
|
||||||
|
Rich Felker
|
||||||
|
Richard Pennington
|
||||||
|
Stefan Kristiansson
|
||||||
|
Szabolcs Nagy
|
||||||
|
|
||||||
|
all of whom have explicitly granted such permission.
|
||||||
|
|
||||||
|
This file previously contained text expressing a belief that most of
|
||||||
|
the files covered by the above exception were sufficiently trivial not
|
||||||
|
to be subject to copyright, resulting in confusion over whether it
|
||||||
|
negated the permissions granted in the license. In the spirit of
|
||||||
|
permissive licensing, and of not having licensing issues being an
|
||||||
|
obstacle to adoption, that text has been removed.
|
2
crates/compiler/builtins/bitcode/src/libc/musl/README.md
Normal file
2
crates/compiler/builtins/bitcode/src/libc/musl/README.md
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
This set of files all come from [musl libc](https://musl.libc.org/).
|
||||||
|
Roc just directly uses a few of them instead of depending on musl libc fully.
|
30
crates/compiler/builtins/bitcode/src/libc/musl/memcpy-i386.S
Normal file
30
crates/compiler/builtins/bitcode/src/libc/musl/memcpy-i386.S
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
.global {[function_prefix]s}musl_memcpy
|
||||||
|
// Windows does not support the type directive.
|
||||||
|
// .type {[function_prefix]s}musl_memcpy,@function
|
||||||
|
{[function_prefix]s}musl_memcpy:
|
||||||
|
push %esi
|
||||||
|
push %edi
|
||||||
|
mov 12(%esp),%edi
|
||||||
|
mov 16(%esp),%esi
|
||||||
|
mov 20(%esp),%ecx
|
||||||
|
mov %edi,%eax
|
||||||
|
cmp $4,%ecx
|
||||||
|
jc 1f
|
||||||
|
test $3,%edi
|
||||||
|
jz 1f
|
||||||
|
2: movsb
|
||||||
|
dec %ecx
|
||||||
|
test $3,%edi
|
||||||
|
jnz 2b
|
||||||
|
1: mov %ecx,%edx
|
||||||
|
shr $2,%ecx
|
||||||
|
rep
|
||||||
|
movsl
|
||||||
|
and $3,%edx
|
||||||
|
jz 1f
|
||||||
|
2: movsb
|
||||||
|
dec %edx
|
||||||
|
jnz 2b
|
||||||
|
1: pop %edi
|
||||||
|
pop %esi
|
||||||
|
ret
|
|
@ -0,0 +1,23 @@
|
||||||
|
.global {[function_prefix]s}musl_memcpy
|
||||||
|
// Windows does not support the type directive.
|
||||||
|
// .type {[function_prefix]s}musl_memcpy,@function
|
||||||
|
{[function_prefix]s}musl_memcpy:
|
||||||
|
mov %rdi,%rax
|
||||||
|
cmp $8,%rdx
|
||||||
|
jc 1f
|
||||||
|
test $7,%edi
|
||||||
|
jz 1f
|
||||||
|
2: movsb
|
||||||
|
dec %rdx
|
||||||
|
test $7,%edi
|
||||||
|
jnz 2b
|
||||||
|
1: mov %rdx,%rcx
|
||||||
|
shr $3,%rcx
|
||||||
|
rep
|
||||||
|
movsq
|
||||||
|
and $7,%edx
|
||||||
|
jz 1f
|
||||||
|
2: movsb
|
||||||
|
dec %edx
|
||||||
|
jnz 2b
|
||||||
|
1: ret
|
201
crates/compiler/builtins/bitcode/src/libc/musl/memcpy.zig
Normal file
201
crates/compiler/builtins/bitcode/src/libc/musl/memcpy.zig
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const arch = builtin.cpu.arch;
|
||||||
|
const function_prefix = @import("../assembly_util.zig").function_prefix;
|
||||||
|
|
||||||
|
comptime {
|
||||||
|
switch (arch) {
|
||||||
|
.x86_64 => {
|
||||||
|
asm (std.fmt.comptimePrint(@embedFile("memcpy-x86_64.S"), .{ .function_prefix = function_prefix }));
|
||||||
|
},
|
||||||
|
.i386 => {
|
||||||
|
asm (std.fmt.comptimePrint(@embedFile("memcpy-i386.S"), .{ .function_prefix = function_prefix }));
|
||||||
|
},
|
||||||
|
// TODO: add assembly implementations for other platforms.
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const memcpy =
|
||||||
|
switch (arch) {
|
||||||
|
.x86_64, .i386 => musl_memcpy,
|
||||||
|
else => fallback_memcpy,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub extern fn musl_memcpy(noalias dest: [*]u8, noalias src: [*]const u8, len: usize) callconv(.C) [*]u8;
|
||||||
|
|
||||||
|
// Note: this is written to only support little endian targets.
|
||||||
|
// To support big endian, `<<` and `>>` wold need to be swapped.
|
||||||
|
pub fn fallback_memcpy(noalias dest: [*]u8, noalias src: [*]const u8, len: usize) callconv(.C) [*]u8 {
|
||||||
|
var d = dest;
|
||||||
|
var s = src;
|
||||||
|
var n = len;
|
||||||
|
while (@ptrToInt(s) % 4 != 0 and n != 0) : (n -= 1) {
|
||||||
|
d[0] = s[0];
|
||||||
|
d += 1;
|
||||||
|
s += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (@ptrToInt(d) % 4 == 0) {
|
||||||
|
var d4 = @alignCast(4, d);
|
||||||
|
var s4 = @alignCast(4, s);
|
||||||
|
while (n >= 16) : (n -= 16) {
|
||||||
|
var d_u32 = @ptrCast([*]u32, d4);
|
||||||
|
var s_u32 = @ptrCast([*]const u32, s4);
|
||||||
|
d_u32[0] = s_u32[0];
|
||||||
|
d_u32[1] = s_u32[1];
|
||||||
|
d_u32[2] = s_u32[2];
|
||||||
|
d_u32[3] = s_u32[3];
|
||||||
|
|
||||||
|
d4 += 16;
|
||||||
|
s4 += 16;
|
||||||
|
}
|
||||||
|
if (n & 8 != 0) {
|
||||||
|
var d_u32 = @ptrCast([*]u32, d4);
|
||||||
|
var s_u32 = @ptrCast([*]const u32, s4);
|
||||||
|
d_u32[0] = s_u32[0];
|
||||||
|
d_u32[1] = s_u32[1];
|
||||||
|
|
||||||
|
d4 += 8;
|
||||||
|
s4 += 8;
|
||||||
|
}
|
||||||
|
if (n & 4 != 0) {
|
||||||
|
var d_u32 = @ptrCast([*]u32, d4);
|
||||||
|
var s_u32 = @ptrCast([*]const u32, s4);
|
||||||
|
d_u32[0] = s_u32[0];
|
||||||
|
|
||||||
|
d4 += 4;
|
||||||
|
s4 += 4;
|
||||||
|
}
|
||||||
|
d = d4;
|
||||||
|
s = s4;
|
||||||
|
if (n & 2 != 0) {
|
||||||
|
d[0] = s[0];
|
||||||
|
d += 1;
|
||||||
|
s += 1;
|
||||||
|
d[0] = s[0];
|
||||||
|
d += 1;
|
||||||
|
s += 1;
|
||||||
|
}
|
||||||
|
if (n & 1 != 0) {
|
||||||
|
d[0] = s[0];
|
||||||
|
}
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
if (n >= 32) {
|
||||||
|
switch (@ptrToInt(d) % 4) {
|
||||||
|
1 => {
|
||||||
|
var w = @ptrCast([*]const u32, @alignCast(4, s))[0];
|
||||||
|
d[0] = s[0];
|
||||||
|
d += 1;
|
||||||
|
s += 1;
|
||||||
|
d[0] = s[0];
|
||||||
|
d += 1;
|
||||||
|
s += 1;
|
||||||
|
d[0] = s[0];
|
||||||
|
d += 1;
|
||||||
|
s += 1;
|
||||||
|
n -= 3;
|
||||||
|
while (n >= 17) : (n -= 16) {
|
||||||
|
var d_u32 = @ptrCast([*]u32, @alignCast(4, d));
|
||||||
|
var s_u32 = @ptrCast([*]const u32, @alignCast(4, s + 1));
|
||||||
|
var x = s_u32[0];
|
||||||
|
d_u32[0] = (w >> 24) | (x << 8);
|
||||||
|
w = s_u32[1];
|
||||||
|
d_u32[1] = (x >> 24) | (w << 8);
|
||||||
|
x = s_u32[2];
|
||||||
|
d_u32[2] = (w >> 24) | (x << 8);
|
||||||
|
w = s_u32[3];
|
||||||
|
d_u32[3] = (x >> 24) | (w << 8);
|
||||||
|
|
||||||
|
d += 16;
|
||||||
|
s += 16;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
2 => {
|
||||||
|
var w = @ptrCast([*]const u32, @alignCast(4, s))[0];
|
||||||
|
d[0] = s[0];
|
||||||
|
d += 1;
|
||||||
|
s += 1;
|
||||||
|
d[0] = s[0];
|
||||||
|
d += 1;
|
||||||
|
s += 1;
|
||||||
|
n -= 2;
|
||||||
|
while (n >= 18) : (n -= 16) {
|
||||||
|
var d_u32 = @ptrCast([*]u32, @alignCast(4, d));
|
||||||
|
var s_u32 = @ptrCast([*]const u32, @alignCast(4, s + 2));
|
||||||
|
var x = s_u32[0];
|
||||||
|
d_u32[0] = (w >> 16) | (x << 16);
|
||||||
|
w = s_u32[1];
|
||||||
|
d_u32[1] = (x >> 16) | (w << 16);
|
||||||
|
x = s_u32[2];
|
||||||
|
d_u32[2] = (w >> 16) | (x << 16);
|
||||||
|
w = s_u32[3];
|
||||||
|
d_u32[3] = (x >> 16) | (w << 16);
|
||||||
|
|
||||||
|
d += 16;
|
||||||
|
s += 16;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
3 => {
|
||||||
|
var w = @ptrCast([*]const u32, @alignCast(4, s))[0];
|
||||||
|
d[0] = s[0];
|
||||||
|
d += 1;
|
||||||
|
s += 1;
|
||||||
|
n -= 1;
|
||||||
|
while (n >= 19) : (n -= 16) {
|
||||||
|
var d_u32 = @ptrCast([*]u32, @alignCast(4, d));
|
||||||
|
var s_u32 = @ptrCast([*]const u32, @alignCast(4, s + 3));
|
||||||
|
var x = s_u32[0];
|
||||||
|
d_u32[0] = (w >> 8) | (x << 24);
|
||||||
|
w = s_u32[1];
|
||||||
|
d_u32[1] = (x >> 8) | (w << 24);
|
||||||
|
x = s_u32[2];
|
||||||
|
d_u32[2] = (w >> 8) | (x << 24);
|
||||||
|
w = s_u32[3];
|
||||||
|
d_u32[3] = (x >> 8) | (w << 24);
|
||||||
|
|
||||||
|
d += 16;
|
||||||
|
s += 16;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (n & 16 != 0) {
|
||||||
|
comptime var i = 0;
|
||||||
|
inline while (i < 16) : (i += 1) {
|
||||||
|
d[0] = s[0];
|
||||||
|
d += 1;
|
||||||
|
s += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (n & 8 != 0) {
|
||||||
|
comptime var i = 0;
|
||||||
|
inline while (i < 8) : (i += 1) {
|
||||||
|
d[0] = s[0];
|
||||||
|
d += 1;
|
||||||
|
s += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (n & 4 != 0) {
|
||||||
|
comptime var i = 0;
|
||||||
|
inline while (i < 4) : (i += 1) {
|
||||||
|
d[0] = s[0];
|
||||||
|
d += 1;
|
||||||
|
s += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (n & 2 != 0) {
|
||||||
|
d[0] = s[0];
|
||||||
|
d += 1;
|
||||||
|
s += 1;
|
||||||
|
d[0] = s[0];
|
||||||
|
d += 1;
|
||||||
|
s += 1;
|
||||||
|
}
|
||||||
|
if (n & 1 != 0) {
|
||||||
|
d[0] = s[0];
|
||||||
|
}
|
||||||
|
return dest;
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ const panic_utils = @import("panic.zig");
|
||||||
|
|
||||||
comptime {
|
comptime {
|
||||||
_ = @import("compiler_rt.zig");
|
_ = @import("compiler_rt.zig");
|
||||||
|
_ = @import("libc.zig");
|
||||||
}
|
}
|
||||||
|
|
||||||
const ROC_BUILTINS = "roc_builtins";
|
const ROC_BUILTINS = "roc_builtins";
|
||||||
|
|
|
@ -19,9 +19,6 @@ extern fn roc_realloc(c_ptr: *anyopaque, new_size: usize, old_size: usize, align
|
||||||
// This should never be passed a null pointer.
|
// This should never be passed a null pointer.
|
||||||
extern fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void;
|
extern fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void;
|
||||||
|
|
||||||
// should work just like libc memcpy (we can't assume libc is present)
|
|
||||||
extern fn roc_memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void;
|
|
||||||
|
|
||||||
extern fn kill(pid: c_int, sig: c_int) c_int;
|
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 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 mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) *anyopaque;
|
||||||
|
@ -49,7 +46,6 @@ comptime {
|
||||||
@export(testing_roc_realloc, .{ .name = "roc_realloc", .linkage = .Strong });
|
@export(testing_roc_realloc, .{ .name = "roc_realloc", .linkage = .Strong });
|
||||||
@export(testing_roc_dealloc, .{ .name = "roc_dealloc", .linkage = .Strong });
|
@export(testing_roc_dealloc, .{ .name = "roc_dealloc", .linkage = .Strong });
|
||||||
@export(testing_roc_panic, .{ .name = "roc_panic", .linkage = .Strong });
|
@export(testing_roc_panic, .{ .name = "roc_panic", .linkage = .Strong });
|
||||||
@export(testing_roc_memcpy, .{ .name = "roc_memcpy", .linkage = .Strong });
|
|
||||||
|
|
||||||
if (builtin.os.tag == .macos or builtin.os.tag == .linux) {
|
if (builtin.os.tag == .macos or builtin.os.tag == .linux) {
|
||||||
@export(testing_roc_getppid, .{ .name = "roc_getppid", .linkage = .Strong });
|
@export(testing_roc_getppid, .{ .name = "roc_getppid", .linkage = .Strong });
|
||||||
|
@ -83,14 +79,6 @@ fn testing_roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void {
|
||||||
@panic("Roc panicked");
|
@panic("Roc panicked");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn testing_roc_memcpy(dest: *anyopaque, src: *anyopaque, bytes: usize) callconv(.C) ?*anyopaque {
|
|
||||||
const zig_dest = @ptrCast([*]u8, dest);
|
|
||||||
const zig_src = @ptrCast([*]u8, src);
|
|
||||||
|
|
||||||
@memcpy(zig_dest, zig_src, bytes);
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn alloc(size: usize, alignment: u32) ?[*]u8 {
|
pub fn alloc(size: usize, alignment: u32) ?[*]u8 {
|
||||||
return @ptrCast(?[*]u8, roc_alloc(size, alignment));
|
return @ptrCast(?[*]u8, roc_alloc(size, alignment));
|
||||||
}
|
}
|
||||||
|
@ -103,10 +91,6 @@ pub fn dealloc(c_ptr: [*]u8, alignment: u32) void {
|
||||||
return roc_dealloc(c_ptr, alignment);
|
return roc_dealloc(c_ptr, alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn memcpy(dst: [*]u8, src: [*]u8, size: usize) void {
|
|
||||||
roc_memcpy(dst, src, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// indirection because otherwise zig creates an alias to the panic function which our LLVM code
|
// indirection because otherwise zig creates an alias to the panic function which our LLVM code
|
||||||
// does not know how to deal with
|
// does not know how to deal with
|
||||||
pub fn test_panic(c_ptr: *anyopaque, crash_tag: u32) callconv(.C) void {
|
pub fn test_panic(c_ptr: *anyopaque, crash_tag: u32) callconv(.C) void {
|
||||||
|
|
|
@ -124,18 +124,19 @@ impl<'a> Env<'a> {
|
||||||
Ok(symbol)
|
Ok(symbol)
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let error = RuntimeError::LookupNotInScope(
|
let error = RuntimeError::LookupNotInScope {
|
||||||
Loc {
|
loc_name: Loc {
|
||||||
value: Ident::from(ident),
|
value: Ident::from(ident),
|
||||||
region,
|
region,
|
||||||
},
|
},
|
||||||
scope
|
suggestion_options: scope
|
||||||
.locals
|
.locals
|
||||||
.ident_ids
|
.ident_ids
|
||||||
.ident_strs()
|
.ident_strs()
|
||||||
.map(|(_, string)| string.into())
|
.map(|(_, string)| string.into())
|
||||||
.collect(),
|
.collect(),
|
||||||
);
|
underscored_suggestion_region: None,
|
||||||
|
};
|
||||||
Err(error)
|
Err(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1019,9 +1019,18 @@ pub fn canonicalize_expr<'a>(
|
||||||
}
|
}
|
||||||
ast::Expr::Underscore(name) => {
|
ast::Expr::Underscore(name) => {
|
||||||
// we parse underscores, but they are not valid expression syntax
|
// we parse underscores, but they are not valid expression syntax
|
||||||
|
|
||||||
let problem = roc_problem::can::RuntimeError::MalformedIdentifier(
|
let problem = roc_problem::can::RuntimeError::MalformedIdentifier(
|
||||||
(*name).into(),
|
(*name).into(),
|
||||||
roc_parse::ident::BadIdent::Underscore(region.start()),
|
if name.is_empty() {
|
||||||
|
roc_parse::ident::BadIdent::UnderscoreAlone(region.start())
|
||||||
|
} else {
|
||||||
|
roc_parse::ident::BadIdent::UnderscoreAtStart {
|
||||||
|
position: region.start(),
|
||||||
|
// Check if there's an ignored identifier with this name in scope (for better error messages)
|
||||||
|
declaration_region: scope.lookup_ignored_local(name),
|
||||||
|
}
|
||||||
|
},
|
||||||
region,
|
region,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -379,6 +379,12 @@ pub fn canonicalize_pattern<'a>(
|
||||||
Err(pattern) => pattern,
|
Err(pattern) => pattern,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Underscore(name) => {
|
||||||
|
// An underscored identifier can't be used, but we'll still add it to the scope
|
||||||
|
// for better error messages if someone tries to use it.
|
||||||
|
scope.introduce_ignored_local(name, region);
|
||||||
|
Pattern::Underscore
|
||||||
|
}
|
||||||
Tag(name) => {
|
Tag(name) => {
|
||||||
// Canonicalize the tag's name.
|
// Canonicalize the tag's name.
|
||||||
Pattern::AppliedTag {
|
Pattern::AppliedTag {
|
||||||
|
@ -479,8 +485,6 @@ pub fn canonicalize_pattern<'a>(
|
||||||
ptype => unsupported_pattern(env, ptype, region),
|
ptype => unsupported_pattern(env, ptype, region),
|
||||||
},
|
},
|
||||||
|
|
||||||
Underscore(_) => Pattern::Underscore,
|
|
||||||
|
|
||||||
&NumLiteral(str) => match pattern_type {
|
&NumLiteral(str) => match pattern_type {
|
||||||
WhenBranch => match finish_parsing_num(str) {
|
WhenBranch => match finish_parsing_num(str) {
|
||||||
Err(_error) => {
|
Err(_error) => {
|
||||||
|
|
|
@ -41,6 +41,10 @@ pub struct Scope {
|
||||||
|
|
||||||
/// Identifiers that are in scope, and defined in the current module
|
/// Identifiers that are in scope, and defined in the current module
|
||||||
pub locals: ScopedIdentIds,
|
pub locals: ScopedIdentIds,
|
||||||
|
|
||||||
|
/// Ignored variables (variables that start with an underscore).
|
||||||
|
/// We won't intern them because they're only used during canonicalization for error reporting.
|
||||||
|
ignored_locals: VecMap<String, Region>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scope {
|
impl Scope {
|
||||||
|
@ -65,6 +69,7 @@ impl Scope {
|
||||||
abilities_store: starting_abilities_store,
|
abilities_store: starting_abilities_store,
|
||||||
shadows: VecMap::default(),
|
shadows: VecMap::default(),
|
||||||
imports: default_imports,
|
imports: default_imports,
|
||||||
|
ignored_locals: VecMap::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,13 +94,17 @@ impl Scope {
|
||||||
match self.scope_contains_ident(ident) {
|
match self.scope_contains_ident(ident) {
|
||||||
InScope(symbol, _) => Ok(symbol),
|
InScope(symbol, _) => Ok(symbol),
|
||||||
NotInScope(_) | NotPresent => {
|
NotInScope(_) | NotPresent => {
|
||||||
let error = RuntimeError::LookupNotInScope(
|
// identifier not found
|
||||||
Loc {
|
|
||||||
|
let error = RuntimeError::LookupNotInScope {
|
||||||
|
loc_name: Loc {
|
||||||
region,
|
region,
|
||||||
value: Ident::from(ident),
|
value: Ident::from(ident),
|
||||||
},
|
},
|
||||||
self.idents_in_scope().map(|v| v.as_ref().into()).collect(),
|
suggestion_options: self.idents_in_scope().map(|v| v.as_ref().into()).collect(),
|
||||||
);
|
// Check if the user just forgot to remove an underscore from an ignored identifier
|
||||||
|
underscored_suggestion_region: self.lookup_ignored_local(ident),
|
||||||
|
};
|
||||||
|
|
||||||
Err(error)
|
Err(error)
|
||||||
}
|
}
|
||||||
|
@ -418,11 +427,13 @@ impl Scope {
|
||||||
// - exposed_ident_count: unchanged
|
// - exposed_ident_count: unchanged
|
||||||
// - home: unchanged
|
// - home: unchanged
|
||||||
let aliases_count = self.aliases.len();
|
let aliases_count = self.aliases.len();
|
||||||
|
let ignored_locals_count = self.ignored_locals.len();
|
||||||
let locals_snapshot = self.locals.in_scope.len();
|
let locals_snapshot = self.locals.in_scope.len();
|
||||||
|
|
||||||
let result = f(self);
|
let result = f(self);
|
||||||
|
|
||||||
self.aliases.truncate(aliases_count);
|
self.aliases.truncate(aliases_count);
|
||||||
|
self.ignored_locals.truncate(ignored_locals_count);
|
||||||
|
|
||||||
// anything added in the inner scope is no longer in scope now
|
// anything added in the inner scope is no longer in scope now
|
||||||
for i in locals_snapshot..self.locals.in_scope.len() {
|
for i in locals_snapshot..self.locals.in_scope.len() {
|
||||||
|
@ -444,6 +455,19 @@ impl Scope {
|
||||||
pub fn gen_unique_symbol(&mut self) -> Symbol {
|
pub fn gen_unique_symbol(&mut self) -> Symbol {
|
||||||
Symbol::new(self.home, self.locals.gen_unique())
|
Symbol::new(self.home, self.locals.gen_unique())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Introduce a new ignored variable (variable starting with an underscore).
|
||||||
|
/// The underscore itself should not be included in `ident`.
|
||||||
|
pub fn introduce_ignored_local(&mut self, ident: &str, region: Region) {
|
||||||
|
self.ignored_locals.insert(ident.to_owned(), region);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Lookup an ignored variable (variable starting with an underscore).
|
||||||
|
/// The underscore itself should not be included in `ident`.
|
||||||
|
/// Returns the source code region of the ignored variable if it's found.
|
||||||
|
pub fn lookup_ignored_local(&self, ident: &str) -> Option<Region> {
|
||||||
|
self.ignored_locals.get(&ident.to_owned()).copied()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_alias(
|
pub fn create_alias(
|
||||||
|
|
|
@ -332,7 +332,7 @@ mod test_can {
|
||||||
matches!(
|
matches!(
|
||||||
problem,
|
problem,
|
||||||
Problem::SignatureDefMismatch { .. }
|
Problem::SignatureDefMismatch { .. }
|
||||||
| Problem::RuntimeError(RuntimeError::LookupNotInScope(_, _))
|
| Problem::RuntimeError(RuntimeError::LookupNotInScope { .. })
|
||||||
)
|
)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -360,7 +360,7 @@ mod test_can {
|
||||||
matches!(
|
matches!(
|
||||||
problem,
|
problem,
|
||||||
Problem::SignatureDefMismatch { .. }
|
Problem::SignatureDefMismatch { .. }
|
||||||
| Problem::RuntimeError(RuntimeError::LookupNotInScope(_, _))
|
| Problem::RuntimeError(RuntimeError::LookupNotInScope { .. })
|
||||||
)
|
)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
@ -761,7 +761,15 @@ fn remove_spaces_bad_ident(ident: BadIdent) -> BadIdent {
|
||||||
match ident {
|
match ident {
|
||||||
BadIdent::Start(_) => BadIdent::Start(Position::zero()),
|
BadIdent::Start(_) => BadIdent::Start(Position::zero()),
|
||||||
BadIdent::Space(e, _) => BadIdent::Space(e, Position::zero()),
|
BadIdent::Space(e, _) => BadIdent::Space(e, Position::zero()),
|
||||||
BadIdent::Underscore(_) => BadIdent::Underscore(Position::zero()),
|
BadIdent::UnderscoreAlone(_) => BadIdent::UnderscoreAlone(Position::zero()),
|
||||||
|
BadIdent::UnderscoreInMiddle(_) => BadIdent::UnderscoreInMiddle(Position::zero()),
|
||||||
|
BadIdent::UnderscoreAtStart {
|
||||||
|
position: _,
|
||||||
|
declaration_region,
|
||||||
|
} => BadIdent::UnderscoreAtStart {
|
||||||
|
position: Position::zero(),
|
||||||
|
declaration_region,
|
||||||
|
},
|
||||||
BadIdent::QualifiedTag(_) => BadIdent::QualifiedTag(Position::zero()),
|
BadIdent::QualifiedTag(_) => BadIdent::QualifiedTag(Position::zero()),
|
||||||
BadIdent::WeirdAccessor(_) => BadIdent::WeirdAccessor(Position::zero()),
|
BadIdent::WeirdAccessor(_) => BadIdent::WeirdAccessor(Position::zero()),
|
||||||
BadIdent::WeirdDotAccess(_) => BadIdent::WeirdDotAccess(Position::zero()),
|
BadIdent::WeirdDotAccess(_) => BadIdent::WeirdDotAccess(Position::zero()),
|
||||||
|
|
|
@ -2859,7 +2859,15 @@ pub fn build_exp_stmt<'a, 'ctx>(
|
||||||
|
|
||||||
_ if lay.is_refcounted() => {
|
_ if lay.is_refcounted() => {
|
||||||
if value.is_pointer_value() {
|
if value.is_pointer_value() {
|
||||||
let value_ptr = value.into_pointer_value();
|
let value_ptr = match lay.repr {
|
||||||
|
LayoutRepr::Union(union_layout)
|
||||||
|
if union_layout
|
||||||
|
.stores_tag_id_in_pointer(env.target_info) =>
|
||||||
|
{
|
||||||
|
tag_pointer_clear_tag_id(env, value.into_pointer_value())
|
||||||
|
}
|
||||||
|
_ => value.into_pointer_value(),
|
||||||
|
};
|
||||||
|
|
||||||
let then_block = env.context.append_basic_block(parent, "then");
|
let then_block = env.context.append_basic_block(parent, "then");
|
||||||
let done_block = env.context.append_basic_block(parent, "done");
|
let done_block = env.context.append_basic_block(parent, "done");
|
||||||
|
|
|
@ -289,11 +289,6 @@ mod dummy_platform_functions {
|
||||||
unimplemented!("It is not valid to call roc panic from within the compiler. Please use the \"platform\" feature if this is a platform.")
|
unimplemented!("It is not valid to call roc panic from within the compiler. Please use the \"platform\" feature if this is a platform.")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub fn roc_memcpy(_dst: *mut c_void, _src: *mut c_void, _n: usize) -> *mut c_void {
|
|
||||||
unimplemented!("It is not valid to call roc memcpy from within the compiler. Please use the \"platform\" feature if this is a platform.")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn roc_memset(_dst: *mut c_void, _c: i32, _n: usize) -> *mut c_void {
|
pub fn roc_memset(_dst: *mut c_void, _c: i32, _n: usize) -> *mut c_void {
|
||||||
unimplemented!("It is not valid to call roc memset from within the compiler. Please use the \"platform\" feature if this is a platform.")
|
unimplemented!("It is not valid to call roc memset from within the compiler. Please use the \"platform\" feature if this is a platform.")
|
||||||
|
|
|
@ -53,6 +53,8 @@ use roc_parse::module::module_defs;
|
||||||
use roc_parse::parser::{FileError, Parser, SourceError, SyntaxError};
|
use roc_parse::parser::{FileError, Parser, SourceError, SyntaxError};
|
||||||
use roc_problem::Severity;
|
use roc_problem::Severity;
|
||||||
use roc_region::all::{LineInfo, Loc, Region};
|
use roc_region::all::{LineInfo, Loc, Region};
|
||||||
|
#[cfg(not(target_family = "wasm"))]
|
||||||
|
use roc_reporting::report::to_https_problem_report_string;
|
||||||
use roc_reporting::report::{to_file_problem_report_string, Palette, RenderTarget};
|
use roc_reporting::report::{to_file_problem_report_string, Palette, RenderTarget};
|
||||||
use roc_solve::module::{extract_module_owned_implementations, Solved, SolvedModule};
|
use roc_solve::module::{extract_module_owned_implementations, Solved, SolvedModule};
|
||||||
use roc_solve_problem::TypeError;
|
use roc_solve_problem::TypeError;
|
||||||
|
@ -72,7 +74,7 @@ use std::{env, fs};
|
||||||
#[cfg(not(target_family = "wasm"))]
|
#[cfg(not(target_family = "wasm"))]
|
||||||
use {
|
use {
|
||||||
roc_packaging::cache::{self},
|
roc_packaging::cache::{self},
|
||||||
roc_packaging::https::PackageMetadata,
|
roc_packaging::https::{PackageMetadata, Problem},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use crate::work::Phase;
|
pub use crate::work::Phase;
|
||||||
|
@ -2454,11 +2456,11 @@ fn update<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(url_err) => {
|
Err(url_err) => {
|
||||||
todo!(
|
let buf = to_https_problem_report_string(
|
||||||
"Gracefully report URL error for {:?} - {:?}",
|
|
||||||
url,
|
url,
|
||||||
url_err
|
Problem::InvalidUrl(url_err),
|
||||||
);
|
);
|
||||||
|
return Err(LoadingProblem::FormattedReport(buf));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4329,17 +4331,22 @@ fn load_packages<'a>(
|
||||||
// TODO we should do this async; however, with the current
|
// TODO we should do this async; however, with the current
|
||||||
// architecture of file.rs (which doesn't use async/await),
|
// architecture of file.rs (which doesn't use async/await),
|
||||||
// this would be very difficult!
|
// this would be very difficult!
|
||||||
let (package_dir, opt_root_module) = cache::install_package(roc_cache_dir, src)
|
match cache::install_package(roc_cache_dir, src) {
|
||||||
.unwrap_or_else(|err| {
|
Ok((package_dir, opt_root_module)) => {
|
||||||
todo!("TODO gracefully handle package install error {:?}", err);
|
// You can optionally specify the root module using the URL fragment,
|
||||||
});
|
// e.g. #foo.roc
|
||||||
|
// (defaults to main.roc)
|
||||||
|
match opt_root_module {
|
||||||
|
Some(root_module) => package_dir.join(root_module),
|
||||||
|
None => package_dir.join("main.roc"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(problem) => {
|
||||||
|
let buf = to_https_problem_report_string(src, problem);
|
||||||
|
|
||||||
// You can optionally specify the root module using the URL fragment,
|
load_messages.push(Msg::FailedToLoad(LoadingProblem::FormattedReport(buf)));
|
||||||
// e.g. #foo.roc
|
return;
|
||||||
// (defaults to main.roc)
|
}
|
||||||
match opt_root_module {
|
|
||||||
Some(root_module) => package_dir.join(root_module),
|
|
||||||
None => package_dir.join("main.roc"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::parser::{BadInputError, EExpr, ParseResult, Parser};
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
use bumpalo::collections::vec::Vec;
|
use bumpalo::collections::vec::Vec;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_region::all::Position;
|
use roc_region::all::{Position, Region};
|
||||||
|
|
||||||
/// A tag, for example. Must start with an uppercase letter
|
/// A tag, for example. Must start with an uppercase letter
|
||||||
/// and then contain only letters and numbers afterwards - no dots allowed!
|
/// and then contain only letters and numbers afterwards - no dots allowed!
|
||||||
|
@ -254,7 +254,14 @@ pub enum BadIdent {
|
||||||
Start(Position),
|
Start(Position),
|
||||||
Space(BadInputError, Position),
|
Space(BadInputError, Position),
|
||||||
|
|
||||||
Underscore(Position),
|
UnderscoreAlone(Position),
|
||||||
|
UnderscoreInMiddle(Position),
|
||||||
|
UnderscoreAtStart {
|
||||||
|
position: Position,
|
||||||
|
/// If this variable was already declared in a pattern (e.g. \_x -> _x),
|
||||||
|
/// then this is where it was declared.
|
||||||
|
declaration_region: Option<Region>,
|
||||||
|
},
|
||||||
QualifiedTag(Position),
|
QualifiedTag(Position),
|
||||||
WeirdAccessor(Position),
|
WeirdAccessor(Position),
|
||||||
WeirdDotAccess(Position),
|
WeirdDotAccess(Position),
|
||||||
|
@ -529,7 +536,7 @@ fn chomp_identifier_chain<'a>(
|
||||||
// to give good error messages for this case
|
// to give good error messages for this case
|
||||||
Err((
|
Err((
|
||||||
chomped as u32 + 1,
|
chomped as u32 + 1,
|
||||||
BadIdent::Underscore(pos.bump_column(chomped as u32 + 1)),
|
BadIdent::UnderscoreInMiddle(pos.bump_column(chomped as u32 + 1)),
|
||||||
))
|
))
|
||||||
} else if first_is_uppercase {
|
} else if first_is_uppercase {
|
||||||
// just one segment, starting with an uppercase letter; that's a tag
|
// just one segment, starting with an uppercase letter; that's a tag
|
||||||
|
|
|
@ -335,7 +335,11 @@ impl Problem {
|
||||||
})
|
})
|
||||||
| Problem::RuntimeError(RuntimeError::UnsupportedPattern(region))
|
| Problem::RuntimeError(RuntimeError::UnsupportedPattern(region))
|
||||||
| Problem::RuntimeError(RuntimeError::MalformedPattern(_, region))
|
| Problem::RuntimeError(RuntimeError::MalformedPattern(_, region))
|
||||||
| Problem::RuntimeError(RuntimeError::LookupNotInScope(Loc { region, .. }, _))
|
| Problem::RuntimeError(RuntimeError::LookupNotInScope {
|
||||||
|
loc_name: Loc { region, .. },
|
||||||
|
suggestion_options: _,
|
||||||
|
underscored_suggestion_region: _,
|
||||||
|
})
|
||||||
| Problem::RuntimeError(RuntimeError::OpaqueNotDefined {
|
| Problem::RuntimeError(RuntimeError::OpaqueNotDefined {
|
||||||
usage: Loc { region, .. },
|
usage: Loc { region, .. },
|
||||||
..
|
..
|
||||||
|
@ -505,7 +509,14 @@ pub enum RuntimeError {
|
||||||
UnresolvedTypeVar,
|
UnresolvedTypeVar,
|
||||||
ErroneousType,
|
ErroneousType,
|
||||||
|
|
||||||
LookupNotInScope(Loc<Ident>, MutSet<Box<str>>),
|
LookupNotInScope {
|
||||||
|
loc_name: Loc<Ident>,
|
||||||
|
/// All of the names in scope (for the error message)
|
||||||
|
suggestion_options: MutSet<Box<str>>,
|
||||||
|
/// If the unfound variable is `name` and there's an ignored variable called `_name`,
|
||||||
|
/// this is the region where `_name` is defined (for the error message)
|
||||||
|
underscored_suggestion_region: Option<Region>,
|
||||||
|
},
|
||||||
OpaqueNotDefined {
|
OpaqueNotDefined {
|
||||||
usage: Loc<Ident>,
|
usage: Loc<Ident>,
|
||||||
opaques_in_scope: MutSet<Box<str>>,
|
opaques_in_scope: MutSet<Box<str>>,
|
||||||
|
|
|
@ -14,6 +14,8 @@ use roc_mono::layout::{LayoutRepr, STLayoutInterner};
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use roc_std::{RocList, RocStr, U128};
|
use roc_std::{RocList, RocStr, U128};
|
||||||
|
|
||||||
|
use crate::helpers::with_larger_debug_stack;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn width_and_alignment_u8_u8() {
|
fn width_and_alignment_u8_u8() {
|
||||||
use roc_mono::layout::Layout;
|
use roc_mono::layout::Layout;
|
||||||
|
@ -2167,27 +2169,29 @@ fn refcount_nullable_unwrapped_needing_no_refcount_issue_5027() {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
fn issue_5162_recast_nested_nullable_unwrapped_layout() {
|
fn issue_5162_recast_nested_nullable_unwrapped_layout() {
|
||||||
assert_evals_to!(
|
with_larger_debug_stack(|| {
|
||||||
indoc!(
|
assert_evals_to!(
|
||||||
r###"
|
indoc!(
|
||||||
app "test" provides [main] to "./platform"
|
r###"
|
||||||
|
app "test" provides [main] to "./platform"
|
||||||
|
|
||||||
Concept : [
|
Concept : [
|
||||||
AtomicConcept,
|
AtomicConcept,
|
||||||
ExistentialRestriction { role : Str, concept : Concept }
|
ExistentialRestriction { role : Str, concept : Concept }
|
||||||
]
|
]
|
||||||
|
|
||||||
bottom : Concept
|
bottom : Concept
|
||||||
bottom = AtomicConcept
|
bottom = AtomicConcept
|
||||||
|
|
||||||
main =
|
main =
|
||||||
when Dict.single bottom 0 is
|
when Dict.single bottom 0 is
|
||||||
_ -> Bool.true
|
_ -> Bool.true
|
||||||
"###
|
"###
|
||||||
),
|
),
|
||||||
true,
|
true,
|
||||||
bool
|
bool
|
||||||
);
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -7,13 +7,6 @@ pub unsafe fn roc_alloc(size: usize, _alignment: u32) -> *mut c_void {
|
||||||
libc::malloc(size)
|
libc::malloc(size)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
/// The Roc application needs this.
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe fn roc_memcpy(dest: *mut c_void, src: *const c_void, bytes: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dest, src, bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// The Roc application needs this.
|
/// The Roc application needs this.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|
|
@ -134,13 +134,6 @@ void roc_panic(void* msg, unsigned int tag_id)
|
||||||
|
|
||||||
//--------------------------
|
//--------------------------
|
||||||
|
|
||||||
void roc_memcpy(void *dest, const void *src, size_t n)
|
|
||||||
{
|
|
||||||
memcpy(dest, src, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------
|
|
||||||
|
|
||||||
void *roc_memset(void *str, int c, size_t n)
|
void *roc_memset(void *str, int c, size_t n)
|
||||||
{
|
{
|
||||||
return memset(str, c, n);
|
return memset(str, c, n);
|
||||||
|
|
|
@ -2,7 +2,7 @@ Closure(
|
||||||
[
|
[
|
||||||
@1-11 MalformedIdent(
|
@1-11 MalformedIdent(
|
||||||
"the_answer",
|
"the_answer",
|
||||||
Underscore(
|
UnderscoreInMiddle(
|
||||||
@5,
|
@5,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -31,7 +31,7 @@ Defs(
|
||||||
@5-8 SpaceBefore(
|
@5-8 SpaceBefore(
|
||||||
MalformedIdent(
|
MalformedIdent(
|
||||||
"n_p",
|
"n_p",
|
||||||
Underscore(
|
UnderscoreInMiddle(
|
||||||
@7,
|
@7,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -78,11 +78,6 @@ pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dst, src, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
||||||
libc::memset(dst, c, n)
|
libc::memset(dst, c, n)
|
||||||
|
|
|
@ -49,11 +49,6 @@ pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dst, src, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
||||||
libc::memset(dst, c, n)
|
libc::memset(dst, c, n)
|
||||||
|
|
|
@ -71,11 +71,6 @@ pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dst, src, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
||||||
libc::memset(dst, c, n)
|
libc::memset(dst, c, n)
|
||||||
|
|
|
@ -13,7 +13,7 @@ pub extern "C" fn rust_main() -> i32 {
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::hash_set::HashSet;
|
use std::collections::hash_set::HashSet;
|
||||||
|
|
||||||
let tag_union = test_glue::mainForHost(());
|
let tag_union = test_glue::mainForHost(());
|
||||||
|
|
||||||
// Verify that it has all the expected traits.
|
// Verify that it has all the expected traits.
|
||||||
|
|
||||||
|
@ -89,11 +89,6 @@ pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dst, src, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
||||||
libc::memset(dst, c, n)
|
libc::memset(dst, c, n)
|
||||||
|
|
|
@ -75,11 +75,6 @@ pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dst, src, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
||||||
libc::memset(dst, c, n)
|
libc::memset(dst, c, n)
|
||||||
|
|
|
@ -88,11 +88,6 @@ pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dst, src, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
||||||
libc::memset(dst, c, n)
|
libc::memset(dst, c, n)
|
||||||
|
|
|
@ -76,11 +76,6 @@ pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dst, src, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
||||||
libc::memset(dst, c, n)
|
libc::memset(dst, c, n)
|
||||||
|
|
|
@ -73,11 +73,6 @@ pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dst, src, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
||||||
libc::memset(dst, c, n)
|
libc::memset(dst, c, n)
|
||||||
|
|
|
@ -91,11 +91,6 @@ pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dst, src, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
||||||
libc::memset(dst, c, n)
|
libc::memset(dst, c, n)
|
||||||
|
|
|
@ -87,11 +87,6 @@ pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dst, src, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
||||||
libc::memset(dst, c, n)
|
libc::memset(dst, c, n)
|
||||||
|
|
|
@ -102,11 +102,6 @@ pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dst, src, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
||||||
libc::memset(dst, c, n)
|
libc::memset(dst, c, n)
|
||||||
|
|
5
crates/glue/tests/fixtures/option/src/lib.rs
vendored
5
crates/glue/tests/fixtures/option/src/lib.rs
vendored
|
@ -51,11 +51,6 @@ pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dst, src, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
||||||
libc::memset(dst, c, n)
|
libc::memset(dst, c, n)
|
||||||
|
|
|
@ -51,11 +51,6 @@ pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dst, src, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
||||||
libc::memset(dst, c, n)
|
libc::memset(dst, c, n)
|
||||||
|
|
|
@ -51,11 +51,6 @@ pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dst, src, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
||||||
libc::memset(dst, c, n)
|
libc::memset(dst, c, n)
|
||||||
|
|
|
@ -77,11 +77,6 @@ pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dst, src, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
||||||
libc::memset(dst, c, n)
|
libc::memset(dst, c, n)
|
||||||
|
|
|
@ -82,11 +82,6 @@ pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dst, src, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
||||||
libc::memset(dst, c, n)
|
libc::memset(dst, c, n)
|
||||||
|
|
|
@ -79,11 +79,6 @@ pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dst, src, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
||||||
libc::memset(dst, c, n)
|
libc::memset(dst, c, n)
|
||||||
|
|
|
@ -140,7 +140,6 @@ fn collect_roc_definitions<'a>(object: &object::File<'a, &'a [u8]>) -> MutMap<St
|
||||||
|
|
||||||
// special exceptions for roc_ functions that map to libc symbols
|
// special exceptions for roc_ functions that map to libc symbols
|
||||||
let direct_mapping = match name {
|
let direct_mapping = match name {
|
||||||
"roc_memcpy" => Some("memcpy"),
|
|
||||||
"roc_memset" => Some("memset"),
|
"roc_memset" => Some("memset"),
|
||||||
"roc_memmove" => Some("memmove"),
|
"roc_memmove" => Some("memmove"),
|
||||||
|
|
||||||
|
@ -603,7 +602,7 @@ fn gen_elf_le(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy header and shift everything to enable more program sections.
|
// Copy header and shift everything to enable more program sections.
|
||||||
let added_header_count = 2;
|
let added_header_count = 3;
|
||||||
md.added_byte_count = ph_ent_size as u64 * added_header_count;
|
md.added_byte_count = ph_ent_size as u64 * added_header_count;
|
||||||
md.added_byte_count = md.added_byte_count
|
md.added_byte_count = md.added_byte_count
|
||||||
+ (MIN_SECTION_ALIGNMENT as u64 - md.added_byte_count % MIN_SECTION_ALIGNMENT as u64);
|
+ (MIN_SECTION_ALIGNMENT as u64 - md.added_byte_count % MIN_SECTION_ALIGNMENT as u64);
|
||||||
|
@ -1278,22 +1277,12 @@ fn surgery_elf_help(
|
||||||
let mut offset = sh_offset as usize;
|
let mut offset = sh_offset as usize;
|
||||||
offset = align_by_constraint(offset, MIN_SECTION_ALIGNMENT);
|
offset = align_by_constraint(offset, MIN_SECTION_ALIGNMENT);
|
||||||
|
|
||||||
let new_rodata_section_offset = offset;
|
|
||||||
|
|
||||||
// Align physical and virtual address of new segment.
|
// Align physical and virtual address of new segment.
|
||||||
let mut virt_offset = align_to_offset_by_constraint(
|
let mut virt_offset = align_to_offset_by_constraint(
|
||||||
md.last_vaddr as usize,
|
md.last_vaddr as usize,
|
||||||
offset,
|
offset,
|
||||||
md.load_align_constraint as usize,
|
md.load_align_constraint as usize,
|
||||||
);
|
);
|
||||||
let new_rodata_section_vaddr = virt_offset;
|
|
||||||
if verbose {
|
|
||||||
println!();
|
|
||||||
println!(
|
|
||||||
"New Virtual Rodata Section Address: {:+x?}",
|
|
||||||
new_rodata_section_vaddr
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// First decide on sections locations and then recode every exact symbol locations.
|
// First decide on sections locations and then recode every exact symbol locations.
|
||||||
|
|
||||||
|
@ -1375,13 +1364,40 @@ fn surgery_elf_help(
|
||||||
println!("Found App Function Symbols: {:+x?}", app_func_vaddr_map);
|
println!("Found App Function Symbols: {:+x?}", app_func_vaddr_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let (new_rodata_section_offset, new_rodata_section_vaddr) = rodata_sections
|
||||||
|
.iter()
|
||||||
|
.map(|sec| section_offset_map.get(&sec.index()).unwrap())
|
||||||
|
.min()
|
||||||
|
.unwrap();
|
||||||
|
let (new_rodata_section_offset, new_rodata_section_vaddr) = (
|
||||||
|
*new_rodata_section_offset as u64,
|
||||||
|
*new_rodata_section_vaddr as u64,
|
||||||
|
);
|
||||||
let (new_text_section_offset, new_text_section_vaddr) = text_sections
|
let (new_text_section_offset, new_text_section_vaddr) = text_sections
|
||||||
.iter()
|
.iter()
|
||||||
.map(|sec| section_offset_map.get(&sec.index()).unwrap())
|
.map(|sec| section_offset_map.get(&sec.index()).unwrap())
|
||||||
.min()
|
.min()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let (new_text_section_offset, new_text_section_vaddr) =
|
let (new_text_section_offset, new_text_section_vaddr) = (
|
||||||
(*new_text_section_offset, *new_text_section_vaddr);
|
*new_text_section_offset as u64,
|
||||||
|
*new_text_section_vaddr as u64,
|
||||||
|
);
|
||||||
|
// BSS section is not guaranteed to exist.
|
||||||
|
// If it doesn't exist, just use the text section offset.
|
||||||
|
// This will make a bss section of size 0.
|
||||||
|
let bss_default = (
|
||||||
|
new_text_section_offset as usize,
|
||||||
|
new_text_section_vaddr as usize,
|
||||||
|
);
|
||||||
|
let (new_bss_section_offset, new_bss_section_vaddr) = bss_sections
|
||||||
|
.iter()
|
||||||
|
.map(|sec| section_offset_map.get(&sec.index()).unwrap())
|
||||||
|
.min()
|
||||||
|
.unwrap_or(&bss_default);
|
||||||
|
let (new_bss_section_offset, new_bss_section_vaddr) = (
|
||||||
|
*new_bss_section_offset as u64,
|
||||||
|
*new_bss_section_vaddr as u64,
|
||||||
|
);
|
||||||
|
|
||||||
// Move data and deal with relocations.
|
// Move data and deal with relocations.
|
||||||
for sec in rodata_sections
|
for sec in rodata_sections
|
||||||
|
@ -1494,15 +1510,15 @@ fn surgery_elf_help(
|
||||||
// Flush app only data to speed up write to disk.
|
// Flush app only data to speed up write to disk.
|
||||||
exec_mmap
|
exec_mmap
|
||||||
.flush_async_range(
|
.flush_async_range(
|
||||||
new_rodata_section_offset,
|
new_rodata_section_offset as usize,
|
||||||
offset - new_rodata_section_offset,
|
offset - new_rodata_section_offset as usize,
|
||||||
)
|
)
|
||||||
.unwrap_or_else(|e| internal_error!("{}", e));
|
.unwrap_or_else(|e| internal_error!("{}", e));
|
||||||
|
|
||||||
// TODO: look into merging symbol tables, debug info, and eh frames to enable better debugger experience.
|
// TODO: look into merging symbol tables, debug info, and eh frames to enable better debugger experience.
|
||||||
|
|
||||||
// Add 2 new sections and segments.
|
// Add 3 new sections and segments.
|
||||||
let new_section_count = 2;
|
let new_section_count = 3;
|
||||||
offset += new_section_count * sh_ent_size as usize;
|
offset += new_section_count * sh_ent_size as usize;
|
||||||
let section_headers = load_structs_inplace_mut::<elf::SectionHeader64<LE>>(
|
let section_headers = load_structs_inplace_mut::<elf::SectionHeader64<LE>>(
|
||||||
exec_mmap,
|
exec_mmap,
|
||||||
|
@ -1510,19 +1526,17 @@ fn surgery_elf_help(
|
||||||
sh_num as usize + new_section_count,
|
sh_num as usize + new_section_count,
|
||||||
);
|
);
|
||||||
|
|
||||||
let new_rodata_section_size = new_text_section_offset as u64 - new_rodata_section_offset as u64;
|
let new_rodata_section_size = new_text_section_offset - new_rodata_section_offset;
|
||||||
let new_rodata_section_virtual_size =
|
let new_bss_section_virtual_size = new_text_section_vaddr - new_bss_section_vaddr;
|
||||||
new_text_section_vaddr as u64 - new_rodata_section_vaddr as u64;
|
let new_text_section_size = new_sh_offset as u64 - new_text_section_offset;
|
||||||
let new_text_section_vaddr = new_rodata_section_vaddr as u64 + new_rodata_section_size;
|
|
||||||
let new_text_section_size = new_sh_offset as u64 - new_text_section_offset as u64;
|
|
||||||
|
|
||||||
// set the new rodata section header
|
// set the new rodata section header
|
||||||
section_headers[section_headers.len() - 2] = elf::SectionHeader64 {
|
section_headers[section_headers.len() - 3] = elf::SectionHeader64 {
|
||||||
sh_name: endian::U32::new(LE, 0),
|
sh_name: endian::U32::new(LE, 0),
|
||||||
sh_type: endian::U32::new(LE, elf::SHT_PROGBITS),
|
sh_type: endian::U32::new(LE, elf::SHT_PROGBITS),
|
||||||
sh_flags: endian::U64::new(LE, elf::SHF_ALLOC as u64),
|
sh_flags: endian::U64::new(LE, elf::SHF_ALLOC as u64),
|
||||||
sh_addr: endian::U64::new(LE, new_rodata_section_vaddr as u64),
|
sh_addr: endian::U64::new(LE, new_rodata_section_vaddr),
|
||||||
sh_offset: endian::U64::new(LE, new_rodata_section_offset as u64),
|
sh_offset: endian::U64::new(LE, new_rodata_section_offset),
|
||||||
sh_size: endian::U64::new(LE, new_rodata_section_size),
|
sh_size: endian::U64::new(LE, new_rodata_section_size),
|
||||||
sh_link: endian::U32::new(LE, 0),
|
sh_link: endian::U32::new(LE, 0),
|
||||||
sh_info: endian::U32::new(LE, 0),
|
sh_info: endian::U32::new(LE, 0),
|
||||||
|
@ -1530,13 +1544,27 @@ fn surgery_elf_help(
|
||||||
sh_entsize: endian::U64::new(LE, 0),
|
sh_entsize: endian::U64::new(LE, 0),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// set the new bss section header
|
||||||
|
section_headers[section_headers.len() - 2] = elf::SectionHeader64 {
|
||||||
|
sh_name: endian::U32::new(LE, 0),
|
||||||
|
sh_type: endian::U32::new(LE, elf::SHT_NOBITS),
|
||||||
|
sh_flags: endian::U64::new(LE, (elf::SHF_ALLOC) as u64),
|
||||||
|
sh_addr: endian::U64::new(LE, new_bss_section_vaddr),
|
||||||
|
sh_offset: endian::U64::new(LE, new_bss_section_offset),
|
||||||
|
sh_size: endian::U64::new(LE, new_bss_section_virtual_size),
|
||||||
|
sh_link: endian::U32::new(LE, 0),
|
||||||
|
sh_info: endian::U32::new(LE, 0),
|
||||||
|
sh_addralign: endian::U64::new(LE, 16),
|
||||||
|
sh_entsize: endian::U64::new(LE, 0),
|
||||||
|
};
|
||||||
|
|
||||||
// set the new text section header
|
// set the new text section header
|
||||||
section_headers[section_headers.len() - 1] = elf::SectionHeader64 {
|
section_headers[section_headers.len() - 1] = elf::SectionHeader64 {
|
||||||
sh_name: endian::U32::new(LE, 0),
|
sh_name: endian::U32::new(LE, 0),
|
||||||
sh_type: endian::U32::new(LE, elf::SHT_PROGBITS),
|
sh_type: endian::U32::new(LE, elf::SHT_PROGBITS),
|
||||||
sh_flags: endian::U64::new(LE, (elf::SHF_ALLOC | elf::SHF_EXECINSTR) as u64),
|
sh_flags: endian::U64::new(LE, (elf::SHF_ALLOC | elf::SHF_EXECINSTR) as u64),
|
||||||
sh_addr: endian::U64::new(LE, new_text_section_vaddr),
|
sh_addr: endian::U64::new(LE, new_text_section_vaddr),
|
||||||
sh_offset: endian::U64::new(LE, new_text_section_offset as u64),
|
sh_offset: endian::U64::new(LE, new_text_section_offset),
|
||||||
sh_size: endian::U64::new(LE, new_text_section_size),
|
sh_size: endian::U64::new(LE, new_text_section_size),
|
||||||
sh_link: endian::U32::new(LE, 0),
|
sh_link: endian::U32::new(LE, 0),
|
||||||
sh_info: endian::U32::new(LE, 0),
|
sh_info: endian::U32::new(LE, 0),
|
||||||
|
@ -1559,14 +1587,26 @@ fn surgery_elf_help(
|
||||||
);
|
);
|
||||||
|
|
||||||
// set the new rodata section program header
|
// set the new rodata section program header
|
||||||
program_headers[program_headers.len() - 2] = elf::ProgramHeader64 {
|
program_headers[program_headers.len() - 3] = elf::ProgramHeader64 {
|
||||||
p_type: endian::U32::new(LE, elf::PT_LOAD),
|
p_type: endian::U32::new(LE, elf::PT_LOAD),
|
||||||
p_flags: endian::U32::new(LE, elf::PF_R),
|
p_flags: endian::U32::new(LE, elf::PF_R),
|
||||||
p_offset: endian::U64::new(LE, new_rodata_section_offset as u64),
|
p_offset: endian::U64::new(LE, new_rodata_section_offset),
|
||||||
p_vaddr: endian::U64::new(LE, new_rodata_section_vaddr as u64),
|
p_vaddr: endian::U64::new(LE, new_rodata_section_vaddr),
|
||||||
p_paddr: endian::U64::new(LE, new_rodata_section_vaddr as u64),
|
p_paddr: endian::U64::new(LE, new_rodata_section_vaddr),
|
||||||
p_filesz: endian::U64::new(LE, new_rodata_section_size),
|
p_filesz: endian::U64::new(LE, new_rodata_section_size),
|
||||||
p_memsz: endian::U64::new(LE, new_rodata_section_virtual_size),
|
p_memsz: endian::U64::new(LE, new_rodata_section_size),
|
||||||
|
p_align: endian::U64::new(LE, md.load_align_constraint),
|
||||||
|
};
|
||||||
|
|
||||||
|
// set the new bss section program header
|
||||||
|
program_headers[program_headers.len() - 2] = elf::ProgramHeader64 {
|
||||||
|
p_type: endian::U32::new(LE, elf::PT_LOAD),
|
||||||
|
p_flags: endian::U32::new(LE, elf::PF_R | elf::PF_W),
|
||||||
|
p_offset: endian::U64::new(LE, new_bss_section_offset),
|
||||||
|
p_vaddr: endian::U64::new(LE, new_bss_section_vaddr),
|
||||||
|
p_paddr: endian::U64::new(LE, new_bss_section_vaddr),
|
||||||
|
p_filesz: endian::U64::new(LE, 0),
|
||||||
|
p_memsz: endian::U64::new(LE, new_bss_section_virtual_size),
|
||||||
p_align: endian::U64::new(LE, md.load_align_constraint),
|
p_align: endian::U64::new(LE, md.load_align_constraint),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1575,7 +1615,7 @@ fn surgery_elf_help(
|
||||||
program_headers[new_text_section_index] = elf::ProgramHeader64 {
|
program_headers[new_text_section_index] = elf::ProgramHeader64 {
|
||||||
p_type: endian::U32::new(LE, elf::PT_LOAD),
|
p_type: endian::U32::new(LE, elf::PT_LOAD),
|
||||||
p_flags: endian::U32::new(LE, elf::PF_R | elf::PF_X),
|
p_flags: endian::U32::new(LE, elf::PF_R | elf::PF_X),
|
||||||
p_offset: endian::U64::new(LE, new_text_section_offset as u64),
|
p_offset: endian::U64::new(LE, new_text_section_offset),
|
||||||
p_vaddr: endian::U64::new(LE, new_text_section_vaddr),
|
p_vaddr: endian::U64::new(LE, new_text_section_vaddr),
|
||||||
p_paddr: endian::U64::new(LE, new_text_section_vaddr),
|
p_paddr: endian::U64::new(LE, new_text_section_vaddr),
|
||||||
p_filesz: endian::U64::new(LE, new_text_section_size),
|
p_filesz: endian::U64::new(LE, new_text_section_size),
|
||||||
|
@ -1722,7 +1762,6 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
[
|
[
|
||||||
"memcpy",
|
|
||||||
"memset",
|
"memset",
|
||||||
"roc_alloc",
|
"roc_alloc",
|
||||||
"roc_dealloc",
|
"roc_dealloc",
|
||||||
|
|
|
@ -141,9 +141,7 @@ fn collect_roc_definitions<'a>(object: &object::File<'a, &'a [u8]>) -> MutMap<St
|
||||||
let address = sym.address();
|
let address = sym.address();
|
||||||
|
|
||||||
// special exceptions for memcpy and memset.
|
// special exceptions for memcpy and memset.
|
||||||
if name == "roc_memcpy" {
|
if name == "roc_memset" {
|
||||||
vaddresses.insert("memcpy".to_string(), address);
|
|
||||||
} else if name == "roc_memset" {
|
|
||||||
vaddresses.insert("memset".to_string(), address);
|
vaddresses.insert("memset".to_string(), address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -444,6 +444,7 @@ pub(crate) fn surgery_pe(executable_path: &Path, metadata_path: &Path, roc_app_b
|
||||||
"__fixsfti",
|
"__fixsfti",
|
||||||
"__fixunsdfti",
|
"__fixunsdfti",
|
||||||
"__fixunssfti",
|
"__fixunssfti",
|
||||||
|
"memcpy_decision",
|
||||||
]
|
]
|
||||||
.contains(&name.as_str());
|
.contains(&name.as_str());
|
||||||
if *address == 0 && !name.starts_with("roc") && !is_ingested_compiler_rt {
|
if *address == 0 && !name.starts_with("roc") && !is_ingested_compiler_rt {
|
||||||
|
@ -1318,7 +1319,6 @@ fn relocate_dummy_dll_entries(executable: &mut [u8], md: &PeMetadata) {
|
||||||
/// Redirect `memcpy` and similar libc functions to their roc equivalents
|
/// Redirect `memcpy` and similar libc functions to their roc equivalents
|
||||||
pub(crate) fn redirect_libc_functions(name: &str) -> Option<&str> {
|
pub(crate) fn redirect_libc_functions(name: &str) -> Option<&str> {
|
||||||
match name {
|
match name {
|
||||||
"memcpy" => Some("roc_memcpy"),
|
|
||||||
"memset" => Some("roc_memset"),
|
"memset" => Some("roc_memset"),
|
||||||
"memmove" => Some("roc_memmove"),
|
"memmove" => Some("roc_memmove"),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
|
|
@ -64,13 +64,6 @@ void roc_panic(void *ptr, unsigned int alignment)
|
||||||
|
|
||||||
//--------------------------
|
//--------------------------
|
||||||
|
|
||||||
void *roc_memcpy(void *dest, const void *src, size_t n)
|
|
||||||
{
|
|
||||||
return memcpy(dest, src, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------
|
|
||||||
|
|
||||||
void *roc_memset(void *str, int c, size_t n)
|
void *roc_memset(void *str, int c, size_t n)
|
||||||
{
|
{
|
||||||
return memset(str, c, n);
|
return memset(str, c, n);
|
||||||
|
|
|
@ -15,12 +15,14 @@ roc_exhaustive = { path = "../compiler/exhaustive" }
|
||||||
roc_fmt = { path = "../compiler/fmt" }
|
roc_fmt = { path = "../compiler/fmt" }
|
||||||
roc_module = { path = "../compiler/module" }
|
roc_module = { path = "../compiler/module" }
|
||||||
roc_parse = { path = "../compiler/parse" }
|
roc_parse = { path = "../compiler/parse" }
|
||||||
|
roc_packaging = { path = "../packaging" }
|
||||||
roc_problem = { path = "../compiler/problem" }
|
roc_problem = { path = "../compiler/problem" }
|
||||||
roc_region = { path = "../compiler/region" }
|
roc_region = { path = "../compiler/region" }
|
||||||
roc_solve_problem = { path = "../compiler/solve_problem" }
|
roc_solve_problem = { path = "../compiler/solve_problem" }
|
||||||
roc_std = { path = "../roc_std" }
|
roc_std = { path = "../roc_std" }
|
||||||
roc_types = { path = "../compiler/types" }
|
roc_types = { path = "../compiler/types" }
|
||||||
ven_pretty = { path = "../vendor/pretty" }
|
ven_pretty = { path = "../vendor/pretty" }
|
||||||
|
byte-unit = "4.0.19"
|
||||||
itertools = "0.10.5"
|
itertools = "0.10.5"
|
||||||
|
|
||||||
bumpalo.workspace = true
|
bumpalo.workspace = true
|
||||||
|
|
|
@ -1254,19 +1254,49 @@ fn to_bad_ident_expr_report<'b>(
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
Underscore(pos) => {
|
UnderscoreAlone(_pos) => {
|
||||||
let region = Region::new(surroundings.start(), pos);
|
alloc.stack([
|
||||||
|
alloc.reflow("An underscore is being used as a variable here:"),
|
||||||
|
alloc.region(lines.convert_region(surroundings)),
|
||||||
|
alloc.concat([alloc
|
||||||
|
.reflow(r"An underscore can be used to ignore a value when pattern matching, but it cannot be used as a variable.")]),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
UnderscoreInMiddle(_pos) => {
|
||||||
alloc.stack([
|
alloc.stack([
|
||||||
alloc.reflow("Underscores are not allowed in identifier names:"),
|
alloc.reflow("Underscores are not allowed in identifier names:"),
|
||||||
alloc.region_with_subregion(
|
alloc.region(lines.convert_region(surroundings)),
|
||||||
lines.convert_region(surroundings),
|
|
||||||
lines.convert_region(region),
|
|
||||||
),
|
|
||||||
alloc.concat([alloc
|
alloc.concat([alloc
|
||||||
.reflow(r"I recommend using camelCase. It's the standard style in Roc code!")]),
|
.reflow(r"I recommend using camelCase. It's the standard style in Roc code!")]),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UnderscoreAtStart {
|
||||||
|
position: _pos,
|
||||||
|
declaration_region,
|
||||||
|
} => {
|
||||||
|
let line = "This variable's name starts with an underscore:";
|
||||||
|
alloc.stack([
|
||||||
|
match declaration_region {
|
||||||
|
None => alloc.reflow(line),
|
||||||
|
Some(declaration_region) => alloc.stack([
|
||||||
|
alloc.reflow(line),
|
||||||
|
alloc.region(lines.convert_region(declaration_region)),
|
||||||
|
alloc.reflow("But then it is used here:"),
|
||||||
|
])
|
||||||
|
},
|
||||||
|
alloc.region(lines.convert_region(surroundings)),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.reflow(r"A variable's name can only start with an underscore if the variable is unused. "),
|
||||||
|
match declaration_region {
|
||||||
|
None => alloc.reflow(r"But it looks like the variable is being used here!"),
|
||||||
|
Some(_) => alloc.reflow(r"Since you are using this variable, you could remove the underscore from its name in both places."),
|
||||||
|
}
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
BadOpaqueRef(pos) => {
|
BadOpaqueRef(pos) => {
|
||||||
use BadIdentNext::*;
|
use BadIdentNext::*;
|
||||||
let kind = "an opaque reference";
|
let kind = "an opaque reference";
|
||||||
|
@ -1409,7 +1439,13 @@ fn to_bad_ident_pattern_report<'b>(
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
Underscore(pos) => {
|
UnderscoreAlone(..) | UnderscoreAtStart { .. } => {
|
||||||
|
unreachable!(
|
||||||
|
"it's fine to have an underscore at the beginning of an identifier in a pattern"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
UnderscoreInMiddle(pos) => {
|
||||||
let region = Region::from_pos(pos.sub(1));
|
let region = Region::from_pos(pos.sub(1));
|
||||||
|
|
||||||
alloc.stack([
|
alloc.stack([
|
||||||
|
@ -1580,8 +1616,19 @@ fn pretty_runtime_error<'b>(
|
||||||
(title, doc) = report_shadowing(alloc, lines, original_region, shadow, kind);
|
(title, doc) = report_shadowing(alloc, lines, original_region, shadow, kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
RuntimeError::LookupNotInScope(loc_name, options) => {
|
RuntimeError::LookupNotInScope {
|
||||||
doc = not_found(alloc, lines, loc_name.region, &loc_name.value, options);
|
loc_name,
|
||||||
|
suggestion_options: options,
|
||||||
|
underscored_suggestion_region,
|
||||||
|
} => {
|
||||||
|
doc = not_found(
|
||||||
|
alloc,
|
||||||
|
lines,
|
||||||
|
loc_name.region,
|
||||||
|
&loc_name.value,
|
||||||
|
options,
|
||||||
|
underscored_suggestion_region,
|
||||||
|
);
|
||||||
title = UNRECOGNIZED_NAME;
|
title = UNRECOGNIZED_NAME;
|
||||||
}
|
}
|
||||||
RuntimeError::CircularDef(entries) => {
|
RuntimeError::CircularDef(entries) => {
|
||||||
|
@ -2219,6 +2266,7 @@ fn not_found<'b>(
|
||||||
region: roc_region::all::Region,
|
region: roc_region::all::Region,
|
||||||
name: &Ident,
|
name: &Ident,
|
||||||
options: MutSet<Box<str>>,
|
options: MutSet<Box<str>>,
|
||||||
|
underscored_suggestion_region: Option<Region>,
|
||||||
) -> RocDocBuilder<'b> {
|
) -> RocDocBuilder<'b> {
|
||||||
let mut suggestions = suggest::sort(
|
let mut suggestions = suggest::sort(
|
||||||
name.as_inline_str().as_str(),
|
name.as_inline_str().as_str(),
|
||||||
|
@ -2234,7 +2282,15 @@ fn not_found<'b>(
|
||||||
alloc.reflow(" missing up-top"),
|
alloc.reflow(" missing up-top"),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let default_yes = alloc.reflow("Did you mean one of these?");
|
let default_yes = match underscored_suggestion_region {
|
||||||
|
Some(underscored_region) => alloc.stack([
|
||||||
|
alloc.reflow("There is an ignored identifier of a similar name here:"),
|
||||||
|
alloc.region(lines.convert_region(underscored_region)),
|
||||||
|
alloc.reflow("Did you mean to remove the leading underscore?"),
|
||||||
|
alloc.reflow("If not, did you mean one of these?"),
|
||||||
|
]),
|
||||||
|
None => alloc.reflow("Did you mean one of these?"),
|
||||||
|
};
|
||||||
|
|
||||||
let to_details = |no_suggestion_details, yes_suggestion_details| {
|
let to_details = |no_suggestion_details, yes_suggestion_details| {
|
||||||
if suggestions.is_empty() {
|
if suggestions.is_empty() {
|
||||||
|
|
|
@ -7,6 +7,11 @@ use std::path::{Path, PathBuf};
|
||||||
use std::{fmt, io};
|
use std::{fmt, io};
|
||||||
use ven_pretty::{text, BoxAllocator, DocAllocator, DocBuilder, Render, RenderAnnotated};
|
use ven_pretty::{text, BoxAllocator, DocAllocator, DocBuilder, Render, RenderAnnotated};
|
||||||
|
|
||||||
|
#[cfg(not(target_family = "wasm"))]
|
||||||
|
use byte_unit::Byte;
|
||||||
|
#[cfg(not(target_family = "wasm"))]
|
||||||
|
use roc_packaging::https::Problem;
|
||||||
|
|
||||||
pub use crate::error::canonicalize::can_problem;
|
pub use crate::error::canonicalize::can_problem;
|
||||||
pub use crate::error::parse::parse_problem;
|
pub use crate::error::parse::parse_problem;
|
||||||
pub use crate::error::r#type::type_problem;
|
pub use crate::error::r#type::type_problem;
|
||||||
|
@ -1075,6 +1080,471 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_family = "wasm"))]
|
||||||
|
pub fn to_https_problem_report_string(url: &str, https_problem: Problem) -> String {
|
||||||
|
let src_lines: Vec<&str> = Vec::new();
|
||||||
|
|
||||||
|
let mut module_ids = ModuleIds::default();
|
||||||
|
|
||||||
|
let module_id = module_ids.get_or_insert(&"find module name somehow?".into());
|
||||||
|
|
||||||
|
let interns = Interns::default();
|
||||||
|
|
||||||
|
// Report parsing and canonicalization problems
|
||||||
|
let alloc = RocDocAllocator::new(&src_lines, module_id, &interns);
|
||||||
|
|
||||||
|
let mut buf = String::new();
|
||||||
|
let palette = DEFAULT_PALETTE;
|
||||||
|
let report = to_https_problem_report(&alloc, url, https_problem);
|
||||||
|
report.render_color_terminal(&mut buf, &alloc, &palette);
|
||||||
|
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_family = "wasm"))]
|
||||||
|
pub fn to_https_problem_report<'b>(
|
||||||
|
alloc: &'b RocDocAllocator<'b>,
|
||||||
|
url: &'b str,
|
||||||
|
https_problem: Problem,
|
||||||
|
) -> Report<'b> {
|
||||||
|
match https_problem {
|
||||||
|
Problem::UnsupportedEncoding(not_supported_encoding) => {
|
||||||
|
let doc = alloc.stack([
|
||||||
|
alloc.reflow(r"I was trying to download this URL:"),
|
||||||
|
alloc.string((&url).to_string()).annotate(Annotation::Url).indent(4),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.reflow(r"But the server replied with a "),
|
||||||
|
alloc.reflow(r"content encoding").annotate(Annotation::Emphasized),
|
||||||
|
alloc.reflow(r" that I do not understand ("),
|
||||||
|
alloc.string(not_supported_encoding).annotate(Annotation::Emphasized),
|
||||||
|
alloc.reflow(r")."),
|
||||||
|
]),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.reflow(r"The supported content encodings are "),
|
||||||
|
alloc.keyword(r"br"),
|
||||||
|
alloc.reflow(r", "),
|
||||||
|
alloc.keyword(r"gzip"),
|
||||||
|
alloc.reflow(r" and "),
|
||||||
|
alloc.keyword(r"deflate"),
|
||||||
|
]),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.tip(),
|
||||||
|
alloc.reflow(r"Perhaps you can check if the URL is correctly formed, or if the server is correctly configured."),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename: "UNKNOWN.roc".into(),
|
||||||
|
doc,
|
||||||
|
title: "UNSUPPORTED ENCODING".to_string(),
|
||||||
|
severity: Severity::Fatal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Problem::MultipleEncodings(multiple_encodings) => {
|
||||||
|
let doc = alloc.stack([
|
||||||
|
alloc.reflow(r"I was trying to download this URL:"),
|
||||||
|
alloc.string((&url).to_string()).annotate(Annotation::Url).indent(4),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.reflow(r"But the server replied with multiple "),
|
||||||
|
alloc.reflow(r"content encodings").annotate(Annotation::Emphasized),
|
||||||
|
alloc.reflow(r": "),
|
||||||
|
alloc.string(multiple_encodings).annotate(Annotation::Emphasized),
|
||||||
|
alloc.reflow(r"."),
|
||||||
|
]),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.reflow(r"The supported content encodings are "),
|
||||||
|
alloc.keyword(r"br"),
|
||||||
|
alloc.reflow(r", "),
|
||||||
|
alloc.keyword(r"gzip"),
|
||||||
|
alloc.reflow(r" and "),
|
||||||
|
alloc.keyword(r"deflate"),
|
||||||
|
alloc.reflow(r". However, the server reply can only contain "),
|
||||||
|
alloc.reflow(r"one").annotate(Annotation::Emphasized),
|
||||||
|
alloc.reflow(r"."),
|
||||||
|
]),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.tip(),
|
||||||
|
alloc.reflow(r"Perhaps you can check if the URL is correctly formed, or if the server is correctly configured."),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename: "UNKNOWN.roc".into(),
|
||||||
|
doc,
|
||||||
|
title: "MULTIPLE ENCODINGS".to_string(),
|
||||||
|
severity: Severity::Fatal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Problem::InvalidContentHash { expected, actual } => {
|
||||||
|
let doc = alloc.stack([
|
||||||
|
alloc.reflow(r"I was able to download this URL:"),
|
||||||
|
alloc.string((&url).to_string()).annotate(Annotation::Url).indent(4),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.reflow(r"I use a mechanism to detect if the file might "),
|
||||||
|
alloc.reflow(r"have been tampered with. This could happen if "),
|
||||||
|
alloc.reflow(r"the server or domain have been compromised."),
|
||||||
|
]),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.reflow(r"This is the content signature I was "),
|
||||||
|
alloc.reflow(r"expecting").annotate(Annotation::Emphasized),
|
||||||
|
alloc.reflow(r":"),
|
||||||
|
]),
|
||||||
|
alloc.string(expected).annotate(Annotation::PlainText).indent(4),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.reflow(r"However, this is the content signature I "),
|
||||||
|
alloc.reflow(r"obtained").annotate(Annotation::Emphasized),
|
||||||
|
alloc.reflow(r":"),
|
||||||
|
]),
|
||||||
|
alloc.string(actual).annotate(Annotation::PlainText).indent(4),
|
||||||
|
alloc.reflow(r"To keep you secure, I will not execute this untrusted code."),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.tip(),
|
||||||
|
alloc.reflow(r"Check if the URL is correctly formed and if this is the server you are expecting to connect to."),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename: "UNKNOWN.roc".into(),
|
||||||
|
doc,
|
||||||
|
title: "INVALID CONTENT HASH".to_string(),
|
||||||
|
severity: Severity::Fatal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: The reporting text for IoErr and FsExtraErr could probably be unified
|
||||||
|
Problem::IoErr(io_error) => {
|
||||||
|
let doc = alloc.stack([
|
||||||
|
alloc.reflow(r"I was trying to download this URL:"),
|
||||||
|
alloc
|
||||||
|
.string((&url).to_string())
|
||||||
|
.annotate(Annotation::Url)
|
||||||
|
.indent(4),
|
||||||
|
alloc.reflow(r"But I encountered an IO (input/output) error:"),
|
||||||
|
alloc
|
||||||
|
.string(io_error.to_string())
|
||||||
|
.annotate(Annotation::PlainText)
|
||||||
|
.indent(4),
|
||||||
|
// TODO: What should the tip for IO errors be?
|
||||||
|
// alloc.concat([
|
||||||
|
// alloc.tip(),
|
||||||
|
// alloc.reflow(r"Check the error message."),
|
||||||
|
// ]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename: "UNKNOWN.roc".into(),
|
||||||
|
doc,
|
||||||
|
title: "IO ERROR".to_string(),
|
||||||
|
severity: Severity::Fatal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: The reporting text for IoErr and FsExtraErr could probably be unified
|
||||||
|
Problem::FsExtraErr(fs_extra_error) => {
|
||||||
|
let doc = alloc.stack([
|
||||||
|
alloc.reflow(r"I was trying to download this URL:"),
|
||||||
|
alloc
|
||||||
|
.string((&url).to_string())
|
||||||
|
.annotate(Annotation::Url)
|
||||||
|
.indent(4),
|
||||||
|
alloc.reflow(r"But I encountered an IO (input/output) error:"),
|
||||||
|
alloc
|
||||||
|
.string(fs_extra_error.to_string())
|
||||||
|
.annotate(Annotation::PlainText)
|
||||||
|
.indent(4),
|
||||||
|
// TODO: What should the tip for IO errors be?
|
||||||
|
// alloc.concat([
|
||||||
|
// alloc.tip(),
|
||||||
|
// alloc.reflow(r"Check the error message."),
|
||||||
|
// ]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename: "UNKNOWN.roc".into(),
|
||||||
|
doc,
|
||||||
|
title: "IO ERROR".to_string(),
|
||||||
|
severity: Severity::Fatal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Problem::HttpErr(reqwest_error) => {
|
||||||
|
let doc = alloc.stack([
|
||||||
|
alloc.reflow(r"I was trying to download this URL:"),
|
||||||
|
alloc
|
||||||
|
.string((&url).to_string())
|
||||||
|
.annotate(Annotation::Url)
|
||||||
|
.indent(4),
|
||||||
|
alloc.reflow(r"But I encountered a network error:"),
|
||||||
|
alloc
|
||||||
|
.string(reqwest_error.to_string())
|
||||||
|
.annotate(Annotation::PlainText)
|
||||||
|
.indent(4),
|
||||||
|
// TODO: What should the tip for HTTP IO errors be?
|
||||||
|
// Should we import reqwest and check stuff like
|
||||||
|
// reqwest_error.{ is_redirect(), is_status(), is_timeout(), ... } ?
|
||||||
|
//
|
||||||
|
// alloc.concat([
|
||||||
|
// alloc.tip(),
|
||||||
|
// alloc.reflow(r"Check the error message."),
|
||||||
|
// ]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename: "UNKNOWN.roc".into(),
|
||||||
|
doc,
|
||||||
|
title: "HTTP ERROR".to_string(),
|
||||||
|
severity: Severity::Fatal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Problem::InvalidUrl(roc_packaging::https::UrlProblem::InvalidExtensionSuffix(
|
||||||
|
invalid_suffix,
|
||||||
|
)) => {
|
||||||
|
let (suffix_text, annotation_style) = if invalid_suffix.is_empty() {
|
||||||
|
(r"empty".to_string(), Annotation::PlainText)
|
||||||
|
} else {
|
||||||
|
(invalid_suffix, Annotation::Emphasized)
|
||||||
|
};
|
||||||
|
|
||||||
|
let doc = alloc.stack([
|
||||||
|
alloc.reflow(r"I was trying to download this URL:"),
|
||||||
|
alloc
|
||||||
|
.string((&url).to_string())
|
||||||
|
.annotate(Annotation::Url)
|
||||||
|
.indent(4),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.reflow(r"However, this file's extension ("),
|
||||||
|
alloc.string(suffix_text).annotate(annotation_style),
|
||||||
|
alloc.reflow(r") is not a supported extension."),
|
||||||
|
]),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.reflow(r"The supported extensions are "),
|
||||||
|
alloc.keyword(r".tar"),
|
||||||
|
alloc.reflow(r", "),
|
||||||
|
alloc.keyword(r".tar.gz"),
|
||||||
|
alloc.reflow(r" and "),
|
||||||
|
alloc.keyword(r".tar.br"),
|
||||||
|
]),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.tip(),
|
||||||
|
alloc.reflow(r"Check that you have the correct URL for this package/platform."),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename: "UNKNOWN.roc".into(),
|
||||||
|
doc,
|
||||||
|
title: "INVALID EXTENSION SUFFIX".to_string(),
|
||||||
|
severity: Severity::Fatal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Problem::InvalidUrl(roc_packaging::https::UrlProblem::MissingTarExt) => {
|
||||||
|
let doc = alloc.stack([
|
||||||
|
alloc.reflow(r"I was trying to download this URL:"),
|
||||||
|
alloc
|
||||||
|
.string((&url).to_string())
|
||||||
|
.annotate(Annotation::Url)
|
||||||
|
.indent(4),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.reflow(r"However, this file's extension is not "),
|
||||||
|
alloc.keyword(r".tar"),
|
||||||
|
alloc.reflow(r"."),
|
||||||
|
]),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.reflow(r"The supported extensions are "),
|
||||||
|
alloc.keyword(r".tar"),
|
||||||
|
alloc.reflow(r", "),
|
||||||
|
alloc.keyword(r".tar.gz"),
|
||||||
|
alloc.reflow(r" and "),
|
||||||
|
alloc.keyword(r".tar.br"),
|
||||||
|
]),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.tip(),
|
||||||
|
alloc.reflow(r"Check that you have the correct URL for this package/platform."),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename: "UNKNOWN.roc".into(),
|
||||||
|
doc,
|
||||||
|
title: "INVALID EXTENSION".to_string(),
|
||||||
|
severity: Severity::Fatal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Problem::InvalidUrl(roc_packaging::https::UrlProblem::InvalidFragment(
|
||||||
|
invalid_fragment,
|
||||||
|
)) => {
|
||||||
|
let doc = alloc.stack([
|
||||||
|
alloc.reflow(r"I was trying to download this URL:"),
|
||||||
|
alloc
|
||||||
|
.string((&url).to_string())
|
||||||
|
.annotate(Annotation::Url)
|
||||||
|
.indent(4),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.reflow(r"However, this URL's fragment (the part after #) "),
|
||||||
|
alloc.reflow(r"is not valid. When present, the fragment must point to "),
|
||||||
|
alloc.reflow(r"an existing "),
|
||||||
|
alloc.keyword(r".roc"),
|
||||||
|
alloc.reflow(r" file inside the package. Also, the filename can't be empty, "),
|
||||||
|
alloc.reflow(r"so a fragment of #.roc would also not be valid. This is the "),
|
||||||
|
alloc.reflow(r"invalid fragment I encountered: "),
|
||||||
|
]),
|
||||||
|
alloc
|
||||||
|
.string(invalid_fragment)
|
||||||
|
.annotate(Annotation::Emphasized)
|
||||||
|
.indent(4),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.tip(),
|
||||||
|
alloc.reflow(r"Check that the fragment points to an existing "),
|
||||||
|
alloc.keyword(r".roc"),
|
||||||
|
alloc.reflow(r" file inside the package. You can download this package "),
|
||||||
|
alloc.reflow(r"and inspect it locally."),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename: "UNKNOWN.roc".into(),
|
||||||
|
doc,
|
||||||
|
title: "INVALID FRAGMENT".to_string(),
|
||||||
|
severity: Severity::Fatal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Problem::InvalidUrl(roc_packaging::https::UrlProblem::MissingHash) => {
|
||||||
|
let doc = alloc.stack([
|
||||||
|
alloc.reflow(r"I was trying to download this URL:"),
|
||||||
|
alloc
|
||||||
|
.string((&url).to_string())
|
||||||
|
.annotate(Annotation::Url)
|
||||||
|
.indent(4),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.reflow(r"I use a content hash to detect if the file might "),
|
||||||
|
alloc.reflow(r"have been tampered with. This could happen if "),
|
||||||
|
alloc.reflow(r"the server or domain have been compromised."),
|
||||||
|
]),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.reflow(r"The way this works is that the name of the file "),
|
||||||
|
alloc.reflow(r"is the BLAKE3 hash of the contents of the "),
|
||||||
|
alloc.reflow(r"file itself. If someone would tamper with the file, "),
|
||||||
|
alloc.reflow(r"I could notify and protect you. However, I could "),
|
||||||
|
alloc.reflow(r"not find the expected hash on the URL above, "),
|
||||||
|
alloc.reflow(r"so I cannot apply this tamper-check."),
|
||||||
|
]),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.tip(),
|
||||||
|
alloc
|
||||||
|
.reflow(r"Check that you have the correct URL for this package/platform. "),
|
||||||
|
alloc.reflow(r"Here is an example of how such a hash looks like: "),
|
||||||
|
alloc
|
||||||
|
.string(r"tE4xS_zLdmmxmHwHih9kHWQ7fsXtJr7W7h3425-eZFk".to_string())
|
||||||
|
.annotate(Annotation::Emphasized),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename: "UNKNOWN.roc".into(),
|
||||||
|
doc,
|
||||||
|
title: "MISSING PACKAGE HASH".to_string(),
|
||||||
|
severity: Severity::Fatal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Problem::InvalidUrl(roc_packaging::https::UrlProblem::MissingHttps) => {
|
||||||
|
let doc = alloc.stack([
|
||||||
|
alloc.reflow(r"I was trying to download this URL:"),
|
||||||
|
alloc
|
||||||
|
.string((&url).to_string())
|
||||||
|
.annotate(Annotation::Url)
|
||||||
|
.indent(4),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.reflow(r"For your security, I will only attempt to download "),
|
||||||
|
alloc.reflow(r"files from servers which use the "),
|
||||||
|
alloc.keyword(r"https"),
|
||||||
|
alloc.reflow(r" protocol."),
|
||||||
|
]),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.tip(),
|
||||||
|
alloc.reflow(r"Check that you have the correct URL for this package/platform."),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename: "UNKNOWN.roc".into(),
|
||||||
|
doc,
|
||||||
|
title: "HTTPS MANDATORY".to_string(),
|
||||||
|
severity: Severity::Fatal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Problem::InvalidUrl(roc_packaging::https::UrlProblem::MisleadingCharacter) => {
|
||||||
|
let doc = alloc.stack([
|
||||||
|
alloc.reflow(r"I was trying to download this URL:"),
|
||||||
|
alloc
|
||||||
|
.string((&url).to_string())
|
||||||
|
.annotate(Annotation::Url)
|
||||||
|
.indent(4),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.reflow(r"I have found one or more potentially misleading "),
|
||||||
|
alloc.reflow(r"characters in this URL. Misleading characters are "),
|
||||||
|
alloc.reflow(r"characters that look like others but aren't the same. "),
|
||||||
|
alloc.reflow(r"The following characters are classified as misleading: "),
|
||||||
|
alloc.keyword(r"@"),
|
||||||
|
alloc.reflow(r", "),
|
||||||
|
alloc.keyword("\u{2044}"),
|
||||||
|
alloc.reflow(r" (unicode 2044), "),
|
||||||
|
alloc.keyword("\u{2215}"),
|
||||||
|
alloc.reflow(r" (unicode 2215), "),
|
||||||
|
alloc.keyword("\u{FF0F}"),
|
||||||
|
alloc.reflow(r" (unicode FF0F) and "),
|
||||||
|
alloc.keyword("\u{29F8}"),
|
||||||
|
alloc.reflow(r" (unicode 29F8). "),
|
||||||
|
]),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.reflow(r"If you have a use-case for any of these characters we "),
|
||||||
|
alloc.reflow(r"would like to hear about it. Reach out on "),
|
||||||
|
alloc
|
||||||
|
.string(r"https://github.com/roc-lang/roc/issues/5487".to_string())
|
||||||
|
.annotate(Annotation::Url),
|
||||||
|
]),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.tip(),
|
||||||
|
alloc.reflow(r"Check that you have the correct URL for this package/platform."),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename: "UNKNOWN.roc".into(),
|
||||||
|
doc,
|
||||||
|
title: "MISLEADING CHARACTERS".to_string(),
|
||||||
|
severity: Severity::Fatal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Problem::DownloadTooBig(content_len) => {
|
||||||
|
let nice_bytes = Byte::from_bytes(content_len.into())
|
||||||
|
.get_appropriate_unit(false)
|
||||||
|
.format(3);
|
||||||
|
let doc = alloc.stack([
|
||||||
|
alloc.reflow(r"I was trying to download this URL:"),
|
||||||
|
alloc
|
||||||
|
.string((&url).to_string())
|
||||||
|
.annotate(Annotation::Url)
|
||||||
|
.indent(4),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.reflow(r"But the server stated this file is "),
|
||||||
|
alloc.string(nice_bytes).annotate(Annotation::Keyword),
|
||||||
|
alloc.reflow(r" in size. This is larger that the maximum size I can handle (around 32 GB)."),
|
||||||
|
]),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.tip(),
|
||||||
|
alloc.reflow(r"Check that you have the correct URL for this package/platform. "),
|
||||||
|
alloc.reflow(r"If you do, you should contact the package/platform's author and "),
|
||||||
|
alloc.reflow(r"notify them about this issue."),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename: "UNKNOWN.roc".into(),
|
||||||
|
doc,
|
||||||
|
title: "FILE TOO LARGE".to_string(),
|
||||||
|
severity: Severity::Fatal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn to_file_problem_report_string(filename: &Path, error: io::ErrorKind) -> String {
|
pub fn to_file_problem_report_string(filename: &Path, error: io::ErrorKind) -> String {
|
||||||
let src_lines: Vec<&str> = Vec::new();
|
let src_lines: Vec<&str> = Vec::new();
|
||||||
|
|
||||||
|
|
|
@ -10151,6 +10151,41 @@ In roc, functions are always written as a lambda, like{}
|
||||||
"###
|
"###
|
||||||
);
|
);
|
||||||
|
|
||||||
|
test_report!(
|
||||||
|
forgot_to_remove_underscore,
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
\_foo -> foo
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
|golden| pretty_assertions::assert_eq!(
|
||||||
|
golden,
|
||||||
|
indoc!(
|
||||||
|
r###"── UNRECOGNIZED NAME ───────────────────────────────────── /code/proj/Main.roc ─
|
||||||
|
|
||||||
|
Nothing is named `foo` in this scope.
|
||||||
|
|
||||||
|
4│ \_foo -> foo
|
||||||
|
^^^
|
||||||
|
|
||||||
|
There is an ignored identifier of a similar name here:
|
||||||
|
|
||||||
|
4│ \_foo -> foo
|
||||||
|
^^^^
|
||||||
|
|
||||||
|
Did you mean to remove the leading underscore?
|
||||||
|
|
||||||
|
If not, did you mean one of these?
|
||||||
|
|
||||||
|
Box
|
||||||
|
Bool
|
||||||
|
U8
|
||||||
|
F64
|
||||||
|
"###
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
test_report!(
|
test_report!(
|
||||||
call_with_underscore_identifier,
|
call_with_underscore_identifier,
|
||||||
indoc!(
|
indoc!(
|
||||||
|
@ -10162,17 +10197,102 @@ In roc, functions are always written as a lambda, like{}
|
||||||
),
|
),
|
||||||
|golden| pretty_assertions::assert_eq!(
|
|golden| pretty_assertions::assert_eq!(
|
||||||
golden,
|
golden,
|
||||||
&format!(
|
indoc!(
|
||||||
r###"── SYNTAX PROBLEM ──────────────────────────────────────── /code/proj/Main.roc ─
|
r###"── SYNTAX PROBLEM ──────────────────────────────────────── /code/proj/Main.roc ─
|
||||||
|
|
||||||
Underscores are not allowed in identifier names:
|
An underscore is being used as a variable here:
|
||||||
|
|
||||||
6│ f 1 _ 1
|
6│ f 1 _ 1
|
||||||
{}
|
^
|
||||||
|
|
||||||
I recommend using camelCase. It's the standard style in Roc code!
|
An underscore can be used to ignore a value when pattern matching, but
|
||||||
"###,
|
it cannot be used as a variable.
|
||||||
" " // TODO make the reporter not insert extraneous spaces here in the first place!
|
"###
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
test_report!(
|
||||||
|
call_with_declared_identifier_starting_with_underscore,
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
f = \x, y, z -> x + y + z
|
||||||
|
|
||||||
|
\a, _b -> f a _b 1
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
|golden| pretty_assertions::assert_eq!(
|
||||||
|
golden,
|
||||||
|
indoc!(
|
||||||
|
r###"── SYNTAX PROBLEM ──────────────────────────────────────── /code/proj/Main.roc ─
|
||||||
|
|
||||||
|
This variable's name starts with an underscore:
|
||||||
|
|
||||||
|
6│ \a, _b -> f a _b 1
|
||||||
|
^^
|
||||||
|
|
||||||
|
But then it is used here:
|
||||||
|
|
||||||
|
6│ \a, _b -> f a _b 1
|
||||||
|
^^
|
||||||
|
|
||||||
|
A variable's name can only start with an underscore if the variable is
|
||||||
|
unused. Since you are using this variable, you could remove the
|
||||||
|
underscore from its name in both places.
|
||||||
|
"###
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
test_report!(
|
||||||
|
call_with_undeclared_identifier_starting_with_underscore,
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
f = \x, y, z -> x + y + z
|
||||||
|
|
||||||
|
\a, _b -> f a _r 1
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
|golden| pretty_assertions::assert_eq!(
|
||||||
|
golden,
|
||||||
|
indoc!(
|
||||||
|
r###"
|
||||||
|
── SYNTAX PROBLEM ──────────────────────────────────────── /code/proj/Main.roc ─
|
||||||
|
|
||||||
|
This variable's name starts with an underscore:
|
||||||
|
|
||||||
|
6│ \a, _b -> f a _r 1
|
||||||
|
^^
|
||||||
|
|
||||||
|
A variable's name can only start with an underscore if the variable is
|
||||||
|
unused. But it looks like the variable is being used here!
|
||||||
|
"###
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
test_report!(
|
||||||
|
underscore_in_middle_of_identifier,
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
f = \x, y, z -> x + y + z
|
||||||
|
|
||||||
|
\a, _b -> f a var_name 1
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
|golden| pretty_assertions::assert_eq!(
|
||||||
|
golden,
|
||||||
|
indoc!(
|
||||||
|
r###"
|
||||||
|
── SYNTAX PROBLEM ──────────────────────────────────────── /code/proj/Main.roc ─
|
||||||
|
|
||||||
|
Underscores are not allowed in identifier names:
|
||||||
|
|
||||||
|
6│ \a, _b -> f a var_name 1
|
||||||
|
^^^^^^^^
|
||||||
|
|
||||||
|
I recommend using camelCase. It's the standard style in Roc code!
|
||||||
|
"###
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -36,7 +36,6 @@ extern "C" {
|
||||||
) -> *mut c_void;
|
) -> *mut c_void;
|
||||||
pub fn roc_dealloc(ptr: *mut c_void, alignment: u32);
|
pub fn roc_dealloc(ptr: *mut c_void, alignment: u32);
|
||||||
pub fn roc_panic(c_ptr: *mut c_void, tag_id: u32);
|
pub fn roc_panic(c_ptr: *mut c_void, tag_id: u32);
|
||||||
pub fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void;
|
|
||||||
pub fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void;
|
pub fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,12 +45,6 @@ pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dst, src, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
||||||
|
|
|
@ -67,10 +67,6 @@ export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void {
|
||||||
std.process.exit(0);
|
std.process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn roc_memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void {
|
|
||||||
return memcpy(dst, src, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
||||||
return memset(dst, value, size);
|
return memset(dst, value, size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ use core::mem::MaybeUninit;
|
||||||
use glue::Metadata;
|
use glue::Metadata;
|
||||||
use roc_std::{RocDict, RocList, RocResult, RocStr};
|
use roc_std::{RocDict, RocList, RocResult, RocStr};
|
||||||
use std::borrow::{Borrow, Cow};
|
use std::borrow::{Borrow, Cow};
|
||||||
use std::ffi::{ OsStr};
|
use std::ffi::OsStr;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
@ -199,11 +199,6 @@ fn display_roc_fn(module_name: &str, fn_name: &str) -> String {
|
||||||
format!("\u{001B}[36m{module_name}\u{001B}[39m.{fn_name}")
|
format!("\u{001B}[36m{module_name}\u{001B}[39m.{fn_name}")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dst, src, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
||||||
libc::memset(dst, c, n)
|
libc::memset(dst, c, n)
|
||||||
|
|
|
@ -81,10 +81,6 @@ export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void {
|
||||||
std.process.exit(0);
|
std.process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn roc_memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void {
|
|
||||||
return memcpy(dst, src, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
||||||
return memset(dst, value, size);
|
return memset(dst, value, size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,11 +61,6 @@ pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dst, src, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
||||||
libc::memset(dst, c, n)
|
libc::memset(dst, c, n)
|
||||||
|
|
|
@ -136,10 +136,6 @@ export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void {
|
||||||
std.process.exit(0);
|
std.process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn roc_memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void {
|
|
||||||
return memcpy(dst, src, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
||||||
return memset(dst, value, size);
|
return memset(dst, value, size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,11 +44,6 @@ pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dst, src, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
||||||
libc::memset(dst, c, n)
|
libc::memset(dst, c, n)
|
||||||
|
|
|
@ -196,11 +196,6 @@ pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dst, src, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
||||||
libc::memset(dst, c, n)
|
libc::memset(dst, c, n)
|
||||||
|
|
|
@ -38,11 +38,6 @@ pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dst, src, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
||||||
libc::memset(dst, c, n)
|
libc::memset(dst, c, n)
|
||||||
|
|
|
@ -42,11 +42,6 @@ void roc_dealloc(void *ptr, unsigned int alignment)
|
||||||
free(ptr);
|
free(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *roc_memcpy(void *dest, const void *src, size_t n)
|
|
||||||
{
|
|
||||||
return memcpy(dest, src, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *roc_memset(void *str, int c, size_t n)
|
void *roc_memset(void *str, int c, size_t n)
|
||||||
{
|
{
|
||||||
return memset(str, c, n);
|
return memset(str, c, n);
|
||||||
|
|
|
@ -27,11 +27,6 @@ void roc_panic(void *ptr, unsigned int alignment)
|
||||||
napi_throw_error(napi_global_env, NULL, (char *)ptr);
|
napi_throw_error(napi_global_env, NULL, (char *)ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *roc_memcpy(void *dest, const void *src, size_t n)
|
|
||||||
{
|
|
||||||
return memcpy(dest, src, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *roc_memset(void *str, int c, size_t n) { return memset(str, c, n); }
|
void *roc_memset(void *str, int c, size_t n) { return memset(str, c, n); }
|
||||||
|
|
||||||
// Reference counting
|
// Reference counting
|
||||||
|
|
|
@ -33,10 +33,6 @@ export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
|
||||||
free(@alignCast(@alignOf(Align), @ptrCast([*]u8, c_ptr)));
|
free(@alignCast(@alignOf(Align), @ptrCast([*]u8, c_ptr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn roc_memcpy(dest: *anyopaque, src: *anyopaque, count: usize) callconv(.C) void {
|
|
||||||
_ = memcpy(dest, src, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE roc_panic is provided in the JS file, so it can throw an exception
|
// NOTE roc_panic is provided in the JS file, so it can throw an exception
|
||||||
|
|
||||||
extern fn roc__mainForHost_1_exposed(*RocStr) void;
|
extern fn roc__mainForHost_1_exposed(*RocStr) void;
|
||||||
|
|
|
@ -30,10 +30,6 @@ void roc_panic(void* ptr, unsigned int alignment) {
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* roc_memcpy(void* dest, const void* src, size_t n) {
|
|
||||||
return memcpy(dest, src, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* roc_memset(void* str, int c, size_t n) { return memset(str, c, n); }
|
void* roc_memset(void* str, int c, size_t n) { return memset(str, c, n); }
|
||||||
|
|
||||||
int roc_shm_open(char* name, int oflag, int mode) {
|
int roc_shm_open(char* name, int oflag, int mode) {
|
||||||
|
|
|
@ -44,11 +44,6 @@ pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dst, src, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
||||||
libc::memset(dst, c, n)
|
libc::memset(dst, c, n)
|
||||||
|
|
|
@ -33,10 +33,6 @@ export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
|
||||||
free(@alignCast(@alignOf(Align), @ptrCast([*]u8, c_ptr)));
|
free(@alignCast(@alignOf(Align), @ptrCast([*]u8, c_ptr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn roc_memcpy(dest: *anyopaque, src: *anyopaque, count: usize) callconv(.C) void {
|
|
||||||
_ = memcpy(dest, src, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE roc_panic is provided in the JS file, so it can throw an exception
|
// NOTE roc_panic is provided in the JS file, so it can throw an exception
|
||||||
|
|
||||||
extern fn roc__mainForHost_1_exposed(*RocStr) void;
|
extern fn roc__mainForHost_1_exposed(*RocStr) void;
|
||||||
|
|
|
@ -67,10 +67,6 @@ export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void {
|
||||||
std.process.exit(0);
|
std.process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn roc_memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void {
|
|
||||||
return memcpy(dst, src, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
||||||
return memset(dst, value, size);
|
return memset(dst, value, size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,11 +27,6 @@ __attribute__((noreturn)) void roc_panic(void *ptr, unsigned int alignment)
|
||||||
PyErr_SetString(PyExc_RuntimeError, (char *)ptr);
|
PyErr_SetString(PyExc_RuntimeError, (char *)ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *roc_memcpy(void *dest, const void *src, size_t n)
|
|
||||||
{
|
|
||||||
return memcpy(dest, src, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *roc_memset(void *str, int c, size_t n) { return memset(str, c, n); }
|
void *roc_memset(void *str, int c, size_t n) { return memset(str, c, n); }
|
||||||
|
|
||||||
// Reference counting
|
// Reference counting
|
||||||
|
|
|
@ -24,10 +24,6 @@ void roc_panic(void* ptr, unsigned int alignment) {
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* roc_memcpy(void* dest, const void* src, size_t n) {
|
|
||||||
return memcpy(dest, src, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* roc_memset(void* str, int c, size_t n) { return memset(str, c, n); }
|
void* roc_memset(void* str, int c, size_t n) { return memset(str, c, n); }
|
||||||
|
|
||||||
int roc_shm_open(char* name, int oflag, int mode) {
|
int roc_shm_open(char* name, int oflag, int mode) {
|
||||||
|
|
|
@ -23,11 +23,6 @@ __attribute__((noreturn)) void roc_panic(void *ptr, unsigned int alignment)
|
||||||
rb_raise(rb_eException, "%s", (char *)ptr);
|
rb_raise(rb_eException, "%s", (char *)ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *roc_memcpy(void *dest, const void *src, size_t n)
|
|
||||||
{
|
|
||||||
return memcpy(dest, src, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *roc_memset(void *str, int c, size_t n) { return memset(str, c, n); }
|
void *roc_memset(void *str, int c, size_t n) { return memset(str, c, n); }
|
||||||
|
|
||||||
// Reference counting
|
// Reference counting
|
||||||
|
|
|
@ -24,10 +24,6 @@ void roc_panic(void* ptr, unsigned int alignment) {
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* roc_memcpy(void* dest, const void* src, size_t n) {
|
|
||||||
return memcpy(dest, src, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* roc_memmove(void* dest, const void* src, size_t n){
|
void* roc_memmove(void* dest, const void* src, size_t n){
|
||||||
return memmove(dest, src, n);
|
return memmove(dest, src, n);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,10 @@ use std::os::raw::c_char;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use syntect::easy::HighlightLines;
|
use syntect::easy::HighlightLines;
|
||||||
|
use syntect::highlighting::{Style, ThemeSet};
|
||||||
|
use syntect::html::{ClassStyle, ClassedHTMLGenerator};
|
||||||
use syntect::parsing::SyntaxSet;
|
use syntect::parsing::SyntaxSet;
|
||||||
use syntect::highlighting::{ThemeSet, Style};
|
use syntect::util::LinesWithEndings;
|
||||||
use syntect::util::{LinesWithEndings};
|
|
||||||
use syntect::html::{ClassedHTMLGenerator, ClassStyle};
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#[link_name = "roc__transformFileContentForHost_1_exposed"]
|
#[link_name = "roc__transformFileContentForHost_1_exposed"]
|
||||||
|
@ -98,15 +98,6 @@ pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn roc_memcpy(
|
|
||||||
dest: *mut c_void,
|
|
||||||
src: *const c_void,
|
|
||||||
bytes: usize,
|
|
||||||
) -> *mut c_void {
|
|
||||||
libc::memcpy(dest, src, bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void {
|
||||||
libc::memset(dst, c, n)
|
libc::memset(dst, c, n)
|
||||||
|
@ -216,9 +207,9 @@ fn process_file(input_dir: &Path, output_dir: &Path, input_file: &Path) -> Resul
|
||||||
// And track a little bit of state
|
// And track a little bit of state
|
||||||
let mut in_code_block = false;
|
let mut in_code_block = false;
|
||||||
let mut is_roc_code = false;
|
let mut is_roc_code = false;
|
||||||
let syntax_set : syntect::parsing::SyntaxSet = SyntaxSet::load_defaults_newlines();
|
let syntax_set: syntect::parsing::SyntaxSet = SyntaxSet::load_defaults_newlines();
|
||||||
let theme_set : syntect::highlighting::ThemeSet = ThemeSet::load_defaults();
|
let theme_set: syntect::highlighting::ThemeSet = ThemeSet::load_defaults();
|
||||||
|
|
||||||
for event in parser {
|
for event in parser {
|
||||||
match event {
|
match event {
|
||||||
pulldown_cmark::Event::Code(code_str) => {
|
pulldown_cmark::Event::Code(code_str) => {
|
||||||
|
@ -227,23 +218,25 @@ fn process_file(input_dir: &Path, output_dir: &Path, input_file: &Path) -> Resul
|
||||||
.strip_prefix("roc!")
|
.strip_prefix("roc!")
|
||||||
.expect("expected leading 'roc!'");
|
.expect("expected leading 'roc!'");
|
||||||
|
|
||||||
let highlighted_html = roc_highlight::highlight_roc_code_inline(stripped.to_string().as_str());
|
let highlighted_html =
|
||||||
|
roc_highlight::highlight_roc_code_inline(stripped.to_string().as_str());
|
||||||
|
|
||||||
parser_with_highlighting.push(pulldown_cmark::Event::Html(
|
parser_with_highlighting.push(pulldown_cmark::Event::Html(
|
||||||
pulldown_cmark::CowStr::from(highlighted_html),
|
pulldown_cmark::CowStr::from(highlighted_html),
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
let inline_code = pulldown_cmark::CowStr::from(format!("<code>{}</code>", code_str));
|
let inline_code =
|
||||||
parser_with_highlighting.push(
|
pulldown_cmark::CowStr::from(format!("<code>{}</code>", code_str));
|
||||||
pulldown_cmark::Event::Html(inline_code)
|
parser_with_highlighting.push(pulldown_cmark::Event::Html(inline_code));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pulldown_cmark::Event::Start(pulldown_cmark::Tag::CodeBlock(cbk)) => {
|
pulldown_cmark::Event::Start(pulldown_cmark::Tag::CodeBlock(cbk)) => {
|
||||||
in_code_block = true;
|
in_code_block = true;
|
||||||
is_roc_code = is_roc_code_block(&cbk);
|
is_roc_code = is_roc_code_block(&cbk);
|
||||||
}
|
}
|
||||||
pulldown_cmark::Event::End(pulldown_cmark::Tag::CodeBlock(pulldown_cmark::CodeBlockKind::Fenced(extention_str))) => {
|
pulldown_cmark::Event::End(pulldown_cmark::Tag::CodeBlock(
|
||||||
|
pulldown_cmark::CodeBlockKind::Fenced(extention_str),
|
||||||
|
)) => {
|
||||||
if in_code_block {
|
if in_code_block {
|
||||||
match replace_code_with_static_file(&code_to_highlight, input_file) {
|
match replace_code_with_static_file(&code_to_highlight, input_file) {
|
||||||
None => {}
|
None => {}
|
||||||
|
@ -263,13 +256,19 @@ fn process_file(input_dir: &Path, output_dir: &Path, input_file: &Path) -> Resul
|
||||||
if is_roc_code {
|
if is_roc_code {
|
||||||
highlighted_html = roc_highlight::highlight_roc_code(&code_to_highlight)
|
highlighted_html = roc_highlight::highlight_roc_code(&code_to_highlight)
|
||||||
} else if let Some(syntax) = syntax_set.find_syntax_by_token(&extention_str) {
|
} else if let Some(syntax) = syntax_set.find_syntax_by_token(&extention_str) {
|
||||||
let mut h = HighlightLines::new(syntax, &theme_set.themes["base16-ocean.dark"]);
|
let mut h =
|
||||||
|
HighlightLines::new(syntax, &theme_set.themes["base16-ocean.dark"]);
|
||||||
|
|
||||||
let mut html_generator = ClassedHTMLGenerator::new_with_class_style(syntax, &syntax_set, ClassStyle::Spaced);
|
let mut html_generator = ClassedHTMLGenerator::new_with_class_style(
|
||||||
|
syntax,
|
||||||
|
&syntax_set,
|
||||||
|
ClassStyle::Spaced,
|
||||||
|
);
|
||||||
for line in LinesWithEndings::from(&code_to_highlight) {
|
for line in LinesWithEndings::from(&code_to_highlight) {
|
||||||
html_generator.parse_html_for_line_which_includes_newline(line);
|
html_generator.parse_html_for_line_which_includes_newline(line);
|
||||||
}
|
}
|
||||||
highlighted_html = format!("<pre><samp>{}</pre></samp>", html_generator.finalize())
|
highlighted_html =
|
||||||
|
format!("<pre><samp>{}</pre></samp>", html_generator.finalize())
|
||||||
} else {
|
} else {
|
||||||
highlighted_html = format!("<pre><samp>{}</pre></samp>", &code_to_highlight)
|
highlighted_html = format!("<pre><samp>{}</pre></samp>", &code_to_highlight)
|
||||||
}
|
}
|
||||||
|
@ -362,12 +361,11 @@ fn is_roc_code_block(cbk: &pulldown_cmark::CodeBlockKind) -> bool {
|
||||||
fn replace_code_with_static_file(code: &str, input_file: &Path) -> Option<String> {
|
fn replace_code_with_static_file(code: &str, input_file: &Path) -> Option<String> {
|
||||||
let input_dir = input_file.parent()?;
|
let input_dir = input_file.parent()?;
|
||||||
let trimmed_code = code.trim();
|
let trimmed_code = code.trim();
|
||||||
|
|
||||||
// Confirm the code block starts with a `file:` tag
|
// Confirm the code block starts with a `file:` tag
|
||||||
match trimmed_code.strip_prefix("file:") {
|
match trimmed_code.strip_prefix("file:") {
|
||||||
None => None,
|
None => None,
|
||||||
Some(path) => {
|
Some(path) => {
|
||||||
|
|
||||||
// File must be located in input folder or sub-directory
|
// File must be located in input folder or sub-directory
|
||||||
if path.contains("../") {
|
if path.contains("../") {
|
||||||
panic!("ERROR File must be located within the input diretory!");
|
panic!("ERROR File must be located within the input diretory!");
|
||||||
|
@ -378,7 +376,10 @@ fn replace_code_with_static_file(code: &str, input_file: &Path) -> Option<String
|
||||||
// Check file exists before opening
|
// Check file exists before opening
|
||||||
match file_path.try_exists() {
|
match file_path.try_exists() {
|
||||||
Err(_) | Ok(false) => {
|
Err(_) | Ok(false) => {
|
||||||
panic!("ERROR File does not exist: \"{}\"", file_path.to_str().unwrap());
|
panic!(
|
||||||
|
"ERROR File does not exist: \"{}\"",
|
||||||
|
file_path.to_str().unwrap()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Ok(true) => {
|
Ok(true) => {
|
||||||
let vec_u8 = fs::read(file_path).ok()?;
|
let vec_u8 = fs::read(file_path).ok()?;
|
||||||
|
@ -388,4 +389,4 @@ fn replace_code_with_static_file(code: &str, input_file: &Path) -> Option<String
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,10 +28,6 @@ export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
|
||||||
free(@alignCast(@alignOf(Align), @ptrCast([*]u8, c_ptr)));
|
free(@alignCast(@alignOf(Align), @ptrCast([*]u8, c_ptr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn roc_memcpy(dest: *anyopaque, src: *anyopaque, count: usize) callconv(.C) void {
|
|
||||||
_ = memcpy(dest, src, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn roc_panic(message: RocStr, tag_id: u32) callconv(.C) void {
|
export fn roc_panic(message: RocStr, tag_id: u32) callconv(.C) void {
|
||||||
_ = tag_id;
|
_ = tag_id;
|
||||||
const msg = @ptrCast([*:0]const u8, c_ptr);
|
const msg = @ptrCast([*:0]const u8, c_ptr);
|
||||||
|
|
|
@ -28,10 +28,6 @@ export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
|
||||||
free(@alignCast(@alignOf(Align), @ptrCast([*]u8, c_ptr)));
|
free(@alignCast(@alignOf(Align), @ptrCast([*]u8, c_ptr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn roc_memcpy(dest: *anyopaque, src: *anyopaque, count: usize) callconv(.C) void {
|
|
||||||
_ = memcpy(dest, src, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void {
|
export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void {
|
||||||
_ = tag_id;
|
_ = tag_id;
|
||||||
const msg = @ptrCast([*:0]const u8, c_ptr);
|
const msg = @ptrCast([*:0]const u8, c_ptr);
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
[files]
|
[files]
|
||||||
extend-exclude = ["crates/vendor/", "examples/static-site-gen/input/"]
|
extend-exclude = ["crates/vendor/", "examples/static-site-gen/input/", "COPYRIGHT"]
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue