use libc::c_char;
use ffi::prelude::{LLVMValueRef, LLVMModuleRef};
use ffi::analysis::LLVMVerifierFailureAction;
use ffi::{analysis, core, LLVMModule};
use ffi::bit_writer as writer;
use ffi::bit_reader as reader;
use cbox::{CBox, CSemiBox};
use std::ffi::CString;
use std::iter::{Iterator, IntoIterator};
use std::io::{Error, ErrorKind};
use std::io::Result as IoResult;
use std::{env, fmt, mem};
use std::marker::PhantomData;
use std::path::Path;
use std::process::Command;
use buffer::MemoryBuffer;
use context::{Context, GetContext};
use value::Function;
use ty::Type;
use util;
pub struct Module;
native_ref!(&Module = LLVMModuleRef);
impl Module {
pub fn new<'a>(name: &str, context: &'a Context) -> CSemiBox<'a, Module> {
let c_name = CString::new(name).unwrap();
unsafe { CSemiBox::new(core::LLVMModuleCreateWithNameInContext(c_name.as_ptr(), context.into())) }
}
pub fn parse_bitcode<'a>(context: &'a Context, path: &str) -> Result<CSemiBox<'a, Module>, CBox<str>> {
unsafe {
let mut out = mem::uninitialized();
let mut err = mem::uninitialized();
let buf = try!(MemoryBuffer::new_from_file(path));
if reader::LLVMParseBitcodeInContext(context.into(), buf.as_ptr(), &mut out, &mut err) == 1 {
Err(CBox::new(err))
} else {
Ok(CSemiBox::new(out))
}
}
}
pub fn write_bitcode(&self, path: &str) -> IoResult<()> {
util::with_cstr(path, |cpath| unsafe {
if writer::LLVMWriteBitcodeToFile(self.into(), cpath) != 0 {
Err(Error::new(ErrorKind::Other, &format!("could not write to {}", path) as &str))
} else {
Ok(())
}
})
}
pub fn add_function<'a>(&'a self, name: &str, sig: &'a Type) -> &'a mut Function {
let c_name = CString::new(name).unwrap();
unsafe { core::LLVMAddFunction(self.into(), c_name.as_ptr(), sig.into()) }.into()
}
pub fn get_function<'a>(&'a self, name: &str) -> Option<&'a Function> {
let c_name = CString::new(name).unwrap();
unsafe {
let ty = core::LLVMGetNamedFunction(self.into(), c_name.as_ptr());
util::ptr_to_null(ty)
}
}
pub fn get_type<'a>(&'a self, name: &str) -> Option<&'a Type> {
let c_name = CString::new(name).unwrap();
unsafe {
let ty = core::LLVMGetTypeByName(self.into(), c_name.as_ptr());
util::ptr_to_null(ty)
}
}
pub fn clone<'a>(&'a self) -> CSemiBox<'a, Module> {
CSemiBox::new(unsafe { core::LLVMCloneModule(self.into()) })
}
pub fn get_target(&self) -> &str {
unsafe {
let target = core::LLVMGetTarget(self.into());
util::to_str(target as *mut c_char)
}
}
pub fn set_target(&self, target: &str) {
let c_target = CString::new(target).unwrap();
unsafe { core::LLVMSetTarget(self.into(), c_target.as_ptr()) }
}
pub fn verify(&self) -> Result<(), CBox<str>> {
unsafe {
let mut error = mem::uninitialized();
let action = LLVMVerifierFailureAction::LLVMReturnStatusAction;
if analysis::LLVMVerifyModule(self.into(), action, &mut error) == 1 {
Err(CBox::new(error))
} else {
Ok(())
}
}
}
pub fn compile(&self, path: &Path, opt_level: usize) -> IoResult<()> {
let dir = env::temp_dir();
let path = path.to_str().unwrap();
let mod_path = dir.join("module.bc");
let mod_path = mod_path.to_str().unwrap();
try!(self.write_bitcode(mod_path));
Command::new("llc")
.arg(&format!("-O={}", opt_level))
.arg("-filetype=obj")
.arg("-o").arg(path)
.arg(mod_path)
.spawn()
.map(|_| ())
}
}
impl<'a> IntoIterator for &'a Module {
type Item = &'a Function;
type IntoIter = Functions<'a>;
fn into_iter(self) -> Functions<'a> {
Functions {
value: unsafe { core::LLVMGetFirstFunction(self.into()) },
marker: PhantomData
}
}
}
get_context!(Module, LLVMGetModuleContext);
to_str!(Module, LLVMPrintModuleToString);
dispose!(Module, LLVMModule, core::LLVMDisposeModule);
#[derive(Copy, Clone)]
pub struct Functions<'a> {
value: LLVMValueRef,
marker: PhantomData<&'a ()>
}
impl<'a> Iterator for Functions<'a> {
type Item = &'a Function;
fn next(&mut self) -> Option<&'a Function> {
if self.value.is_null() {
None
} else {
let c_next = unsafe { core::LLVMGetNextFunction(self.value) };
self.value = c_next;
Some(self.value.into())
}
}
}