c3 0.11.2

Complete C AST. Enables analysis and generation of code derived from C. Built using LLVM 4/Clang using some fragile C++ APIs to work around missing data and ambiguities in libclang.
use crate::expr::*;
use std::fmt;

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Visibility {
    Default,
    Hidden,
}

#[derive(Clone, PartialEq)]
pub struct Ty {
    pub debug_name: Option<String>,
    pub kind: TyKind,
    pub is_const: bool,
}

#[derive(Debug, Clone)]
pub enum TyKind {
    Bool,
    Int,
    UInt,
    Short,
    UShort,
    Long,
    ULong,
    LongLong,
    ULongLong,
    Int128,
    UInt128,
    Float,
    Double,
    LongDouble,
    SChar,
    UChar,
    WChar,
    Char16,
    Char32,
    Void,

    Auto,
    BlockPointer,
    Complex,
    Dependent,
    DependentSizedArray,
    Enum(String, Vec<EnumConstant>),
    Struct(String, Vec<Field>),
    Union(String, Vec<Field>),
    FunctionNoProto,
    FunctionProto,
    ConstantArray(usize, Box<Ty>),
    VariableArray(Box<Expr>, Box<Ty>),
    IncompleteArray(Box<Ty>),
    Pointer(Box<Ty>),
    Elaborated(String, Option<Box<Ty>>),
    Typedef(String),
    Record(Box<Expr>),

    /// Rusty
    Reference(Box<Ty>),
    Slice(Box<Ty>),
    Generic(String), // template parameter

    // Not supported yet:
    // MemberPointer,
    // NullPtr,
    // ObjCClass,
    // ObjCId,
    // ObjCInterface,
    // ObjCObjectPointer,
    // ObjCSel,
    // Overload,
    // RValueReference,
    // Vector,
}

impl PartialEq for TyKind {
    fn eq(&self, other: &Self) -> bool {
        use crate::TyKind::*;
        match (self, other) {
            (&Bool, &Bool) |
            (&Int, &Int) |
            (&UInt, &UInt) |
            (&Short, &Short) |
            (&UShort, &UShort) |
            (&Long, &Long) |
            (&ULong, &ULong) |
            (&LongLong, &LongLong) |
            (&ULongLong, &ULongLong) |
            (&Int128, &Int128) |
            (&UInt128, &UInt128) |
            (&Float, &Float) |
            (&Double, &Double) |
            (&LongDouble, &LongDouble) |
            (&SChar, &SChar) |
            (&UChar, &UChar) |
            (&WChar, &WChar) |
            (&Char16, &Char16) |
            (&Char32, &Char32) |
            (&Auto, &Auto) |
            (&BlockPointer, &BlockPointer) |
            (&Complex, &Complex) |
            (&Void, &Void) => true,
            (ConstantArray(s1, ty1), ConstantArray(s2, ty2)) if s1 == s2 && ty1 == ty2 => true,
            (VariableArray(s1, ty1), VariableArray(s2, ty2)) if s1 == s2 && ty1 == ty2 => true,
            (Enum(s1, ty1), Enum(s2, ty2)) if s1 == s2 && ty1 == ty2 => true,
            (IncompleteArray(ty1), IncompleteArray(ty2)) if ty1 == ty2 => true,
            (&Struct(ref s1, _), &Struct(ref s2, _)) |
            (&Union(ref s1, _), &Union(ref s2, _)) if s1 == s2 => true,
            (Pointer(ty1), Pointer(ty2)) if ty1 == ty2 => true,

            // // Dependent
            // // DependentSizedArray
            // // FunctionNoProto
            // // FunctionProto
            (&Elaborated(ref n1, _) | &Struct(ref n1, _) | &Union(ref n1, _) |
&Enum(ref n1, _), &Elaborated(ref n2, _)) |
(&Elaborated(ref n1, _),
&Struct(ref n2, _) | &Union(ref n2, _) | &Enum(ref n2, _)) if n1 == n2 => true,
            (&Typedef(ref s1), &Typedef(ref s2)) |
            (&Generic(ref s1), &Generic(ref s2)) if s1 == s2 => true,

            (&Slice(ref s1), &Slice(ref s2)) |
            (&Reference(ref s1), &Reference(ref s2)) if s1 == s2 => true,
            // // Record
            _ => false,
        }
    }
}

impl PartialEq for EnumConstant {
    fn eq(&self, other: &Self) -> bool {
        self.name.eq(&other.name)
    }
}

#[derive(Clone)]
pub struct EnumConstant {
    pub name: String,
    pub value: Option<Expr>,
}

impl fmt::Debug for EnumConstant {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} = {:?}", self.name, self.value)
    }
}


#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Storage {
    None,
    Static,
    Extern,
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Abi {
    C,
    Rust,
    Stdcall,
    Fastcall,
    Vectorcall,
    Thiscall,
    Aapcs,
    Win64,
    SysV64,
}

#[derive(Clone)]
pub struct Arg {
    pub name: String,
    pub ty: Ty,
    pub loc: Loc,
}

impl PartialEq for Arg {
    fn eq(&self, other: &Self) -> bool {
        self.name.eq(&other.name) &&
        self.ty.eq(&other.ty)
    }
}


#[derive(Debug, Clone, PartialEq)]
pub struct Field {
    pub name: String,
    pub ty: Ty,
    pub loc: Loc,
}

impl fmt::Debug for Ty {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use crate::TyKind::*;
        if self.is_const {
            write!(f, "const ")?;
        }
        match self.kind {
            IncompleteArray(ref ty) => write!(f, "[{ty:?}; …]"),
            ConstantArray(ref sz, ref ty) => write!(f, "[{ty:?}; {sz:?}]"),
            Pointer(ref po) => write!(f, "*{po:?}"),
            ref other => write!(f, "{other:?}"),
        }
    }
}

impl fmt::Debug for Arg {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?} {:?}", self.name, self.ty)
    }
}