blob: bb91c18300c8611c5e9c9611a9bb7fc2a14139ba [file] [log] [blame] [edit]
use std::marker::PhantomData;
use std::fmt;
use std::ptr;
use std::mem;
use std::ops::{Add, Sub, Mul, Div, Rem, BitAnd, BitOr, BitXor, Shl, Shr};
use context::Context;
use object::{ToObject, Object};
use object;
use types::Type;
use types;
use field::Field;
use field;
use lvalue::LValue;
use lvalue;
use location::Location;
use location;
use block::BinaryOp;
/// An RValue is a value that may or may not have a storage address in gccjit.
/// RValues can be dereferenced, used for field accesses, and are the parameters
/// given to a majority of the gccjit API calls.
#[derive(Copy, Clone, Eq, Hash, PartialEq)]
pub struct RValue<'ctx> {
marker: PhantomData<&'ctx Context<'ctx>>,
ptr: *mut gccjit_sys::gcc_jit_rvalue
}
/// ToRValue is a trait implemented by types that can be converted to, or
/// treated as, an RValue.
pub trait ToRValue<'ctx> {
fn to_rvalue(&self) -> RValue<'ctx>;
}
impl<'ctx> ToObject<'ctx> for RValue<'ctx> {
fn to_object(&self) -> Object<'ctx> {
unsafe {
object::from_ptr(gccjit_sys::gcc_jit_rvalue_as_object(self.ptr))
}
}
}
impl<'ctx> fmt::Debug for RValue<'ctx> {
fn fmt<'a>(&self, fmt: &mut fmt::Formatter<'a>) -> Result<(), fmt::Error> {
let obj = self.to_object();
obj.fmt(fmt)
}
}
impl<'ctx> ToRValue<'ctx> for RValue<'ctx> {
fn to_rvalue(&self) -> RValue<'ctx> {
unsafe { from_ptr(self.ptr) }
}
}
macro_rules! binary_operator_for {
($ty:ty, $name:ident, $op:expr) => {
impl<'ctx> $ty for RValue<'ctx> {
type Output = RValue<'ctx>;
fn $name(self, rhs: RValue<'ctx>) -> RValue<'ctx> {
unsafe {
let rhs_rvalue = rhs.to_rvalue();
let obj_ptr = object::get_ptr(&self.to_object());
let ctx_ptr = gccjit_sys::gcc_jit_object_get_context(obj_ptr);
let ty = rhs.get_type();
let ptr = gccjit_sys::gcc_jit_context_new_binary_op(ctx_ptr,
ptr::null_mut(),
mem::transmute::<BinaryOp, gccjit_sys::gcc_jit_binary_op>($op),
types::get_ptr(&ty),
self.ptr,
rhs_rvalue.ptr);
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.to_object().get_context().get_last_error() {
panic!("{}", error);
}
from_ptr(ptr)
}
}
}
}
}
// Operator overloads for ease of manipulation of rvalues
binary_operator_for!(Add, add, BinaryOp::Plus);
binary_operator_for!(Sub, sub, BinaryOp::Minus);
binary_operator_for!(Mul, mul, BinaryOp::Mult);
binary_operator_for!(Div, div, BinaryOp::Divide);
binary_operator_for!(Rem, rem, BinaryOp::Modulo);
binary_operator_for!(BitAnd, bitand, BinaryOp::BitwiseAnd);
binary_operator_for!(BitOr, bitor, BinaryOp::BitwiseOr);
binary_operator_for!(BitXor, bitxor, BinaryOp::BitwiseXor);
binary_operator_for!(Shl<RValue<'ctx>>, shl, BinaryOp::LShift);
binary_operator_for!(Shr<RValue<'ctx>>, shr, BinaryOp::RShift);
impl<'ctx> RValue<'ctx> {
/// Gets the type of this RValue.
pub fn get_type(&self) -> Type<'ctx> {
unsafe {
let ptr = gccjit_sys::gcc_jit_rvalue_get_type(self.ptr);
types::from_ptr(ptr)
}
}
/// Sets the location of this RValue.
#[cfg(feature="master")]
pub fn set_location(&self, loc: Location) {
unsafe {
let loc_ptr = location::get_ptr(&loc);
gccjit_sys::gcc_jit_rvalue_set_location(self.ptr, loc_ptr);
}
}
/// Change the type of this RValue.
#[cfg(feature="master")]
pub fn set_type(&self, typ: Type<'ctx>) {
unsafe {
let type_ptr = types::get_ptr(&typ);
gccjit_sys::gcc_jit_rvalue_set_type(self.ptr, type_ptr);
}
}
/// Given an RValue x and a Field f, returns an RValue representing
/// C's x.f.
pub fn access_field(&self,
loc: Option<Location<'ctx>>,
field: Field<'ctx>) -> RValue<'ctx> {
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
unsafe {
let ptr = gccjit_sys::gcc_jit_rvalue_access_field(self.ptr,
loc_ptr,
field::get_ptr(&field));
from_ptr(ptr)
}
}
/// Given an RValue x and a Field f, returns an LValue representing
/// C's x->f.
pub fn dereference_field(&self,
loc: Option<Location<'ctx>>,
field: Field<'ctx>) -> LValue<'ctx> {
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
unsafe {
let ptr = gccjit_sys::gcc_jit_rvalue_dereference_field(self.ptr,
loc_ptr,
field::get_ptr(&field));
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.to_object().get_context().get_last_error() {
panic!("{}", error);
}
lvalue::from_ptr(ptr)
}
}
/// Given a RValue x, returns an RValue that represents *x.
pub fn dereference(&self,
loc: Option<Location<'ctx>>) -> LValue<'ctx> {
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
unsafe {
let ptr = gccjit_sys::gcc_jit_rvalue_dereference(self.ptr,
loc_ptr);
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.to_object().get_context().get_last_error() {
panic!("{}", error);
}
lvalue::from_ptr(ptr)
}
}
}
pub unsafe fn from_ptr<'ctx>(ptr: *mut gccjit_sys::gcc_jit_rvalue) -> RValue<'ctx> {
RValue {
marker: PhantomData,
ptr
}
}
pub unsafe fn get_ptr<'ctx>(rvalue: &RValue<'ctx>) -> *mut gccjit_sys::gcc_jit_rvalue {
rvalue.ptr
}