use verilization_compiler::{lang, model, parser, load_all_models, VError, MemoryOutputHandler};
use lang::{GeneratorError, Language, LanguageRegistry, LanguageHandler};
use std::ffi::{c_void, OsString};
use std::collections::HashMap;
#[repr(C)]
pub struct APIString {
length: usize,
data: [u8; 0],
}
impl APIString {
unsafe fn allocate(s: &str) -> *mut APIString {
let ptr = verilization_mem_alloc(std::mem::size_of::<APIString>() + s.len());
let api_str = ptr as *mut APIString;
(*api_str).length = s.len();
std::ptr::copy_nonoverlapping(s.as_ptr(), (*api_str).data.as_mut_ptr(), s.len());
api_str
}
fn to_str<'a>(&'a self) -> Option<&'a str> {
let data = &self.data as *const u8;
unsafe { std::str::from_utf8(std::slice::from_raw_parts(data, self.length)).ok() }
}
}
#[repr(C)]
pub struct APIResult<T> {
is_error: usize,
data: APIResultPtr<T>,
}
#[repr(C)]
pub union APIResultPtr<T> {
error: *mut APIString,
value: *mut T,
}
#[repr(C)]
pub struct LanguageOption {
name: *mut APIString,
value: *mut APIString,
}
#[repr(C)]
pub struct OutputFileEntry {
name: *mut APIString,
length: usize,
content: *mut u8,
}
#[repr(C)]
pub struct OutputFileMap {
length: usize,
entries: [OutputFileEntry; 0],
}
impl OutputFileMap {
unsafe fn allocate(map: &HashMap<String, Vec<u8>>) -> *mut OutputFileMap {
let ptr = verilization_mem_alloc(std::mem::size_of::<OutputFileMap>() + map.len() * std::mem::size_of::<OutputFileEntry>()) as *mut OutputFileMap;
(*ptr).length = map.len();
let entries = std::slice::from_raw_parts_mut((*ptr).entries.as_mut_ptr(), map.len());
for (index, (name, data)) in map.iter().enumerate() {
let entry: &mut OutputFileEntry = &mut entries[index];
entry.name = APIString::allocate(name);
entry.length = data.len();
let buffer = verilization_mem_alloc(data.len());
entry.content = buffer;
std::ptr::copy_nonoverlapping(data.as_ptr(), buffer, data.len());
}
ptr
}
}
#[no_mangle]
pub unsafe extern "C" fn verilization_mem_alloc(size: usize) -> *mut u8 {
std::alloc::alloc(std::alloc::Layout::from_size_align(size, std::mem::size_of::<*mut c_void>()).unwrap())
}
#[no_mangle]
pub unsafe extern "C" fn verilization_mem_free(size: usize, ptr: *mut u8) {
std::alloc::dealloc(ptr, std::alloc::Layout::from_size_align(size, std::mem::size_of::<*mut c_void>()).unwrap())
}
#[no_mangle]
pub unsafe extern "C" fn verilization_parse(nfiles: usize, files: *const *const APIString, result: *mut APIResult<model::Verilization>) {
let files = std::slice::from_raw_parts(files, nfiles);
*result = match verilization_parse_impl(files) {
Ok(model) => APIResult {
is_error: 0,
data: APIResultPtr {
value: Box::into_raw(Box::new(model)),
},
},
Err(err) => APIResult {
is_error: 1,
data: APIResultPtr {
error: APIString::allocate(&format!("{:?}", err)),
},
},
}
}
unsafe fn verilization_parse_impl(files: &[*const APIString]) -> Result<model::Verilization, VError> {
let models = files.iter().map(|content| {
let content = content.as_ref().expect("Pointer was null").to_str().expect("Invalid String");
let (_, model) = parser::parse_model(content)?;
let model = model()?;
Ok(model)
});
load_all_models(models)
}
#[no_mangle]
pub unsafe extern "C" fn verilization_destroy(verilization: *mut model::Verilization) {
Box::from_raw(verilization);
}
pub unsafe fn verilization_generate_impl<Registry: LanguageRegistry>(verilization: *const model::Verilization, language: *const APIString, noptions: usize, options: *const LanguageOption, result: *mut APIResult<OutputFileMap>, registry: &Registry) {
*result = match verilization_generate_impl_result(verilization, language, noptions, options, registry) {
Ok(map) => APIResult {
is_error: 0,
data: APIResultPtr {
value: map,
},
},
Err(err) => APIResult {
is_error: 1,
data: APIResultPtr {
error: APIString::allocate(&format!("{:?}", err)),
},
},
}
}
unsafe fn verilization_generate_impl_result<Registry: LanguageRegistry>(verilization: *const model::Verilization, language: *const APIString, noptions: usize, options: *const LanguageOption, registry: &Registry) -> Result<*mut OutputFileMap, GeneratorError> {
let verilization = verilization.as_ref().expect("Verilization pointer is null");
let language = language.as_ref().expect("Language string is null").to_str().expect("Language is invalid text");
let options = std::slice::from_raw_parts(options, noptions)
.iter()
.map(|option| {
let name = option.name.as_ref().expect("Option name is null").to_str().expect("Invalid option name text");
let value = option.value.as_ref().expect("Option value is null").to_str().expect("Invalid option value text");
(name, value)
})
.collect::<Vec<_>>();
let mut output = MemoryOutputHandler {
files: HashMap::new(),
};
match registry.handle_language(language, &mut VerilizationGenerateLang { verilization: verilization, options: options, output: &mut output, }) {
Some(result) => result?,
None =>Err(GeneratorError::UnknownLanguage(String::from(language)))?,
}
Ok(OutputFileMap::allocate(&output.files))
}
struct VerilizationGenerateLang<'a, Output> {
verilization: &'a model::Verilization,
options: Vec<(&'a str, &'a str)>,
output: &'a mut Output,
}
impl <'a, Output: for<'output> lang::OutputHandler<'output>> LanguageHandler for VerilizationGenerateLang<'a, Output> {
type Result = Result<(), GeneratorError>;
fn run<Lang: Language>(&mut self) -> Self::Result {
let mut lang_options = Lang::empty_options();
for (name, value) in &self.options {
Lang::add_option(&mut lang_options, name, OsString::from(value))?;
}
let lang_options = Lang::finalize_options(lang_options)?;
Lang::generate(self.verilization, lang_options, self.output)
}
}