diff --git a/crates/cli/tests/cli_run.rs b/crates/cli/tests/cli_run.rs index f753c5e866..8c6f3683e4 100644 --- a/crates/cli/tests/cli_run.rs +++ b/crates/cli/tests/cli_run.rs @@ -1227,6 +1227,40 @@ mod cli_run { ); } + #[test] + #[serial(multi_dep_thunk)] + #[cfg_attr(windows, ignore)] + fn run_package_unoptimized() { + check_output_with_stdin( + &fixture_file("packages", "app.roc"), + &[], + "packages-test", + &[], + &[], + &[], + "I am Dep2.value2\n", + UseValgrind::Yes, + TestCliCommands::Run, + ); + } + + #[test] + #[serial(multi_dep_thunk)] + #[cfg_attr(windows, ignore)] + fn run_package_optimized() { + check_output_with_stdin( + &fixture_file("packages", "app.roc"), + &[], + "packages-test", + &[OPTIMIZE_FLAG], + &[], + &[], + "I am Dep2.value2\n", + UseValgrind::Yes, + TestCliCommands::Run, + ); + } + #[test] fn known_type_error() { check_compile_error( diff --git a/crates/cli/tests/fixtures/packages/app.roc b/crates/cli/tests/fixtures/packages/app.roc new file mode 100644 index 0000000000..a37bee685b --- /dev/null +++ b/crates/cli/tests/fixtures/packages/app.roc @@ -0,0 +1,6 @@ +app "packages-test" + packages { pf: "platform/main.roc", json: "json/main.roc", csv: "csv/main.roc" } + imports [json.JsonParser, csv.Csv] + provides [main] to pf + +main = "Hello, World! \(JsonParser.example) \(Csv.example)" diff --git a/crates/cli/tests/fixtures/packages/csv/Csv.roc b/crates/cli/tests/fixtures/packages/csv/Csv.roc new file mode 100644 index 0000000000..55367d1b9e --- /dev/null +++ b/crates/cli/tests/fixtures/packages/csv/Csv.roc @@ -0,0 +1,6 @@ +interface Csv + exposes [example] + imports [dep.CsvDep] + +example : Str +example = "This text came from a CSV package: \(CsvDep.stuff)!" \ No newline at end of file diff --git a/crates/cli/tests/fixtures/packages/csv/main.roc b/crates/cli/tests/fixtures/packages/csv/main.roc new file mode 100644 index 0000000000..12d60ce654 --- /dev/null +++ b/crates/cli/tests/fixtures/packages/csv/main.roc @@ -0,0 +1,3 @@ +package "csv" + exposes [Csv] + packages {} \ No newline at end of file diff --git a/examples/json/JsonParser.roc b/crates/cli/tests/fixtures/packages/json/JsonParser.roc similarity index 100% rename from examples/json/JsonParser.roc rename to crates/cli/tests/fixtures/packages/json/JsonParser.roc diff --git a/examples/json/main.roc b/crates/cli/tests/fixtures/packages/json/main.roc similarity index 100% rename from examples/json/main.roc rename to crates/cli/tests/fixtures/packages/json/main.roc diff --git a/crates/cli/tests/fixtures/packages/platform/host.zig b/crates/cli/tests/fixtures/packages/platform/host.zig new file mode 100644 index 0000000000..bb797f2bf3 --- /dev/null +++ b/crates/cli/tests/fixtures/packages/platform/host.zig @@ -0,0 +1,127 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const str = @import("str"); +const RocStr = str.RocStr; +const testing = std.testing; +const expectEqual = testing.expectEqual; +const expect = testing.expect; + +comptime { + // This is a workaround for https://github.com/ziglang/zig/issues/8218 + // which is only necessary on macOS. + // + // Once that issue is fixed, we can undo the changes in + // 177cf12e0555147faa4d436e52fc15175c2c4ff0 and go back to passing + // -fcompiler-rt in link.rs instead of doing this. Note that this + // workaround is present in many host.zig files, so make sure to undo + // it everywhere! + if (builtin.os.tag == .macos) { + _ = @import("compiler_rt"); + } +} + +const mem = std.mem; +const Allocator = mem.Allocator; + +extern fn roc__mainForHost_1_exposed_generic(*RocStr) void; + +const Align = 2 * @alignOf(usize); +extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque; +extern fn realloc(c_ptr: [*]align(Align) u8, size: usize) callconv(.C) ?*anyopaque; +extern fn free(c_ptr: [*]align(Align) u8) callconv(.C) void; +extern fn memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void; +extern fn memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void; + +export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*anyopaque { + _ = alignment; + return malloc(size); +} + +export fn roc_realloc(c_ptr: *anyopaque, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*anyopaque { + _ = old_size; + _ = alignment; + return realloc(@alignCast(16, @ptrCast([*]u8, c_ptr)), new_size); +} + +export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void { + _ = alignment; + 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 { + return memset(dst, value, size); +} + +export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void { + _ = tag_id; + + const stderr = std.io.getStdErr().writer(); + const msg = @ptrCast([*:0]const u8, c_ptr); + stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable; + std.process.exit(0); +} + +extern fn kill(pid: c_int, sig: c_int) c_int; +extern fn shm_open(name: *const i8, oflag: c_int, mode: c_uint) c_int; +extern fn mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) *anyopaque; +extern fn getppid() c_int; + +fn roc_getppid() callconv(.C) c_int { + return getppid(); +} + +fn roc_getppid_windows_stub() callconv(.C) c_int { + return 0; +} + +fn roc_shm_open(name: *const i8, oflag: c_int, mode: c_uint) callconv(.C) c_int { + return shm_open(name, oflag, mode); +} +fn roc_mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) callconv(.C) *anyopaque { + return mmap(addr, length, prot, flags, fd, offset); +} + +comptime { + if (builtin.os.tag == .macos or builtin.os.tag == .linux) { + @export(roc_getppid, .{ .name = "roc_getppid", .linkage = .Strong }); + @export(roc_mmap, .{ .name = "roc_mmap", .linkage = .Strong }); + @export(roc_shm_open, .{ .name = "roc_shm_open", .linkage = .Strong }); + } + + if (builtin.os.tag == .windows) { + @export(roc_getppid_windows_stub, .{ .name = "roc_getppid", .linkage = .Strong }); + } +} + +const Unit = extern struct {}; + +pub export fn main() i32 { + const stdout = std.io.getStdOut().writer(); + const stderr = std.io.getStdErr().writer(); + + var timer = std.time.Timer.start() catch unreachable; + + // actually call roc to populate the callresult + var callresult = RocStr.empty(); + roc__mainForHost_1_exposed_generic(&callresult); + + const nanos = timer.read(); + const seconds = (@intToFloat(f64, nanos) / 1_000_000_000.0); + + // stdout the result + stdout.print("{s}\n", .{callresult.asSlice()}) catch unreachable; + + callresult.deinit(); + + stderr.print("runtime: {d:.3}ms\n", .{seconds * 1000}) catch unreachable; + + return 0; +} + +fn to_seconds(tms: std.os.timespec) f64 { + return @intToFloat(f64, tms.tv_sec) + (@intToFloat(f64, tms.tv_nsec) / 1_000_000_000.0); +} diff --git a/crates/cli/tests/fixtures/packages/platform/main.roc b/crates/cli/tests/fixtures/packages/platform/main.roc new file mode 100644 index 0000000000..edc3368f93 --- /dev/null +++ b/crates/cli/tests/fixtures/packages/platform/main.roc @@ -0,0 +1,9 @@ +platform "multi-module" + requires {}{ main : Str } + exposes [] + packages {} + imports [] + provides [mainForHost] + +mainForHost : Str +mainForHost = main