use ffi::prelude::LLVMTypeRef;
use ffi::{core, target, LLVMTypeKind};
use libc::{c_int, c_uint};
use compile::Compile;
use context::{Context, GetContext};
use target::TargetData;
use util::{self, Sub};
use std::{fmt, mem};
use std::marker::PhantomData;
use std::iter::Iterator;
use std::ops::Deref;
macro_rules! sub {
($ty:ty, $kind:ident) => (
unsafe impl Sub<::Type> for $ty {
fn is(ty: &Type) -> bool {
unsafe {
let kind = core::LLVMGetTypeKind(ty.into());
kind as c_uint == LLVMTypeKind::$kind as c_uint
}
}
}
deref!{$ty, Type}
)
}
pub struct Type(PhantomData<[u8]>);
native_ref!{&Type = LLVMTypeRef}
get_context!{Type, LLVMGetTypeContext}
to_str!{Type, LLVMPrintTypeToString}
impl Type {
#[inline(always)]
pub fn get<'a, T>(context:&'a Context) -> &'a Type where T:Compile<'a> {
T::get_type(context)
}
pub fn is_sized(&self) -> bool {
unsafe { core::LLVMTypeIsSized(self.into()) != 0 }
}
pub fn is_function(&self) -> bool {
let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
kind as c_uint == LLVMTypeKind::LLVMFunctionTypeKind as c_uint
}
pub fn is_struct(&self) -> bool {
let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
kind as c_uint == LLVMTypeKind::LLVMStructTypeKind as c_uint
}
pub fn is_void(&self) -> bool {
let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
kind as c_uint == LLVMTypeKind::LLVMVoidTypeKind as c_uint
}
pub fn is_pointer(&self) -> bool {
let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
kind as c_uint == LLVMTypeKind::LLVMPointerTypeKind as c_uint
}
pub fn is_integer(&self) -> bool {
let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
kind as c_uint == LLVMTypeKind::LLVMIntegerTypeKind as c_uint
}
pub fn is_float(&self) -> bool {
let kind = unsafe { core::LLVMGetTypeKind(self.into()) } as c_uint;
kind == LLVMTypeKind::LLVMHalfTypeKind as c_uint ||
kind == LLVMTypeKind::LLVMFloatTypeKind as c_uint ||
kind == LLVMTypeKind::LLVMDoubleTypeKind as c_uint
}
pub fn get_size(&self, target: &TargetData) -> usize {
unsafe { target::LLVMABISizeOfType(target.into(), self.into()) as usize }
}
}
pub struct StructType;
native_ref!{&StructType = LLVMTypeRef}
get_context!{StructType, LLVMGetTypeContext}
to_str!{StructType, LLVMPrintTypeToString}
sub!{StructType, LLVMStructTypeKind}
impl StructType {
pub fn new<'a>(context: &'a Context, fields: &[&'a Type], packed: bool) -> &'a StructType {
unsafe { core::LLVMStructTypeInContext(context.into(), fields.as_ptr() as *mut LLVMTypeRef, fields.len() as c_uint, packed as c_int) }.into()
}
pub fn new_named<'a>(context: &'a Context, name: &str, fields: &[&'a Type], packed: bool) -> &'a StructType {
util::with_cstr(name, |name| unsafe {
let ty = core::LLVMStructCreateNamed(context.into(), name);
core::LLVMStructSetBody(ty, fields.as_ptr() as *mut LLVMTypeRef, fields.len() as c_uint, packed as c_int);
ty.into()
})
}
pub fn get_elements(&self) -> Vec<&Type> {
unsafe {
let size = core::LLVMCountStructElementTypes(self.into());
let mut els:Vec<_> = (0..size).map(|_| mem::uninitialized()).collect();
core::LLVMGetStructElementTypes(self.into(), els.as_mut_ptr() as *mut LLVMTypeRef);
els
}
}
}
pub struct FunctionType;
native_ref!{&FunctionType = LLVMTypeRef}
get_context!{FunctionType, LLVMGetTypeContext}
to_str!{FunctionType, LLVMPrintTypeToString}
deref!{FunctionType, Type}
unsafe impl Sub<Type> for FunctionType {
fn is(mut ty: &Type) -> bool {
unsafe {
while let Some(ptr) = PointerType::from_super(ty) {
ty = ptr.get_element();
}
let kind = core::LLVMGetTypeKind(ty.into());
kind as c_uint == LLVMTypeKind::LLVMFunctionTypeKind as c_uint
}
}
}
impl FunctionType {
pub fn new<'a>(ret: &'a Type, args: &[&'a Type]) -> &'a FunctionType {
unsafe { core::LLVMFunctionType(ret.into(), args.as_ptr() as *mut LLVMTypeRef, args.len() as c_uint, 0) }.into()
}
pub fn num_params(&self) -> usize {
unsafe { core::LLVMCountParamTypes(self.into()) as usize }
}
pub fn get_params(&self) -> Vec<&Type> {
unsafe {
let count = core::LLVMCountParamTypes(self.into());
let mut types:Vec<_> = (0..count).map(|_| mem::uninitialized()).collect();
core::LLVMGetParamTypes(self.into(), types.as_mut_ptr() as *mut LLVMTypeRef);
types
}
}
pub fn get_return(&self) -> &Type {
unsafe { core::LLVMGetReturnType(self.into()).into() }
}
}
pub struct PointerType;
native_ref!{&PointerType = LLVMTypeRef}
get_context!{PointerType, LLVMGetTypeContext}
to_str!{PointerType, LLVMPrintTypeToString}
sub!{PointerType, LLVMPointerTypeKind}
impl PointerType {
pub fn new(elem: &Type) -> &Type {
unsafe { core::LLVMPointerType(elem.into(), 0 as c_uint) }.into()
}
pub fn get_element(&self) -> &Type {
unsafe { mem::transmute(core::LLVMGetElementType(self.into())) }
}
}
pub struct IntegerType;
native_ref!{&IntegerType = LLVMTypeRef}
get_context!{IntegerType, LLVMGetTypeContext}
to_str!{IntegerType, LLVMPrintTypeToString}
sub!{IntegerType, LLVMPointerTypeKind}
impl IntegerType {
pub fn new(context: &Context, numbits: usize) -> &IntegerType {
unsafe { core::LLVMIntTypeInContext(context.into(), numbits as c_uint) }.into()
}
pub fn get_width(&self) -> usize {
unsafe { core::LLVMGetIntTypeWidth (self.into()) as usize }
}
}
pub struct VectorType;
native_ref!{&VectorType = LLVMTypeRef}
get_context!{VectorType, LLVMGetTypeContext}
to_str!{VectorType, LLVMPrintTypeToString}
sub!{VectorType, LLVMVectorTypeKind}
impl VectorType {
pub fn new(element: &Type, length: usize) -> &VectorType {
unsafe { core::LLVMVectorType(element.into(), length as c_uint) }.into()
}
pub fn get_element(&self) -> &Type {
unsafe { mem::transmute(core::LLVMGetElementType(self.into())) }
}
pub fn get_size(&self) -> usize {
unsafe { core::LLVMGetVectorSize(self.into()) as usize }
}
}
pub struct ArrayType;
native_ref!{&ArrayType = LLVMTypeRef}
get_context!{ArrayType, LLVMGetTypeContext}
to_str!{ArrayType, LLVMPrintTypeToString}
sub!{ArrayType, LLVMArrayTypeKind}
impl ArrayType {
pub fn new(element: &Type, length: usize) -> &ArrayType {
unsafe { core::LLVMArrayType(element.into(), length as c_uint) }.into()
}
pub fn get_element(&self) -> &Type {
unsafe { mem::transmute(core::LLVMGetElementType(self.into())) }
}
pub fn get_length(&self) -> usize {
unsafe { core::LLVMGetArrayLength(self.into()) as usize }
}
}