mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 00:24:34 +00:00
Rename crates/bindgen to crates/glue
This commit is contained in:
parent
20275f480b
commit
98c6ab0e97
53 changed files with 37 additions and 34 deletions
40
crates/glue/src/bindgen_c.rs
Normal file
40
crates/glue/src/bindgen_c.rs
Normal file
|
@ -0,0 +1,40 @@
|
|||
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(())
|
||||
// }
|
2014
crates/glue/src/bindgen_rs.rs
Normal file
2014
crates/glue/src/bindgen_rs.rs
Normal file
File diff suppressed because it is too large
Load diff
18
crates/glue/src/bindgen_zig.rs
Normal file
18
crates/glue/src/bindgen_zig.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
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(())
|
||||
}
|
36
crates/glue/src/enums.rs
Normal file
36
crates/glue/src/enums.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
use roc_collections::MutMap;
|
||||
use roc_types::subs::Variable;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
struct EnumId(u64);
|
||||
|
||||
impl EnumId {
|
||||
pub fn to_name(self) -> String {
|
||||
format!("U{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Whenever we register a new tag union type,
|
||||
/// give it a unique and short name (e.g. U1, U2, U3...)
|
||||
/// and then from then on, whenever we ask for that
|
||||
/// same record type, return the same name.
|
||||
#[derive(Default)]
|
||||
pub struct Enums {
|
||||
by_variable: MutMap<Variable, EnumId>,
|
||||
next_id: EnumId,
|
||||
}
|
||||
|
||||
impl Enums {
|
||||
pub fn get_name(&mut self, var: Variable) -> String {
|
||||
match self.by_variable.get(&var) {
|
||||
Some(struct_id) => struct_id.to_name(),
|
||||
None => self.next_id().to_name(),
|
||||
}
|
||||
}
|
||||
|
||||
fn next_id(&mut self) -> EnumId {
|
||||
self.next_id.0 += 1;
|
||||
|
||||
self.next_id
|
||||
}
|
||||
}
|
7
crates/glue/src/lib.rs
Normal file
7
crates/glue/src/lib.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
pub mod bindgen_c;
|
||||
pub mod bindgen_rs;
|
||||
pub mod bindgen_zig;
|
||||
pub mod enums;
|
||||
pub mod load;
|
||||
pub mod structs;
|
||||
pub mod types;
|
82
crates/glue/src/load.rs
Normal file
82
crates/glue/src/load.rs
Normal file
|
@ -0,0 +1,82 @@
|
|||
use crate::types::{Env, Types};
|
||||
use bumpalo::Bump;
|
||||
use roc_load::{LoadedModule, Threading};
|
||||
use roc_reporting::report::RenderTarget;
|
||||
use roc_target::{Architecture, TargetInfo};
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
use strum::IntoEnumIterator;
|
||||
use target_lexicon::Triple;
|
||||
|
||||
pub fn load_types(
|
||||
full_file_path: PathBuf,
|
||||
threading: Threading,
|
||||
) -> Result<Vec<(Types, TargetInfo)>, io::Error> {
|
||||
let target_info = (&Triple::host()).into();
|
||||
|
||||
let arena = &Bump::new();
|
||||
let subs_by_module = Default::default();
|
||||
let LoadedModule {
|
||||
module_id: home,
|
||||
mut can_problems,
|
||||
mut type_problems,
|
||||
mut declarations_by_id,
|
||||
mut solved,
|
||||
mut interns,
|
||||
..
|
||||
} = roc_load::load_and_typecheck(
|
||||
arena,
|
||||
full_file_path,
|
||||
subs_by_module,
|
||||
target_info,
|
||||
RenderTarget::Generic,
|
||||
threading,
|
||||
)
|
||||
.expect("Problem loading platform module");
|
||||
|
||||
let decls = declarations_by_id.remove(&home).unwrap();
|
||||
let subs = solved.inner_mut();
|
||||
|
||||
let can_problems = can_problems.remove(&home).unwrap_or_default();
|
||||
let type_problems = type_problems.remove(&home).unwrap_or_default();
|
||||
|
||||
if !can_problems.is_empty() || !type_problems.is_empty() {
|
||||
todo!(
|
||||
"Gracefully report compilation problems during bindgen: {:?}, {:?}",
|
||||
can_problems,
|
||||
type_problems
|
||||
);
|
||||
}
|
||||
|
||||
let variables = (0..decls.len()).filter_map(|index| {
|
||||
use roc_can::expr::DeclarationTag::*;
|
||||
|
||||
match decls.declarations[index] {
|
||||
Value | Function(_) | Recursive(_) | TailRecursive(_) => Some(decls.variables[index]),
|
||||
Destructure(_) => {
|
||||
// figure out if we need to export non-identifier defs - when would that
|
||||
// happen?
|
||||
None
|
||||
}
|
||||
MutualRecursion { .. } => {
|
||||
// handled by future iterations
|
||||
None
|
||||
}
|
||||
Expectation => {
|
||||
// not publicly visible
|
||||
None
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let types_and_targets = Architecture::iter()
|
||||
.map(|arch| {
|
||||
let target_info = arch.into();
|
||||
let mut env = Env::new(arena, subs, &mut interns, target_info);
|
||||
|
||||
(env.vars_to_types(variables.clone()), target_info)
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(types_and_targets)
|
||||
}
|
113
crates/glue/src/main.rs
Normal file
113
crates/glue/src/main.rs
Normal file
|
@ -0,0 +1,113 @@
|
|||
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);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
36
crates/glue/src/structs.rs
Normal file
36
crates/glue/src/structs.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
use roc_collections::MutMap;
|
||||
use roc_types::subs::Variable;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
struct StructId(u64);
|
||||
|
||||
impl StructId {
|
||||
pub fn to_name(self) -> String {
|
||||
format!("R{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Whenever we register a new Roc record type,
|
||||
/// give it a unique and short name (e.g. R1, R2, R3...)
|
||||
/// and then from then on, whenever we ask for that
|
||||
/// same record type, return the same name.
|
||||
#[derive(Default)]
|
||||
pub struct Structs {
|
||||
by_variable: MutMap<Variable, StructId>,
|
||||
next_id: StructId,
|
||||
}
|
||||
|
||||
impl Structs {
|
||||
pub fn get_name(&mut self, var: Variable) -> String {
|
||||
match self.by_variable.get(&var) {
|
||||
Some(struct_id) => struct_id.to_name(),
|
||||
None => self.next_id().to_name(),
|
||||
}
|
||||
}
|
||||
|
||||
fn next_id(&mut self) -> StructId {
|
||||
self.next_id.0 += 1;
|
||||
|
||||
self.next_id
|
||||
}
|
||||
}
|
1166
crates/glue/src/types.rs
Normal file
1166
crates/glue/src/types.rs
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue