Rename crates/bindgen to crates/glue

This commit is contained in:
Richard Feldman 2022-07-24 10:24:16 -04:00
parent 20275f480b
commit 98c6ab0e97
No known key found for this signature in database
GPG key ID: 7E4127D1E4241798
53 changed files with 37 additions and 34 deletions

View 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(())
// }

File diff suppressed because it is too large Load diff

View 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
View 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
View 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
View 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
View 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);
}
},
}
}

View 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

File diff suppressed because it is too large Load diff