diff --git a/Cargo.lock b/Cargo.lock index 0894b484b8..7bb567e093 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3314,37 +3314,6 @@ dependencies = [ "libc", ] -[[package]] -name = "roc-bindgen" -version = "0.1.0" -dependencies = [ - "bumpalo", - "clap 3.2.11", - "cli_utils", - "ctor", - "dircpy", - "fnv", - "indexmap", - "indoc", - "pretty_assertions", - "roc_builtins", - "roc_can", - "roc_collections", - "roc_error_macros", - "roc_load", - "roc_module", - "roc_mono", - "roc_reporting", - "roc_std", - "roc_target", - "roc_test_utils", - "roc_types", - "strum", - "strum_macros", - "target-lexicon", - "tempfile", -] - [[package]] name = "roc_alias_analysis" version = "0.1.0" @@ -3475,6 +3444,7 @@ dependencies = [ "roc_error_macros", "roc_fmt", "roc_gen_llvm", + "roc_glue", "roc_linker", "roc_load", "roc_module", @@ -3737,6 +3707,36 @@ dependencies = [ "roc_target", ] +[[package]] +name = "roc_glue" +version = "0.1.0" +dependencies = [ + "bumpalo", + "clap 3.2.11", + "cli_utils", + "dircpy", + "fnv", + "indexmap", + "indoc", + "pretty_assertions", + "roc_builtins", + "roc_can", + "roc_collections", + "roc_error_macros", + "roc_load", + "roc_module", + "roc_mono", + "roc_reporting", + "roc_std", + "roc_target", + "roc_test_utils", + "roc_types", + "strum", + "strum_macros", + "target-lexicon", + "tempfile", +] + [[package]] name = "roc_highlight" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 21aeb513a5..097aa11a01 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ members = [ "crates/vendor/inkwell", "crates/vendor/pathfinding", "crates/vendor/pretty", - "crates/bindgen", + "crates/glue", "crates/editor", "crates/ast", "crates/cli", diff --git a/crates/bindgen/src/bindgen_c.rs b/crates/bindgen/src/bindgen_c.rs deleted file mode 100644 index c19b087c87..0000000000 --- a/crates/bindgen/src/bindgen_c.rs +++ /dev/null @@ -1,40 +0,0 @@ -use std::io; - -static TEMPLATE: &[u8] = include_bytes!("../templates/template.c"); - -pub fn write_template(writer: &mut impl io::Write) -> io::Result<()> { - writer.write_all(TEMPLATE)?; - - Ok(()) -} - -// pub fn write_bindings(_writer: &mut impl io::Write) -> io::Result<()> { -// extern struct RocStr roc__mainForHost_1_exposed(); - -// int main() { -// struct RocStr str = roc__mainForHost_1_exposed(); - -// // Determine str_len and the str_bytes pointer, -// // taking into account the small string optimization. -// size_t str_len = roc_str_len(str); -// char* str_bytes; - -// if (is_small_str(str)) { -// str_bytes = (char*)&str; -// } else { -// str_bytes = str.bytes; -// } - -// // Write to stdout -// if (write(1, str_bytes, str_len) >= 0) { -// // Writing succeeded! -// return 0; -// } else { -// printf("Error writing to stdout: %s\n", strerror(errno)); - -// return 1; -// } -// } - -// Ok(()) -// } diff --git a/crates/bindgen/src/bindgen_zig.rs b/crates/bindgen/src/bindgen_zig.rs deleted file mode 100644 index d16c500d04..0000000000 --- a/crates/bindgen/src/bindgen_zig.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::io; - -static TEMPLATE: &[u8] = include_bytes!("../templates/template.zig"); - -pub fn write_template(writer: &mut impl io::Write) -> io::Result<()> { - writer.write_all(TEMPLATE)?; - - Ok(()) -} - -pub fn write_bindings(_writer: &mut impl io::Write) -> io::Result<()> { - // extern "C" { - // #[link_name = "roc__mainForHost_1_exposed"] - // fn roc_main() -> RocStr; - // } - - Ok(()) -} diff --git a/crates/bindgen/src/main.rs b/crates/bindgen/src/main.rs deleted file mode 100644 index 2586623974..0000000000 --- a/crates/bindgen/src/main.rs +++ /dev/null @@ -1,113 +0,0 @@ -use clap::Parser; -use roc_bindgen::bindgen_rs; -use roc_bindgen::load::load_types; -use roc_load::Threading; -use std::ffi::OsStr; -use std::fs::File; -use std::io::{ErrorKind, Write}; -use std::path::PathBuf; -use std::process; - -/// Printed in error messages if you try to use an unsupported extension. -const SUPPORTED_EXTENSIONS: &str = ".c, .rs, .zig, and .json"; - -// TODO add an option for --targets so that you can specify -// e.g. 64-bit, 32-bit, *and* 16-bit (which can matter for alignment because of pointers) -#[derive(Debug, Parser)] -#[clap(about)] -struct Opts { - /// The path to the `platform` module .roc file - platform_module: PathBuf, - - /// The output file, e.g. `test.rs` - dest: PathBuf, -} - -enum OutputType { - Rust, - C, - Zig, - Json, -} - -pub fn main() { - let opts = Opts::parse(); - let input_path = opts.platform_module; - let output_path = opts.dest; - let output_type = match output_path.extension().and_then(OsStr::to_str) { - Some("rs") => OutputType::Rust, - Some("c") => OutputType::C, - Some("zig") => OutputType::Zig, - Some("json") => OutputType::Json, - Some(other) => { - eprintln!( - "Unsupported output file extension: \".{}\" - currently supported extensions are {}", - other, - SUPPORTED_EXTENSIONS - ); - - process::exit(1); - } - None => { - eprintln!("The output file path needs to have a file extension in order to tell what output format to use. Currently supported extensions are {}", SUPPORTED_EXTENSIONS); - - process::exit(1); - } - }; - - match load_types(input_path.clone(), Threading::AllAvailable) { - Ok(types_and_targets) => { - let mut file = File::create(output_path.clone()).unwrap_or_else(|err| { - eprintln!( - "Unable to create output file {} - {:?}", - output_path.display(), - err - ); - - process::exit(1); - }); - - let mut buf; - match output_type { - OutputType::Rust => { - buf = std::str::from_utf8(bindgen_rs::HEADER).unwrap().to_string(); - let body = bindgen_rs::emit(&types_and_targets); - - buf.push_str(&body); - } - OutputType::C => todo!("TODO: Generate bindings for C"), - OutputType::Zig => todo!("TODO: Generate bindings for Zig"), - OutputType::Json => todo!("TODO: Generate bindings for JSON"), - }; - - file.write_all(buf.as_bytes()).unwrap_or_else(|err| { - eprintln!( - "Unable to write bindings to output file {} - {:?}", - output_path.display(), - err - ); - - process::exit(1); - }); - - println!( - "🎉 Generated type declarations in:\n\n\t{}", - output_path.display() - ); - } - Err(err) => match err.kind() { - ErrorKind::NotFound => { - eprintln!("Platform module file not found: {}", input_path.display()); - process::exit(1); - } - error => { - eprintln!( - "Error loading platform module file {} - {:?}", - input_path.display(), - error - ); - process::exit(1); - } - }, - } -} diff --git a/crates/bindgen/templates/template.c b/crates/bindgen/templates/template.c deleted file mode 100644 index 4e28b6d042..0000000000 --- a/crates/bindgen/templates/template.c +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include -#include -#include -#include -#include - -void* roc_alloc(size_t size, unsigned int alignment) { return malloc(size); } - -void* roc_realloc(void* ptr, size_t new_size, size_t old_size, unsigned int alignment) { - return realloc(ptr, new_size); -} - -void roc_dealloc(void* ptr, unsigned int alignment) { free(ptr); } - -void roc_panic(void* ptr, unsigned int alignment) { - char* msg = (char*)ptr; - fprintf(stderr, - "Application crashed with message\n\n %s\n\nShutting down\n", msg); - 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); } - -/////////////////////////////////////////////////////////////////////////// -// -// roc_std -// -/////////////////////////////////////////////////////////////////////////// - -struct RocStr { - char* bytes; - size_t len; -}; - -bool is_small_str(struct RocStr str) { return ((ssize_t)str.len) < 0; } - -// Determine the length of the string, taking into -// account the small string optimization -size_t roc_str_len(struct RocStr str) { - char* bytes = (char*)&str; - char last_byte = bytes[sizeof(str) - 1]; - char last_byte_xored = last_byte ^ 0b10000000; - size_t small_len = (size_t)(last_byte_xored); - size_t big_len = str.len; - - // Avoid branch misprediction costs by always - // determining both small_len and big_len, - // so this compiles to a cmov instruction. - if (is_small_str(str)) { - return small_len; - } else { - return big_len; - } -} diff --git a/crates/bindgen/templates/template.rs b/crates/bindgen/templates/template.rs deleted file mode 100644 index 3ca441f5d2..0000000000 --- a/crates/bindgen/templates/template.rs +++ /dev/null @@ -1,79 +0,0 @@ -#![allow(non_snake_case)] - -use core::ffi::c_void; - -// TODO don't have these depend on the libc crate; instead, use default -// allocator, built-in memset, etc. - -#[no_mangle] -pub unsafe extern "C" fn roc_alloc(size: usize, _alignment: u32) -> *mut c_void { - return libc::malloc(size); -} - -#[no_mangle] -pub unsafe extern "C" fn roc_realloc( - c_ptr: *mut c_void, - new_size: usize, - _old_size: usize, - _alignment: u32, -) -> *mut c_void { - return libc::realloc(c_ptr, new_size); -} - -#[no_mangle] -pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { - return libc::free(c_ptr); -} - -#[no_mangle] -pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { - use std::ffi::CStr; - use std::os::raw::c_char; - - match tag_id { - 0 => { - let slice = CStr::from_ptr(c_ptr as *const c_char); - let string = slice.to_str().unwrap(); - eprintln!("Roc hit a panic: {}", string); - std::process::exit(1); - } - _ => todo!(), - } -} - -#[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] -pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void { - libc::memset(dst, c, n) -} - -//////////////////////////////////////////////////////////////////////////// -// -// TODO: rust_main should be removed once we use surgical linking everywhere. -// It's just a workaround to get cargo to build an object file the way -// the non-surgical linker needs it to. The surgical linker works on -// executables, not object files, so this workaround is not needed there. -// -//////////////////////////////////////////////////////////////////////////// -#[no_mangle] -pub extern "C" fn rust_main() -> i32 { - use roc_std::RocStr; - - unsafe { - let roc_str = roc_main(); - - let len = roc_str.len(); - let str_bytes = roc_str.as_bytes().as_ptr() as *const libc::c_void; - - if libc::write(1, str_bytes, len) < 0 { - panic!("Writing to stdout failed!"); - } - } - - // Exit code - 0 -} diff --git a/crates/bindgen/templates/template.zig b/crates/bindgen/templates/template.zig deleted file mode 100644 index a2e73bd5af..0000000000 --- a/crates/bindgen/templates/template.zig +++ /dev/null @@ -1,71 +0,0 @@ -const std = @import("std"); -const str = @import("str"); - -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 (std.builtin.os.tag == .macos) { - _ = @import("compiler_rt"); - } -} - -const Align = 2 * @alignOf(usize); -extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque; -extern fn realloc(c_ptr: [*]align(Align) u8, size: usize) callconv(.C) ?*anyopaque; -extern fn free(c_ptr: [*]align(Align) u8) callconv(.C) void; -extern fn memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void; -extern fn memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void; - -const DEBUG: bool = false; - -export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*anyopaque { - if (DEBUG) { - var ptr = malloc(size); - const stdout = std.io.getStdOut().writer(); - stdout.print("alloc: {d} (alignment {d}, size {d})\n", .{ ptr, alignment, size }) catch unreachable; - return ptr; - } else { - return malloc(size); - } -} - -export fn roc_realloc(c_ptr: *anyopaque, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*anyopaque { - if (DEBUG) { - const stdout = std.io.getStdOut().writer(); - stdout.print("realloc: {d} (alignment {d}, old_size {d})\n", .{ c_ptr, alignment, old_size }) catch unreachable; - } - - return realloc(@alignCast(Align, @ptrCast([*]u8, c_ptr)), new_size); -} - -export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void { - if (DEBUG) { - const stdout = std.io.getStdOut().writer(); - stdout.print("dealloc: {d} (alignment {d})\n", .{ c_ptr, alignment }) catch unreachable; - } - - free(@alignCast(Align, @ptrCast([*]u8, c_ptr))); -} - -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); -} - -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); -} diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 6a4bfc310e..7a0e21a809 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -44,6 +44,7 @@ target-all = [ roc_collections = { path = "../compiler/collections" } roc_can = { path = "../compiler/can" } roc_docs = { path = "../docs" } +roc_glue = { path = "../glue" } roc_parse = { path = "../compiler/parse" } roc_region = { path = "../compiler/region" } roc_module = { path = "../compiler/module" } diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs index 9a1867311a..1e2618cc9e 100644 --- a/crates/cli/src/lib.rs +++ b/crates/cli/src/lib.rs @@ -43,6 +43,7 @@ pub const CMD_CHECK: &str = "check"; pub const CMD_VERSION: &str = "version"; pub const CMD_FORMAT: &str = "format"; pub const CMD_TEST: &str = "test"; +pub const CMD_GLUE: &str = "glue"; pub const FLAG_DEBUG: &str = "debug"; pub const FLAG_DEV: &str = "dev"; @@ -59,6 +60,7 @@ pub const FLAG_VALGRIND: &str = "valgrind"; pub const FLAG_CHECK: &str = "check"; pub const ROC_FILE: &str = "ROC_FILE"; pub const ROC_DIR: &str = "ROC_DIR"; +pub const GLUE_FILE: &str = "GLUE_FILE"; pub const DIRECTORY_OR_FILES: &str = "DIRECTORY_OR_FILES"; pub const ARGS_FOR_APP: &str = "ARGS_FOR_APP"; @@ -171,7 +173,7 @@ pub fn build_app<'a>() -> Command<'a> { ) ) .subcommand(Command::new(CMD_TEST) - .about("Run all top-level `expect`s in a root module and any modules it imports.") + .about("Run all top-level `expect`s in a main module and any modules it imports.") .arg(flag_optimize.clone()) .arg(flag_max_threads.clone()) .arg(flag_opt_size.clone()) @@ -183,7 +185,7 @@ pub fn build_app<'a>() -> Command<'a> { .arg(flag_valgrind.clone()) .arg( Arg::new(ROC_FILE) - .help("The .roc file for the root module") + .help("The .roc file for the main module") .allow_invalid_utf8(true) .required(false) .default_value(DEFAULT_ROC_FILENAME) @@ -246,6 +248,21 @@ pub fn build_app<'a>() -> Command<'a> { .allow_invalid_utf8(true) ) ) + .subcommand(Command::new(CMD_GLUE) + .about("Generate glue code between a platform's Roc API and its host language.") + .arg( + Arg::new(ROC_FILE) + .help("The .roc file for the platform module") + .allow_invalid_utf8(true) + .required(true) + ) + .arg( + Arg::new(GLUE_FILE) + .help("The filename for the generated glue code. Currently, this must be a .rs file because only Rust glue generation is supported so far.") + .allow_invalid_utf8(true) + .required(true) + ) + ) .trailing_var_arg(true) .arg(flag_optimize) .arg(flag_max_threads.clone()) diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 537c0ccc47..86b5d52e60 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -2,11 +2,12 @@ use roc_build::link::LinkType; use roc_cli::build::check_file; use roc_cli::{ build_app, format, test, BuildConfig, FormatMode, Target, CMD_BUILD, CMD_CHECK, CMD_DOCS, - CMD_EDIT, CMD_FORMAT, CMD_REPL, CMD_RUN, CMD_TEST, CMD_VERSION, DIRECTORY_OR_FILES, FLAG_CHECK, - FLAG_LIB, FLAG_NO_LINK, FLAG_TARGET, FLAG_TIME, ROC_FILE, + CMD_EDIT, CMD_FORMAT, CMD_GLUE, CMD_REPL, CMD_RUN, CMD_TEST, CMD_VERSION, DIRECTORY_OR_FILES, + FLAG_CHECK, FLAG_LIB, FLAG_NO_LINK, FLAG_TARGET, FLAG_TIME, GLUE_FILE, ROC_FILE, }; use roc_docs::generate_docs_html; use roc_error_macros::user_error; +use roc_glue; use roc_load::{LoadingProblem, Threading}; use std::fs::{self, FileType}; use std::io; @@ -64,6 +65,18 @@ fn main() -> io::Result<()> { Ok(1) } } + Some((CMD_GLUE, matches)) => { + let input_path = Path::new(matches.value_of_os(ROC_FILE).unwrap()); + let output_path = Path::new(matches.value_of_os(GLUE_FILE).unwrap()); + + if Some("rs") == output_path.extension().and_then(OsStr::to_str) { + roc_glue::generate(input_path, output_path) + } else { + eprintln!("Currently, `roc glue` only supports generating Rust glue files (with the .rs extension). In the future, the plan is to decouple `roc glue` from any particular output format, by having it accept a second .roc file which gets executed as a plugin to generate glue code for any desired language. However, this has not yet been implemented, and for now only .rs is supported."); + + Ok(1) + } + } Some((CMD_BUILD, matches)) => { let target: Target = matches.value_of_t(FLAG_TARGET).unwrap_or_default(); diff --git a/crates/cli_utils/src/helpers.rs b/crates/cli_utils/src/helpers.rs index 2598504ae3..fb8c63b370 100644 --- a/crates/cli_utils/src/helpers.rs +++ b/crates/cli_utils/src/helpers.rs @@ -65,22 +65,18 @@ where run_with_stdin(&roc_binary_path, args, stdin_vals) } -pub fn run_bindgen(args: I) -> Out +pub fn run_glue(args: I) -> Out where I: IntoIterator, S: AsRef, { - run_with_stdin(&path_to_bindgen_binary(), args, &[]) + run_with_stdin(&path_to_roc_binary(), args, &[]) } pub fn path_to_roc_binary() -> PathBuf { path_to_binary("roc") } -pub fn path_to_bindgen_binary() -> PathBuf { - path_to_binary("roc-bindgen") -} - pub fn path_to_binary(binary_name: &str) -> PathBuf { // Adapted from https://github.com/volta-cli/volta/blob/cefdf7436a15af3ce3a38b8fe53bb0cfdb37d3dd/tests/acceptance/support/sandbox.rs#L680 // by the Volta Contributors - license information can be found in diff --git a/crates/compiler/load_internal/src/file.rs b/crates/compiler/load_internal/src/file.rs index 7643d209d1..615e7ef9d8 100644 --- a/crates/compiler/load_internal/src/file.rs +++ b/crates/compiler/load_internal/src/file.rs @@ -3766,7 +3766,7 @@ fn send_header_two<'a>( { // If we don't have an app module id (e.g. because we're doing - // `roc check myplatform.roc` or because we're doing bindgen), + // `roc check myplatform.roc` or because we're generating glue code), // insert the `requires` symbols into the platform module's IdentIds. // // Otherwise, get them from the app module's IdentIds, because it diff --git a/crates/compiler/mono/src/layout.rs b/crates/compiler/mono/src/layout.rs index 952ccacb84..82a53ae626 100644 --- a/crates/compiler/mono/src/layout.rs +++ b/crates/compiler/mono/src/layout.rs @@ -3304,7 +3304,7 @@ impl<'a> LayoutIds<'a> { } /// Compare two fields when sorting them for code gen. -/// This is called by both code gen and bindgen, so that +/// This is called by both code gen and glue, so that /// their field orderings agree. #[inline(always)] pub fn cmp_fields( diff --git a/crates/bindgen/Cargo.toml b/crates/glue/Cargo.toml similarity index 83% rename from crates/bindgen/Cargo.toml rename to crates/glue/Cargo.toml index 3311d7111f..b7e08114fd 100644 --- a/crates/bindgen/Cargo.toml +++ b/crates/glue/Cargo.toml @@ -1,17 +1,9 @@ [package] -name = "roc-bindgen" +name = "roc_glue" version = "0.1.0" authors = ["The Roc Contributors"] license = "UPL-1.0" -repository = "https://github.com/rtfeldman/roc" edition = "2021" -description = "A CLI for roc-bindgen" - -[[bin]] -name = "roc-bindgen" -path = "src/main.rs" -test = false -bench = false [dependencies] roc_std = { path = "../roc_std" } @@ -40,4 +32,3 @@ indoc = "1.0.3" cli_utils = { path = "../cli_utils" } roc_test_utils = { path = "../test_utils" } dircpy = "0.3.9" -ctor = "0.1.22" diff --git a/crates/bindgen/src/enums.rs b/crates/glue/src/enums.rs similarity index 100% rename from crates/bindgen/src/enums.rs rename to crates/glue/src/enums.rs diff --git a/crates/bindgen/src/lib.rs b/crates/glue/src/lib.rs similarity index 50% rename from crates/bindgen/src/lib.rs rename to crates/glue/src/lib.rs index 45257ecef2..4c78e97495 100644 --- a/crates/bindgen/src/lib.rs +++ b/crates/glue/src/lib.rs @@ -1,7 +1,7 @@ -pub mod bindgen_c; -pub mod bindgen_rs; -pub mod bindgen_zig; pub mod enums; pub mod load; +pub mod rust_glue; pub mod structs; pub mod types; + +pub use load::generate; diff --git a/crates/bindgen/src/load.rs b/crates/glue/src/load.rs similarity index 50% rename from crates/bindgen/src/load.rs rename to crates/glue/src/load.rs index 7bf2bbc717..0b942325b2 100644 --- a/crates/bindgen/src/load.rs +++ b/crates/glue/src/load.rs @@ -1,13 +1,68 @@ +use crate::rust_glue; use crate::types::{Env, Types}; use bumpalo::Bump; -use roc_load::{LoadedModule, Threading}; +use roc_load::{LoadedModule, LoadingProblem, Threading}; use roc_reporting::report::RenderTarget; use roc_target::{Architecture, TargetInfo}; -use std::io; -use std::path::PathBuf; +use std::fs::File; +use std::io::{self, ErrorKind, Write}; +use std::path::{Path, PathBuf}; +use std::process; use strum::IntoEnumIterator; use target_lexicon::Triple; +pub fn generate(input_path: &Path, output_path: &Path) -> io::Result { + match load_types(input_path.to_path_buf(), Threading::AllAvailable) { + Ok(types_and_targets) => { + let mut file = File::create(output_path).unwrap_or_else(|err| { + eprintln!( + "Unable to create output file {} - {:?}", + output_path.display(), + err + ); + + process::exit(1); + }); + + let mut buf = std::str::from_utf8(rust_glue::HEADER).unwrap().to_string(); + let body = rust_glue::emit(&types_and_targets); + + buf.push_str(&body); + + file.write_all(buf.as_bytes()).unwrap_or_else(|err| { + eprintln!( + "Unable to write bindings to output file {} - {:?}", + output_path.display(), + err + ); + + process::exit(1); + }); + + println!( + "🎉 Generated type declarations in:\n\n\t{}", + output_path.display() + ); + + Ok(0) + } + Err(err) => match err.kind() { + ErrorKind::NotFound => { + eprintln!("Platform module file not found: {}", input_path.display()); + process::exit(1); + } + error => { + eprintln!( + "Error loading platform module file {} - {:?}", + input_path.display(), + error + ); + process::exit(1); + } + }, + } +} + pub fn load_types( full_file_path: PathBuf, threading: Threading, @@ -32,7 +87,16 @@ pub fn load_types( RenderTarget::Generic, threading, ) - .expect("Problem loading platform module"); + .unwrap_or_else(|problem| match problem { + LoadingProblem::FormattedReport(report) => { + eprintln!("{}", report); + + process::exit(1); + } + problem => { + todo!("{:?}", problem); + } + }); let decls = declarations_by_id.remove(&home).unwrap(); let subs = solved.inner_mut(); @@ -42,7 +106,7 @@ pub fn load_types( if !can_problems.is_empty() || !type_problems.is_empty() { todo!( - "Gracefully report compilation problems during bindgen: {:?}, {:?}", + "Gracefully report compilation problems during glue generation: {:?}, {:?}", can_problems, type_problems ); diff --git a/crates/bindgen/src/bindgen_rs.rs b/crates/glue/src/rust_glue.rs similarity index 99% rename from crates/bindgen/src/bindgen_rs.rs rename to crates/glue/src/rust_glue.rs index 08e9027e32..f40896b929 100644 --- a/crates/bindgen/src/bindgen_rs.rs +++ b/crates/glue/src/rust_glue.rs @@ -3,7 +3,6 @@ use indexmap::IndexMap; use roc_target::{Architecture, TargetInfo}; use std::fmt::{Display, Write}; -pub static TEMPLATE: &[u8] = include_bytes!("../templates/template.rs"); pub static HEADER: &[u8] = include_bytes!("../templates/header.rs"); const INDENT: &str = " "; const DISCRIMINANT_DOC_COMMENT: &str = @@ -255,7 +254,7 @@ fn add_type(target_info: TargetInfo, id: TypeId, types: &Types, impls: &mut Impl // so no extra work needs to happen. } RocType::Function { .. } => { - // TODO actually bindgen functions! + // TODO actually generate glue functions! } } } @@ -313,8 +312,8 @@ fn add_tag_union( types: &Types, impls: &mut Impls, ) { - // We should never be attempting to bindgen empty tag unions; RocType should not - // have let this happen. + // We should never be attempting to generate glue for empty tag unions; + // RocType should not have let this happen. debug_assert_ne!(tags.len(), 0); let tag_names = tags.iter().map(|(name, _)| name).cloned().collect(); @@ -472,7 +471,7 @@ pub struct {name} {{ ); } else { todo!( - "Support {} tags in a recursive tag union on target_info {:?}. (This is too many tags for pointer tagging to work, so we need to bindgen something different.)", + "Support {} tags in a recursive tag union on target_info {:?}. (This is too many tags for pointer tagging to work, so we need to generate different glue.)", tags.len(), target_info ); diff --git a/crates/bindgen/src/structs.rs b/crates/glue/src/structs.rs similarity index 100% rename from crates/bindgen/src/structs.rs rename to crates/glue/src/structs.rs diff --git a/crates/bindgen/src/types.rs b/crates/glue/src/types.rs similarity index 99% rename from crates/bindgen/src/types.rs rename to crates/glue/src/types.rs index 1184b0e49f..9530f33f5d 100644 --- a/crates/bindgen/src/types.rs +++ b/crates/glue/src/types.rs @@ -1111,11 +1111,11 @@ fn add_tag_union<'a>( | Layout::Boxed(_) | Layout::LambdaSet(_) | Layout::RecursivePointer => { - // These must be single-tag unions. Bindgen ordinary nonrecursive + // These must be single-tag unions. Generate ordinary nonrecursive // tag unions for them, and let Rust do the unwrapping. // // This should be a very rare use case, and it's not worth overcomplicating - // the rest of bindgen to make it do something different. + // the rest of glue to make it do something different. RocType::TagUnion(RocTagUnion::NonRecursive { name: name.clone(), tags, diff --git a/crates/bindgen/templates/header.rs b/crates/glue/templates/header.rs similarity index 88% rename from crates/bindgen/templates/header.rs rename to crates/glue/templates/header.rs index 66613dfa09..b4935b9097 100644 --- a/crates/bindgen/templates/header.rs +++ b/crates/glue/templates/header.rs @@ -1,4 +1,4 @@ -// ⚠️ GENERATED CODE ⚠️ - this entire file was generated by the `roc-bindgen` CLI +// ⚠️ GENERATED CODE ⚠️ - this entire file was generated by the `roc glue` CLI command #![allow(dead_code)] #![allow(unused_mut)] diff --git a/crates/bindgen/tests/fixture-templates/rust/Cargo.lock b/crates/glue/tests/fixture-templates/rust/Cargo.lock similarity index 100% rename from crates/bindgen/tests/fixture-templates/rust/Cargo.lock rename to crates/glue/tests/fixture-templates/rust/Cargo.lock diff --git a/crates/bindgen/tests/fixture-templates/rust/Cargo.toml b/crates/glue/tests/fixture-templates/rust/Cargo.toml similarity index 100% rename from crates/bindgen/tests/fixture-templates/rust/Cargo.toml rename to crates/glue/tests/fixture-templates/rust/Cargo.toml diff --git a/crates/bindgen/tests/fixture-templates/rust/build.rs b/crates/glue/tests/fixture-templates/rust/build.rs similarity index 100% rename from crates/bindgen/tests/fixture-templates/rust/build.rs rename to crates/glue/tests/fixture-templates/rust/build.rs diff --git a/crates/bindgen/tests/fixture-templates/rust/host.c b/crates/glue/tests/fixture-templates/rust/host.c similarity index 100% rename from crates/bindgen/tests/fixture-templates/rust/host.c rename to crates/glue/tests/fixture-templates/rust/host.c diff --git a/crates/bindgen/tests/fixture-templates/rust/src/main.rs b/crates/glue/tests/fixture-templates/rust/src/main.rs similarity index 100% rename from crates/bindgen/tests/fixture-templates/rust/src/main.rs rename to crates/glue/tests/fixture-templates/rust/src/main.rs diff --git a/crates/bindgen/tests/fixtures/.gitignore b/crates/glue/tests/fixtures/.gitignore similarity index 89% rename from crates/bindgen/tests/fixtures/.gitignore rename to crates/glue/tests/fixtures/.gitignore index cc22f3ac1f..a71685876a 100644 --- a/crates/bindgen/tests/fixtures/.gitignore +++ b/crates/glue/tests/fixtures/.gitignore @@ -2,7 +2,7 @@ Cargo.lock Cargo.toml build.rs host.c -bindings.rs +test_glue.rs roc_externs.rs main.rs app diff --git a/crates/bindgen/tests/fixtures/advanced-recursive-union/app.roc b/crates/glue/tests/fixtures/advanced-recursive-union/app.roc similarity index 100% rename from crates/bindgen/tests/fixtures/advanced-recursive-union/app.roc rename to crates/glue/tests/fixtures/advanced-recursive-union/app.roc diff --git a/crates/bindgen/tests/fixtures/advanced-recursive-union/platform.roc b/crates/glue/tests/fixtures/advanced-recursive-union/platform.roc similarity index 100% rename from crates/bindgen/tests/fixtures/advanced-recursive-union/platform.roc rename to crates/glue/tests/fixtures/advanced-recursive-union/platform.roc diff --git a/crates/bindgen/tests/fixtures/advanced-recursive-union/src/lib.rs b/crates/glue/tests/fixtures/advanced-recursive-union/src/lib.rs similarity index 98% rename from crates/bindgen/tests/fixtures/advanced-recursive-union/src/lib.rs rename to crates/glue/tests/fixtures/advanced-recursive-union/src/lib.rs index 7df74a4368..8199720954 100644 --- a/crates/bindgen/tests/fixtures/advanced-recursive-union/src/lib.rs +++ b/crates/glue/tests/fixtures/advanced-recursive-union/src/lib.rs @@ -1,7 +1,7 @@ -mod bindings; +mod test_glue; -use bindings::Rbt; use indoc::indoc; +use test_glue::Rbt; extern "C" { #[link_name = "roc__mainForHost_1_exposed_generic"] diff --git a/crates/bindgen/tests/fixtures/basic-record/app.roc b/crates/glue/tests/fixtures/basic-record/app.roc similarity index 100% rename from crates/bindgen/tests/fixtures/basic-record/app.roc rename to crates/glue/tests/fixtures/basic-record/app.roc diff --git a/crates/bindgen/tests/fixtures/basic-record/platform.roc b/crates/glue/tests/fixtures/basic-record/platform.roc similarity index 100% rename from crates/bindgen/tests/fixtures/basic-record/platform.roc rename to crates/glue/tests/fixtures/basic-record/platform.roc diff --git a/crates/bindgen/tests/fixtures/basic-record/src/lib.rs b/crates/glue/tests/fixtures/basic-record/src/lib.rs similarity index 93% rename from crates/bindgen/tests/fixtures/basic-record/src/lib.rs rename to crates/glue/tests/fixtures/basic-record/src/lib.rs index 15e3ecd7e5..d467649ad7 100644 --- a/crates/bindgen/tests/fixtures/basic-record/src/lib.rs +++ b/crates/glue/tests/fixtures/basic-record/src/lib.rs @@ -1,8 +1,8 @@ -mod bindings; +mod test_glue; extern "C" { #[link_name = "roc__mainForHost_1_exposed_generic"] - fn roc_main(_: *mut bindings::MyRcd); + fn roc_main(_: *mut test_glue::MyRcd); } #[no_mangle] @@ -11,7 +11,7 @@ pub extern "C" fn rust_main() -> i32 { use std::collections::hash_set::HashSet; let record = unsafe { - let mut ret: core::mem::MaybeUninit = core::mem::MaybeUninit::uninit(); + let mut ret: core::mem::MaybeUninit = core::mem::MaybeUninit::uninit(); roc_main(ret.as_mut_ptr()); diff --git a/crates/bindgen/tests/fixtures/basic-recursive-union/app.roc b/crates/glue/tests/fixtures/basic-recursive-union/app.roc similarity index 100% rename from crates/bindgen/tests/fixtures/basic-recursive-union/app.roc rename to crates/glue/tests/fixtures/basic-recursive-union/app.roc diff --git a/crates/bindgen/tests/fixtures/basic-recursive-union/platform.roc b/crates/glue/tests/fixtures/basic-recursive-union/platform.roc similarity index 100% rename from crates/bindgen/tests/fixtures/basic-recursive-union/platform.roc rename to crates/glue/tests/fixtures/basic-recursive-union/platform.roc diff --git a/crates/bindgen/tests/fixtures/basic-recursive-union/src/lib.rs b/crates/glue/tests/fixtures/basic-recursive-union/src/lib.rs similarity index 98% rename from crates/bindgen/tests/fixtures/basic-recursive-union/src/lib.rs rename to crates/glue/tests/fixtures/basic-recursive-union/src/lib.rs index 1cc2d76e9d..8a82758288 100644 --- a/crates/bindgen/tests/fixtures/basic-recursive-union/src/lib.rs +++ b/crates/glue/tests/fixtures/basic-recursive-union/src/lib.rs @@ -1,7 +1,7 @@ -mod bindings; +mod test_glue; -use bindings::Expr; use indoc::indoc; +use test_glue::Expr; extern "C" { #[link_name = "roc__mainForHost_1_exposed_generic"] diff --git a/crates/bindgen/tests/fixtures/enumeration/app.roc b/crates/glue/tests/fixtures/enumeration/app.roc similarity index 100% rename from crates/bindgen/tests/fixtures/enumeration/app.roc rename to crates/glue/tests/fixtures/enumeration/app.roc diff --git a/crates/bindgen/tests/fixtures/enumeration/platform.roc b/crates/glue/tests/fixtures/enumeration/platform.roc similarity index 100% rename from crates/bindgen/tests/fixtures/enumeration/platform.roc rename to crates/glue/tests/fixtures/enumeration/platform.roc diff --git a/crates/bindgen/tests/fixtures/enumeration/src/lib.rs b/crates/glue/tests/fixtures/enumeration/src/lib.rs similarity index 90% rename from crates/bindgen/tests/fixtures/enumeration/src/lib.rs rename to crates/glue/tests/fixtures/enumeration/src/lib.rs index b63cee5ce8..9bf76923e2 100644 --- a/crates/bindgen/tests/fixtures/enumeration/src/lib.rs +++ b/crates/glue/tests/fixtures/enumeration/src/lib.rs @@ -1,8 +1,8 @@ -mod bindings; +mod test_glue; extern "C" { #[link_name = "roc__mainForHost_1_exposed_generic"] - fn roc_main(_: *mut bindings::MyEnum); + fn roc_main(_: *mut test_glue::MyEnum); } #[no_mangle] @@ -11,7 +11,7 @@ pub extern "C" fn rust_main() -> i32 { use std::collections::hash_set::HashSet; let tag_union = unsafe { - let mut ret: core::mem::MaybeUninit = core::mem::MaybeUninit::uninit(); + let mut ret: core::mem::MaybeUninit = core::mem::MaybeUninit::uninit(); roc_main(ret.as_mut_ptr()); @@ -39,8 +39,8 @@ pub extern "C" fn rust_main() -> i32 { println!( "tag_union was: {:?}, Bar is: {:?}, Baz is: {:?}", tag_union, - bindings::MyEnum::Bar, - bindings::MyEnum::Baz, + test_glue::MyEnum::Bar, + test_glue::MyEnum::Baz, ); // Debug // Exit code diff --git a/crates/bindgen/tests/fixtures/list-recursive-union/app.roc b/crates/glue/tests/fixtures/list-recursive-union/app.roc similarity index 100% rename from crates/bindgen/tests/fixtures/list-recursive-union/app.roc rename to crates/glue/tests/fixtures/list-recursive-union/app.roc diff --git a/crates/bindgen/tests/fixtures/list-recursive-union/platform.roc b/crates/glue/tests/fixtures/list-recursive-union/platform.roc similarity index 100% rename from crates/bindgen/tests/fixtures/list-recursive-union/platform.roc rename to crates/glue/tests/fixtures/list-recursive-union/platform.roc diff --git a/crates/bindgen/tests/fixtures/list-recursive-union/src/lib.rs b/crates/glue/tests/fixtures/list-recursive-union/src/lib.rs similarity index 98% rename from crates/bindgen/tests/fixtures/list-recursive-union/src/lib.rs rename to crates/glue/tests/fixtures/list-recursive-union/src/lib.rs index 7df74a4368..8199720954 100644 --- a/crates/bindgen/tests/fixtures/list-recursive-union/src/lib.rs +++ b/crates/glue/tests/fixtures/list-recursive-union/src/lib.rs @@ -1,7 +1,7 @@ -mod bindings; +mod test_glue; -use bindings::Rbt; use indoc::indoc; +use test_glue::Rbt; extern "C" { #[link_name = "roc__mainForHost_1_exposed_generic"] diff --git a/crates/bindgen/tests/fixtures/nested-record/app.roc b/crates/glue/tests/fixtures/nested-record/app.roc similarity index 100% rename from crates/bindgen/tests/fixtures/nested-record/app.roc rename to crates/glue/tests/fixtures/nested-record/app.roc diff --git a/crates/bindgen/tests/fixtures/nested-record/platform.roc b/crates/glue/tests/fixtures/nested-record/platform.roc similarity index 100% rename from crates/bindgen/tests/fixtures/nested-record/platform.roc rename to crates/glue/tests/fixtures/nested-record/platform.roc diff --git a/crates/bindgen/tests/fixtures/nested-record/src/lib.rs b/crates/glue/tests/fixtures/nested-record/src/lib.rs similarity index 93% rename from crates/bindgen/tests/fixtures/nested-record/src/lib.rs rename to crates/glue/tests/fixtures/nested-record/src/lib.rs index a660d079a9..52b9445876 100644 --- a/crates/bindgen/tests/fixtures/nested-record/src/lib.rs +++ b/crates/glue/tests/fixtures/nested-record/src/lib.rs @@ -1,8 +1,8 @@ -mod bindings; +mod test_glue; extern "C" { #[link_name = "roc__mainForHost_1_exposed_generic"] - fn roc_main(_: *mut bindings::Outer); + fn roc_main(_: *mut test_glue::Outer); } #[no_mangle] @@ -10,7 +10,7 @@ pub extern "C" fn rust_main() -> i32 { use std::cmp::Ordering; let outer = unsafe { - let mut ret: core::mem::MaybeUninit = core::mem::MaybeUninit::uninit(); + let mut ret: core::mem::MaybeUninit = core::mem::MaybeUninit::uninit(); roc_main(ret.as_mut_ptr()); diff --git a/crates/bindgen/tests/fixtures/nullable-unwrapped/app.roc b/crates/glue/tests/fixtures/nullable-unwrapped/app.roc similarity index 100% rename from crates/bindgen/tests/fixtures/nullable-unwrapped/app.roc rename to crates/glue/tests/fixtures/nullable-unwrapped/app.roc diff --git a/crates/bindgen/tests/fixtures/nullable-unwrapped/platform.roc b/crates/glue/tests/fixtures/nullable-unwrapped/platform.roc similarity index 100% rename from crates/bindgen/tests/fixtures/nullable-unwrapped/platform.roc rename to crates/glue/tests/fixtures/nullable-unwrapped/platform.roc diff --git a/crates/bindgen/tests/fixtures/nullable-unwrapped/src/lib.rs b/crates/glue/tests/fixtures/nullable-unwrapped/src/lib.rs similarity index 98% rename from crates/bindgen/tests/fixtures/nullable-unwrapped/src/lib.rs rename to crates/glue/tests/fixtures/nullable-unwrapped/src/lib.rs index 8b025e07dd..58a5516bde 100644 --- a/crates/bindgen/tests/fixtures/nullable-unwrapped/src/lib.rs +++ b/crates/glue/tests/fixtures/nullable-unwrapped/src/lib.rs @@ -1,7 +1,7 @@ -mod bindings; +mod test_glue; -use bindings::StrConsList; use indoc::indoc; +use test_glue::StrConsList; extern "C" { #[link_name = "roc__mainForHost_1_exposed_generic"] diff --git a/crates/bindgen/tests/fixtures/union-with-padding/app.roc b/crates/glue/tests/fixtures/union-with-padding/app.roc similarity index 100% rename from crates/bindgen/tests/fixtures/union-with-padding/app.roc rename to crates/glue/tests/fixtures/union-with-padding/app.roc diff --git a/crates/bindgen/tests/fixtures/union-with-padding/platform.roc b/crates/glue/tests/fixtures/union-with-padding/platform.roc similarity index 100% rename from crates/bindgen/tests/fixtures/union-with-padding/platform.roc rename to crates/glue/tests/fixtures/union-with-padding/platform.roc diff --git a/crates/bindgen/tests/fixtures/union-with-padding/src/lib.rs b/crates/glue/tests/fixtures/union-with-padding/src/lib.rs similarity index 98% rename from crates/bindgen/tests/fixtures/union-with-padding/src/lib.rs rename to crates/glue/tests/fixtures/union-with-padding/src/lib.rs index 408f574a4c..f8b9a05e20 100644 --- a/crates/bindgen/tests/fixtures/union-with-padding/src/lib.rs +++ b/crates/glue/tests/fixtures/union-with-padding/src/lib.rs @@ -1,6 +1,6 @@ -mod bindings; +mod test_glue; -use bindings::NonRecursive; +use test_glue::NonRecursive; extern "C" { #[link_name = "roc__mainForHost_1_exposed_generic"] diff --git a/crates/bindgen/tests/fixtures/union-without-padding/app.roc b/crates/glue/tests/fixtures/union-without-padding/app.roc similarity index 100% rename from crates/bindgen/tests/fixtures/union-without-padding/app.roc rename to crates/glue/tests/fixtures/union-without-padding/app.roc diff --git a/crates/bindgen/tests/fixtures/union-without-padding/platform.roc b/crates/glue/tests/fixtures/union-without-padding/platform.roc similarity index 84% rename from crates/bindgen/tests/fixtures/union-without-padding/platform.roc rename to crates/glue/tests/fixtures/union-without-padding/platform.roc index 881b30b330..68a1c236fc 100644 --- a/crates/bindgen/tests/fixtures/union-without-padding/platform.roc +++ b/crates/glue/tests/fixtures/union-without-padding/platform.roc @@ -8,7 +8,7 @@ platform "test-platform" # This case is important to test because there's no padding # after the largest variant, so the compiler adds an extra u8 # (rounded up to alignment, so an an extra 8 bytes) in which -# to store the discriminant. We have to bindgen accordingly! +# to store the discriminant. We have to generate glue code accordingly! NonRecursive : [Foo Str, Bar I64, Blah I32, Baz] mainForHost : NonRecursive diff --git a/crates/bindgen/tests/fixtures/union-without-padding/src/lib.rs b/crates/glue/tests/fixtures/union-without-padding/src/lib.rs similarity index 87% rename from crates/bindgen/tests/fixtures/union-without-padding/src/lib.rs rename to crates/glue/tests/fixtures/union-without-padding/src/lib.rs index ba4df484bf..c65c5c76e3 100644 --- a/crates/bindgen/tests/fixtures/union-without-padding/src/lib.rs +++ b/crates/glue/tests/fixtures/union-without-padding/src/lib.rs @@ -1,8 +1,8 @@ -mod bindings; +mod test_glue; extern "C" { #[link_name = "roc__mainForHost_1_exposed_generic"] - fn roc_main(_: *mut bindings::NonRecursive); + fn roc_main(_: *mut test_glue::NonRecursive); } #[no_mangle] @@ -11,7 +11,7 @@ pub extern "C" fn rust_main() -> i32 { use std::collections::hash_set::HashSet; let tag_union = unsafe { - let mut ret: core::mem::MaybeUninit = + let mut ret: core::mem::MaybeUninit = core::mem::MaybeUninit::uninit(); roc_main(ret.as_mut_ptr()); @@ -30,10 +30,10 @@ pub extern "C" fn rust_main() -> i32 { println!( "tag_union was: {:?}\n`Foo \"small str\"` is: {:?}\n`Bar 123` is: {:?}\n`Baz` is: {:?}\n`Blah 456` is: {:?}", tag_union, - bindings::NonRecursive::Foo("small str".into()), - bindings::NonRecursive::Bar(123), - bindings::NonRecursive::Baz, - bindings::NonRecursive::Blah(456), + test_glue::NonRecursive::Foo("small str".into()), + test_glue::NonRecursive::Bar(123), + test_glue::NonRecursive::Baz, + test_glue::NonRecursive::Blah(456), ); // Debug let mut set = HashSet::new(); diff --git a/crates/bindgen/tests/gen_rs.rs b/crates/glue/tests/gen_rs.rs similarity index 100% rename from crates/bindgen/tests/gen_rs.rs rename to crates/glue/tests/gen_rs.rs diff --git a/crates/bindgen/tests/helpers/mod.rs b/crates/glue/tests/helpers/mod.rs similarity index 93% rename from crates/bindgen/tests/helpers/mod.rs rename to crates/glue/tests/helpers/mod.rs index b58612531e..127940603e 100644 --- a/crates/bindgen/tests/helpers/mod.rs +++ b/crates/glue/tests/helpers/mod.rs @@ -1,5 +1,5 @@ -use roc_bindgen::bindgen_rs; -use roc_bindgen::load::load_types; +use roc_glue::load::load_types; +use roc_glue::rust_glue; use roc_load::Threading; use std::env; use std::fs::File; @@ -40,7 +40,7 @@ pub fn generate_bindings(decl_src: &str) -> String { result.expect("had problems loading") }; - bindgen_rs::emit(&pairs) + rust_glue::emit(&pairs) } #[allow(dead_code)] @@ -49,7 +49,7 @@ pub fn fixtures_dir(dir_name: &str) -> PathBuf { // Descend into cli/tests/fixtures/{dir_name} path.push("crates"); - path.push("bindgen"); + path.push("glue"); path.push("tests"); path.push("fixtures"); path.push(dir_name); diff --git a/crates/bindgen/tests/test_bindgen_cli.rs b/crates/glue/tests/test_glue_cli.rs similarity index 74% rename from crates/bindgen/tests/test_bindgen_cli.rs rename to crates/glue/tests/test_glue_cli.rs index a9ce346e10..4d506621c2 100644 --- a/crates/bindgen/tests/test_bindgen_cli.rs +++ b/crates/glue/tests/test_glue_cli.rs @@ -10,41 +10,11 @@ extern crate roc_collections; mod helpers; #[cfg(test)] -mod bindgen_cli_run { - use crate::helpers::{fixtures_dir, root_dir}; - use cli_utils::helpers::{run_bindgen, run_roc, Out}; +mod glue_cli_run { + use crate::helpers::fixtures_dir; + use cli_utils::helpers::{run_glue, run_roc, Out}; use std::fs; use std::path::Path; - use std::process::Command; - - // All of these tests rely on `target/` for the `cli` crate being up-to-date, - // so do a `cargo build` on it first! - #[ctor::ctor] - fn init() { - let args = if cfg!(debug_assertions) { - vec!["build"] - } else { - vec!["build", "--release"] - }; - - println!( - "Running `cargo {}` on the `cli` crate before running the tests. This may take a bit!", - args.join(" ") - ); - - let output = Command::new("cargo") - .args(args) - .current_dir(root_dir().join("crates").join("cli")) - .output() - .unwrap_or_else(|err| { - panic!( - "Failed to `cargo build` roc CLI for bindgen CLI tests - error was: {:?}", - err - ) - }); - - assert!(output.status.success()); - } /// This macro does two things. /// @@ -68,7 +38,7 @@ mod bindgen_cli_run { fn $test_name() { let dir = fixtures_dir($fixture_dir); - generate_bindings_for(&dir, std::iter::empty()); + generate_glue_for(&dir, std::iter::empty()); let out = run_app(&dir.join("app.roc"), std::iter::empty()); assert!(out.status.success()); @@ -137,8 +107,6 @@ mod bindgen_cli_run { fn check_for_tests(all_fixtures: &mut roc_collections::VecSet) { use roc_collections::VecSet; - // todo!("Remove a bunch of duplication - don't have a ton of files in there."); - let fixtures = fixtures_dir(""); let entries = std::fs::read_dir(fixtures.as_path()).unwrap_or_else(|err| { panic!( @@ -156,7 +124,7 @@ mod bindgen_cli_run { if !all_fixtures.remove(&fixture_dir_name) { panic!( - "The bindgen fixture directory {} does not have any corresponding tests in cli_run. Please add one, so if it ever stops working, we'll know about it right away!", + "The glue fixture directory {} does not have any corresponding tests in test_glue_cli. Please add one, so if it ever stops working, we'll know about it right away!", entry.path().to_string_lossy() ); } @@ -166,12 +134,12 @@ mod bindgen_cli_run { assert_eq!(all_fixtures, &mut VecSet::default()); } - fn generate_bindings_for<'a, I: IntoIterator>( + fn generate_glue_for<'a, I: IntoIterator>( platform_dir: &'a Path, args: I, ) -> Out { let platform_module_path = platform_dir.join("platform.roc"); - let bindings_file = platform_dir.join("src").join("bindings.rs"); + let glue_file = platform_dir.join("src").join("test_glue.rs"); let fixture_templates_dir = platform_dir .parent() .unwrap() @@ -179,44 +147,49 @@ mod bindgen_cli_run { .unwrap() .join("fixture-templates"); + dbg!(&platform_module_path); + dbg!(&glue_file); + // Copy the rust template from the templates directory into the fixture dir. dircpy::CopyBuilder::new(fixture_templates_dir.join("rust"), platform_dir) .overwrite(true) // overwrite any files that were already present .run() .unwrap(); - // Delete the bindings file to make sure we're actually regenerating it! - if bindings_file.exists() { - fs::remove_file(&bindings_file) - .expect("Unable to remove bindings.rs in order to regenerate it in the test"); + // Delete the glue file to make sure we're actually regenerating it! + if glue_file.exists() { + fs::remove_file(&glue_file) + .expect("Unable to remove test_glue.rs in order to regenerate it in the test"); } - // Generate a fresh bindings.rs for this platform - let bindgen_out = run_bindgen( + // Generate a fresh test_glue.rs for this platform + let glue_out = run_glue( // converting these all to String avoids lifetime issues - args.into_iter().map(|arg| arg.to_string()).chain([ - platform_module_path.to_str().unwrap().to_string(), - bindings_file.to_str().unwrap().to_string(), - ]), + std::iter::once("glue".to_string()).chain( + args.into_iter().map(|arg| arg.to_string()).chain([ + platform_module_path.to_str().unwrap().to_string(), + glue_file.to_str().unwrap().to_string(), + ]), + ), ); // If there is any stderr, it should be reporting the runtime and that's it! - if !(bindgen_out.stderr.is_empty() - || bindgen_out.stderr.starts_with("runtime: ") && bindgen_out.stderr.ends_with("ms\n")) + if !(glue_out.stderr.is_empty() + || glue_out.stderr.starts_with("runtime: ") && glue_out.stderr.ends_with("ms\n")) { panic!( - "`roc-bindgen` command had unexpected stderr: {}", - bindgen_out.stderr + "`roc glue` command had unexpected stderr: {}", + glue_out.stderr ); } - assert!(bindgen_out.status.success(), "bad status {:?}", bindgen_out); + assert!(glue_out.status.success(), "bad status {:?}", glue_out); - bindgen_out + glue_out } fn run_app<'a, I: IntoIterator>(app_file: &'a Path, args: I) -> Out { - // Generate bindings.rs for this platform + // Generate test_glue.rs for this platform let compile_out = run_roc( // converting these all to String avoids lifetime issues args.into_iter() diff --git a/examples/interactive/cli-platform/src/glue.rs b/examples/interactive/cli-platform/src/glue.rs index c09aeca0e8..779b0bf874 100644 --- a/examples/interactive/cli-platform/src/glue.rs +++ b/examples/interactive/cli-platform/src/glue.rs @@ -1,4 +1,4 @@ -// ⚠️ GENERATED CODE ⚠️ - this entire file was generated by the `roc-bindgen` CLI +// ⚠️ GENERATED CODE ⚠️ - this entire file was generated by the `roc glue` CLI command #![allow(dead_code)] #![allow(unused_mut)]