use std::fmt::{self, Display, Write};
use crate::formatter::Formatter;
#[derive(Debug, Clone, PartialEq, Copy)]
pub enum Visibility {
Public,
Protected,
Private,
Default,
}
impl Visibility {
pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
use Visibility::*;
match self {
Public => write!(fmt, "public"),
Protected => write!(fmt, "protected"),
Private => write!(fmt, "private"),
Default => Ok(()),
}
}
}
impl Display for Visibility {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut ret = String::new();
self.fmt(&mut Formatter::new(&mut ret)).unwrap();
write!(f, "{ret}")
}
}
#[derive(Debug, Clone)]
pub enum BaseType {
Void,
Double,
Float,
Char,
UInt8,
UInt16,
UInt32,
UInt64,
Int8,
Int16,
Int32,
Int64,
Size,
UIntPtr,
Bool,
Enum(String),
Struct(String),
Union(String),
Class(String),
TemplateClass(String, Vec<String>),
TypeDef(String, bool),
}
impl BaseType {
pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
use BaseType::*;
match self {
Void => write!(fmt, "void"),
Double => write!(fmt, "double"),
Float => write!(fmt, "float"),
Char => write!(fmt, "char"),
UInt8 => write!(fmt, "uint8_t"),
UInt16 => write!(fmt, "uint16_t"),
UInt32 => write!(fmt, "uint32_t"),
UInt64 => write!(fmt, "uint64_t"),
Int8 => write!(fmt, "int8_t"),
Int16 => write!(fmt, "int16_t"),
Int32 => write!(fmt, "int32_t"),
Int64 => write!(fmt, "int64_t"),
Size => write!(fmt, "size_t"),
UIntPtr => write!(fmt, "uintptr_t"),
Bool => write!(fmt, "bool"),
Enum(s) => write!(fmt, "enum {s}"),
Struct(s) => write!(fmt, "struct {s}"),
Union(s) => write!(fmt, "union {s}"),
Class(s) => write!(fmt, "{s}"),
TemplateClass(s, t) => {
if !t.is_empty() {
write!(fmt, "{}<{}>", s, t.join(","))
} else {
write!(fmt, "{s}")
}
}
TypeDef(s, _) => write!(fmt, "{s}"),
}
}
pub fn is_integer(&self) -> bool {
use BaseType::*;
matches!(self, |UInt8| UInt16 | UInt32 | UInt64
| Int8 | Int16 | Int32 | Int64
| Size | UIntPtr | Bool | Char
| TypeDef(_, false))
}
pub fn is_struct(&self) -> bool {
use BaseType::*;
matches!(self, Struct(_) | Union(_) | Class(_) | TemplateClass(_, _) | TypeDef(_, _))
}
pub fn new_uint(bits: u64) -> BaseType {
use BaseType::*;
match bits {
8 => UInt8,
16 => UInt16,
32 => UInt32,
64 => UInt64,
_ => {
println!("Unsupported integer size: {bits}. Defaulting to u64");
UInt64
}
}
}
pub fn new_int(bits: u64) -> BaseType {
use BaseType::*;
match bits {
8 => Int8,
16 => Int16,
32 => Int32,
64 => Int64,
_ => {
println!("Unsupported integer size: {bits}. Defaulting to i64");
Int64
}
}
}
}
impl Display for BaseType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut ret = String::new();
self.fmt(&mut Formatter::new(&mut ret)).unwrap();
write!(f, "{ret}")
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum TypeModifier {
Ptr,
Volatile,
Const,
Ref,
}
#[derive(Debug, Clone)]
pub struct Type {
base: BaseType,
mods: Vec<TypeModifier>,
nptr: u8,
is_const: bool,
is_volatile: bool,
array_size: usize,
}
impl TypeModifier {
pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
use TypeModifier::*;
match self {
Ptr => write!(fmt, " *"),
Volatile => write!(fmt, " volatile"),
Const => write!(fmt, " const"),
Ref => write!(fmt, " &"),
}
}
}
impl Type {
pub fn new(base: BaseType) -> Self {
Type {
base,
mods: Vec::new(),
nptr: 0,
is_volatile: false,
is_const: false,
array_size: 0,
}
}
pub fn new_void() -> Self {
Type::new(BaseType::Void)
}
pub fn new_bool() -> Self {
Type::new(BaseType::Bool)
}
pub fn new_char() -> Self {
Type::new(BaseType::Char)
}
pub fn new_int(bits: u64) -> Self {
Type::new(BaseType::new_int(bits))
}
pub fn new_int8() -> Self {
Type::new(BaseType::Int8)
}
pub fn new_int16() -> Self {
Type::new(BaseType::Int16)
}
pub fn new_int32() -> Self {
Type::new(BaseType::Int32)
}
pub fn new_int64() -> Self {
Type::new(BaseType::Int64)
}
pub fn new_uint(bits: u64) -> Self {
Type::new(BaseType::new_uint(bits))
}
pub fn new_uint8() -> Self {
Type::new(BaseType::UInt8)
}
pub fn new_uint16() -> Self {
Type::new(BaseType::UInt16)
}
pub fn new_uint32() -> Self {
Type::new(BaseType::UInt32)
}
pub fn new_uint64() -> Self {
Type::new(BaseType::UInt64)
}
pub fn new_size() -> Self {
Type::new(BaseType::Size)
}
pub fn new_uintptr() -> Self {
Type::new(BaseType::UIntPtr)
}
pub fn new_float() -> Self {
Type::new(BaseType::Float)
}
pub fn new_double() -> Self {
Type::new(BaseType::Double)
}
pub fn new_std_string() -> Self {
Type::new_class("std::string")
}
pub fn new_cstr() -> Self {
let mut t = Type::new_char();
t.pointer();
t
}
pub fn new_enum(name: &str) -> Self {
Type::new(BaseType::Enum(String::from(name)))
}
pub fn new_struct(name: &str) -> Self {
Type::new(BaseType::Struct(String::from(name)))
}
pub fn new_union(name: &str) -> Self {
Type::new(BaseType::Union(String::from(name)))
}
pub fn new_class(name: &str) -> Self {
Type::new(BaseType::Class(String::from(name)))
}
pub fn new_typedef(name: &str) -> Self {
Type::new(BaseType::TypeDef(name.to_string(), false))
}
pub fn new_typedef_ptr(name: &str) -> Self {
Type::new(BaseType::TypeDef(name.to_string(), true))
}
pub fn to_ptr(&self) -> Self {
let mut n = self.clone();
n.mods.push(TypeModifier::Ptr);
n.nptr += 1;
n
}
pub fn to_ref(&self) -> Self {
let mut n = self.clone();
n.mods.push(TypeModifier::Ref);
n
}
pub fn to_deref(&self) -> Option<Self> {
if self.nptr == 0 {
return None;
}
let mut n = Self::new(self.base.clone());
n.is_const = self.is_const;
n.is_volatile = self.is_volatile;
for m in &self.mods {
if *m == TypeModifier::Ptr {
if n.nptr == self.nptr - 1 {
return Some(n);
}
n.nptr += 1;
}
n.mods.push(*m);
}
Some(n)
}
pub fn to_const(&mut self) -> Self {
let mut n = self.clone();
n.mods.push(TypeModifier::Const);
n
}
pub fn to_volatile(&mut self) -> &mut Self {
self.mods.push(TypeModifier::Volatile);
self
}
pub fn to_array(mut self, nelems: usize) -> Self {
self.array_size = nelems;
self
}
pub fn basetype(&self) -> &BaseType {
&self.base
}
pub fn is_struct(&self) -> bool {
self.base.is_struct()
}
pub fn is_integer(&self) -> bool {
if self.nptr != 0 {
return false;
}
self.base.is_integer()
}
pub fn is_ptr(&self) -> bool {
self.nptr > 0 || self.array_size != 0 || matches!(self.base, BaseType::TypeDef(_, true))
}
pub fn is_array(&self) -> bool {
self.array_size != 0
}
pub fn get_array_size(&self) -> usize {
self.array_size
}
pub fn toggle_value_volatile(&mut self, val: bool) -> &mut Self {
self.is_volatile = val;
if val {
self.is_const = false;
}
self
}
pub fn set_value_volatile(&mut self) -> &mut Self {
self.toggle_value_volatile(true)
}
pub fn toggle_value_const(&mut self, val: bool) -> &mut Self {
self.is_const = val;
if val {
self.is_volatile = false;
}
self
}
pub fn set_value_const(&mut self) -> &mut Self {
self.toggle_value_const(true)
}
pub fn pointer(&mut self) -> &mut Self {
assert!(self.nptr < 32);
self.mods.push(TypeModifier::Ptr);
self.nptr += 1;
self
}
pub fn reference(&mut self) -> &mut Self {
self.mods.push(TypeModifier::Ref);
self
}
pub fn constant(&mut self) -> &mut Self {
self.mods.push(TypeModifier::Const);
self
}
pub fn volatile(&mut self) -> &mut Self {
self.mods.push(TypeModifier::Volatile);
self
}
pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
if self.is_volatile {
write!(fmt, "volatile ")?;
}
if self.is_const {
write!(fmt, "const ")?;
}
self.base.fmt(fmt)?;
for m in &self.mods {
m.fmt(fmt)?
}
Ok(())
}
}
impl Display for Type {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut ret = String::new();
self.fmt(&mut Formatter::new(&mut ret)).unwrap();
write!(f, "{ret}")
}
}