use std::marker::PhantomData;
use std::ffi::CString;
use std::fmt;
use std::ptr;
use std::mem;
use std::os::raw::c_int;
use asm::ExtendedAsm;
use block;
use context::{Case, Context};
use object::{self, ToObject, Object};
use function::{self, Function};
use location::{self, Location};
use rvalue::{self, ToRValue};
use lvalue::{self, ToLValue};
use crate::with_lib;
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum BinaryOp {
Plus,
Minus,
Mult,
Divide,
Modulo,
BitwiseAnd,
BitwiseXor,
BitwiseOr,
LogicalAnd,
LogicalOr,
LShift,
RShift
}
#[repr(C)]
#[derive(Clone, Copy)]
pub enum UnaryOp {
Minus,
BitwiseNegate,
LogicalNegate,
Abs
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub enum ComparisonOp {
Equals,
NotEquals,
LessThan,
LessThanEquals,
GreaterThan,
GreaterThanEquals
}
#[derive(Copy, Clone, Eq, Hash, PartialEq)]
pub struct Block<'ctx> {
marker: PhantomData<&'ctx Context<'ctx>>,
ptr: *mut gccjit_sys::gcc_jit_block,
}
impl<'ctx> ToObject<'ctx> for Block<'ctx> {
fn to_object(&self) -> Object<'ctx> {
with_lib(|lib| {
unsafe {
let ptr = lib.gcc_jit_block_as_object(self.ptr);
object::from_ptr(ptr)
}
})
}
}
impl<'ctx> fmt::Debug for Block<'ctx> {
fn fmt<'a>(&self, fmt: &mut fmt::Formatter<'a>) -> Result<(), fmt::Error> {
let obj = self.to_object();
obj.fmt(fmt)
}
}
impl<'ctx> Block<'ctx> {
pub fn get_function(&self) -> Function<'ctx> {
with_lib(|lib| {
unsafe {
let ptr = lib.gcc_jit_block_get_function(self.ptr);
function::from_ptr(ptr)
}
})
}
pub fn add_eval<T: ToRValue<'ctx>>(&self,
loc: Option<Location<'ctx>>,
value: T) {
let rvalue = value.to_rvalue();
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
with_lib(|lib| {
unsafe {
lib.gcc_jit_block_add_eval(self.ptr, loc_ptr, rvalue::get_ptr(&rvalue));
}
});
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.to_object().get_context().get_last_error() {
panic!("{}", error);
}
}
#[cfg(feature="master")]
pub fn add_try_catch(&self, loc: Option<Location<'ctx>>, try_block: Block<'ctx>, catch_block: Block<'ctx>) {
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
with_lib(|lib| {
unsafe {
lib.gcc_jit_block_add_try_catch(self.ptr, loc_ptr, try_block.ptr, catch_block.ptr);
}
});
}
#[cfg(feature="master")]
pub fn add_try_finally(&self, loc: Option<Location<'ctx>>, try_block: Block<'ctx>, finally_block: Block<'ctx>) {
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
with_lib(|lib| {
unsafe {
lib.gcc_jit_block_add_try_finally(self.ptr, loc_ptr, try_block.ptr, finally_block.ptr);
}
});
}
pub fn add_assignment<L: ToLValue<'ctx>, R: ToRValue<'ctx>>(&self,
loc: Option<Location<'ctx>>,
assign_target: L,
value: R) {
let lvalue = assign_target.to_lvalue();
let rvalue = value.to_rvalue();
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
with_lib(|lib| {
unsafe {
lib.gcc_jit_block_add_assignment(self.ptr, loc_ptr, lvalue::get_ptr(&lvalue),
rvalue::get_ptr(&rvalue));
}
});
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.to_object().get_context().get_last_error() {
panic!("{}", error);
}
}
pub fn add_assignment_op<L: ToLValue<'ctx>, R: ToRValue<'ctx>>(&self,
loc: Option<Location<'ctx>>,
assign_target: L,
op: BinaryOp,
value: R) {
let lvalue = assign_target.to_lvalue();
let rvalue = value.to_rvalue();
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
with_lib(|lib| {
unsafe {
lib.gcc_jit_block_add_assignment_op(self.ptr, loc_ptr, lvalue::get_ptr(&lvalue),
mem::transmute::<BinaryOp, gccjit_sys::gcc_jit_binary_op>(op), rvalue::get_ptr(&rvalue));
}
});
}
pub fn add_comment<S: AsRef<str>>(&self,
loc: Option<Location<'ctx>>,
message: S) {
let message_ref = message.as_ref();
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
with_lib(|lib| {
unsafe {
let cstr = CString::new(message_ref).unwrap();
lib.gcc_jit_block_add_comment(self.ptr, loc_ptr, cstr.as_ptr());
}
});
}
pub fn end_with_conditional<T: ToRValue<'ctx>>(&self,
loc: Option<Location<'ctx>>,
cond: T,
on_true: Block<'ctx>,
on_false: Block<'ctx>) {
let cond_rvalue = cond.to_rvalue();
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
with_lib(|lib| {
unsafe {
lib.gcc_jit_block_end_with_conditional(self.ptr, loc_ptr, rvalue::get_ptr(&cond_rvalue),
on_true.ptr, on_false.ptr);
}
});
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.to_object().get_context().get_last_error() {
panic!("{}", error);
}
}
pub fn end_with_jump(&self,
loc: Option<Location<'ctx>>,
target: Block<'ctx>) {
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
with_lib(|lib| {
unsafe {
lib.gcc_jit_block_end_with_jump(self.ptr, loc_ptr, target.ptr);
}
});
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.to_object().get_context().get_last_error() {
panic!("{}", error);
}
}
pub fn end_with_return<T: ToRValue<'ctx>>(&self,
loc: Option<Location<'ctx>>,
ret: T) {
let ret_rvalue = ret.to_rvalue();
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
with_lib(|lib| {
unsafe {
lib.gcc_jit_block_end_with_return(self.ptr, loc_ptr, rvalue::get_ptr(&ret_rvalue));
}
});
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.to_object().get_context().get_last_error() {
panic!("{}", error);
}
}
pub fn end_with_void_return(&self, loc: Option<Location<'ctx>>) {
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
with_lib(|lib| {
unsafe {
lib.gcc_jit_block_end_with_void_return(self.ptr, loc_ptr);
}
});
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.to_object().get_context().get_last_error() {
panic!("{}", error);
}
}
pub fn end_with_switch<T: ToRValue<'ctx>>(&self, loc: Option<Location<'ctx>>, expr: T, default_block: Block<'ctx>, cases: &[Case<'ctx>]) {
let expr = expr.to_rvalue();
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
with_lib(|lib| {
unsafe {
lib.gcc_jit_block_end_with_switch(self.ptr, loc_ptr, rvalue::get_ptr(&expr), block::get_ptr(&default_block),
cases.len() as c_int, cases.as_ptr() as *mut *mut _);
}
});
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.to_object().get_context().get_last_error() {
panic!("{}", error);
}
}
pub fn add_extended_asm(&self, loc: Option<Location<'ctx>>, asm_template: &str) -> ExtendedAsm<'ctx> {
let asm_template = CString::new(asm_template).unwrap();
let loc_ptr =
match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut(),
};
with_lib(|lib| {
unsafe {
ExtendedAsm::from_ptr(lib.gcc_jit_block_add_extended_asm(self.ptr, loc_ptr, asm_template.as_ptr()))
}
})
}
pub fn end_with_extended_asm_goto(&self, loc: Option<Location<'ctx>>, asm_template: &str, goto_blocks: &[Block<'ctx>], fallthrough_block: Option<Block<'ctx>>) -> ExtendedAsm<'ctx> {
let asm_template = CString::new(asm_template).unwrap();
let loc_ptr =
match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut(),
};
let fallthrough_block_ptr =
match fallthrough_block {
Some(ref block) => unsafe { get_ptr(block) },
None => ptr::null_mut(),
};
with_lib(|lib| {
unsafe {
ExtendedAsm::from_ptr(lib.gcc_jit_block_end_with_extended_asm_goto(self.ptr, loc_ptr, asm_template.as_ptr(), goto_blocks.len() as c_int, goto_blocks.as_ptr() as *mut _, fallthrough_block_ptr))
}
})
}
}
pub unsafe fn from_ptr<'ctx>(ptr: *mut gccjit_sys::gcc_jit_block) -> Block<'ctx> {
Block {
marker: PhantomData,
ptr
}
}
pub unsafe fn get_ptr<'ctx>(block: &Block<'ctx>) -> *mut gccjit_sys::gcc_jit_block {
block.ptr
}