use std::fmt;
use crate::ty::*;
use std::cmp::Ordering;
#[derive(Clone)]
pub struct Expr {
pub kind: Kind,
pub loc: Loc,
}
#[derive(Debug, Clone)]
pub struct Comment {
pub syntax: String,
pub loc: Loc,
pub after_code: bool,
}
impl PartialEq for Expr {
fn eq(&self, other: &Self) -> bool {
self.kind.eq(&other.kind)
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum Kind {
TyDecl(TyDecl),
RecordDecl(RecordDecl),
FunctionDecl(FunctionDecl, Box<Expr>),
FunctionProtoDecl(FunctionDecl),
VarDecl(VarDecl),
InitList(Vec<Expr>),
TranslationUnit(TranslationUnit),
ExternC(Vec<Expr>),
Block(Block),
Paren(Box<Expr>),
Switch(Switch),
Case(Case),
For(For),
ForIn(ForIn), While(While),
If(If),
Call(Call),
Return(Option<Box<Expr>>),
Break,
Goto(String),
Label(String, Box<Expr>),
Continue,
DeclRef(String),
MacroRef(String),
BinaryOperator(BinaryOperator),
UnaryOperator(UnaryOperator),
SizeOf(SizeOf),
OffsetOf(Ty, String),
IntegerLiteral(u64, Option<Ty>),
StringLiteral(String),
FloatingLiteral(f64, Option<Ty>),
CharacterLiteral(char),
CompoundLiteral(CompoundLiteral),
Cast(Cast),
MemberRef(MemberRef),
DesignatedInit(String, Box<Expr>),
Namespace(String, Vec<Expr>),
ClassDecl(ClassDecl),
CXXConstructor(String),
CXXDestructor(String),
CXXMethod(String),
Throw(Box<Expr>),
Try(Box<Expr>),
TransparentGroup(TransparentGroup),
Invalid(String),
}
static bool_ty: Ty = Ty {
debug_name: None,
kind: TyKind::Bool,
is_const: true,
};
impl Kind {
#[must_use] pub fn ty(&self) -> Option<&Ty> {
Some(match *self {
Kind::TyDecl(ref t) => &t.ty,
Kind::FunctionDecl(ref t, _) => &t.ty,
Kind::FunctionProtoDecl(ref t) => &t.ty,
Kind::VarDecl(VarDecl{ty: Some(ref ty),..}) => ty,
Kind::CompoundLiteral(ref t) => &t.ty,
Kind::Cast(ref t) => &t.ty,
Kind::Paren(ref t) => return t.kind.ty(),
Kind::TransparentGroup(TransparentGroup{ref items}) if items.len() == 1 => return items[0].kind.ty(),
Kind::Block(Block{ref items, returns_value:true}) => return items.last().and_then(|i|i.kind.ty()),
Kind::DesignatedInit(_, ref arg) => return arg.kind.ty(),
Kind::If(ref t) => return t.body.kind.ty(),
Kind::IntegerLiteral(_, Some(ref ty)) => return Some(ty),
Kind::UnaryOperator(UnaryOperator { kind: UnOpKind::IsNull | UnOpKind::Not, ..
}) => return Some(&bool_ty),
Kind::BinaryOperator(BinaryOperator{kind,..}) if match kind {
BinOpKind::And |
BinOpKind::Or |
BinOpKind::Eq |
BinOpKind::Lt |
BinOpKind::Le |
BinOpKind::Ne |
BinOpKind::Ge |
BinOpKind::Gt => true,
_ => false,
} => return Some(&bool_ty),
_ => return None,
})
}
}
#[derive(Clone, PartialEq)]
pub struct TranslationUnit {
pub name: String,
pub items: Vec<Expr>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct TyDecl {
pub name: String,
pub ty: Ty,
}
impl fmt::Debug for TranslationUnit {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "{}", self.name)?;
for item in &self.items {
writeln!(f, "{item:?}")?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct RecordDecl {}
#[derive(Debug, Clone, PartialEq)]
pub struct VarDecl {
pub name: String,
pub init: Option<Box<Expr>>,
pub ty: Option<Ty>,
pub storage: Storage,
}
#[derive(Debug, Clone, PartialEq)]
pub struct FunctionDecl {
pub name: String,
pub args: Vec<Arg>,
pub variadic: bool,
pub ty: Ty,
pub storage: Storage,
pub abi: Abi,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ClassDecl {
pub name: String,
pub base: Vec<Ty>,
pub items: Vec<Expr>,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum UnOpKind {
PostInc,
PostDec,
PreInc,
PreDec,
PostIncPtr,
PostDecPtr,
PreIncPtr,
PreDecPtr,
AddrOf(bool), Deref,
Plus,
Minus,
BinNot,
Not,
IsNull,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum BinOpKind {
Add,
Sub,
AddPtr,
SubPtr,
Mul,
Div,
Rem,
And,
Or,
BitXor,
BitAnd,
BitOr,
Shl,
Shr,
Eq,
Lt,
Le,
Ne,
Ge,
Gt,
MulAssign,
DivAssign,
RemAssign,
AddAssign,
SubAssign,
AddPtrAssign,
SubPtrAssign,
ShlAssign,
ShrAssign,
BitAndAssign,
BitXorAssign,
BitOrAssign,
Assign,
Comma,
ArrayIndex,
PointerIndex,
HalfOpenRange,
ClosedRange,
}
#[derive(Clone, PartialEq)]
pub struct BinaryOperator {
pub kind: BinOpKind,
pub left: Box<Expr>,
pub right: Box<Expr>,
}
#[derive(Clone, PartialEq)]
pub struct UnaryOperator {
pub kind: UnOpKind,
pub arg: Box<Expr>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct SizeOf {
pub arg: Option<Box<Expr>>,
pub ty: Ty,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CompoundLiteral {
pub items: Vec<Expr>,
pub ty: Ty,
}
#[derive(Copy, Clone, PartialEq)]
pub struct Loc {
pub byte_pos: u32,
pub byte_len: u32,
pub start_line: u32,
pub start_col: u16,
pub line_len: u16,
}
#[derive(Clone, PartialEq)]
pub struct Cast {
pub arg: Box<Expr>,
pub ty: Ty,
pub explicit: bool,
}
#[derive(Debug, Clone, PartialEq)]
pub struct MemberRef {
pub arg: Box<Expr>,
pub name: String,
}
#[derive(Clone, PartialEq)]
pub struct Call {
pub callee: Box<Expr>,
pub args: Vec<Expr>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Switch {
pub cond: Box<Expr>,
pub items: Vec<Expr>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct While {
pub cond: Box<Expr>,
pub body: Box<Expr>,
pub is_do: bool,
}
#[derive(Debug, Clone, PartialEq)]
pub struct For {
pub init: Option<Box<Expr>>,
pub cond: Option<Box<Expr>>,
pub inc: Option<Box<Expr>>,
pub body: Box<Expr>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ForIn {
pub pattern: Box<Expr>,
pub iter: Box<Expr>,
pub body: Box<Expr>,
}
#[derive(Clone, PartialEq)]
pub struct Case {
pub conds: Vec<Expr>, pub items: Vec<Expr>,
}
#[derive(Clone, PartialEq)]
pub struct If {
pub cond: Box<Expr>,
pub body: Box<Expr>,
pub alt: Option<Box<Expr>>,
pub returns_value: bool,
}
#[derive(Clone, PartialEq)]
pub struct Block {
pub items: Vec<Expr>,
pub returns_value: bool,
}
#[derive(Clone, PartialEq)]
pub struct TransparentGroup {
pub items: Vec<Expr>,
}
impl Kind {
#[must_use] pub fn flat(mut self) -> Self {
match self {
Kind::TransparentGroup(TransparentGroup{ref mut items}) if items.len() == 1 => {
items.remove(0).kind
},
_ => self,
}
}
}
fn fmt_items(f: &mut fmt::Formatter, items: &[Expr]) -> fmt::Result {
f.debug_list().entries(items).finish()
}
impl fmt::Debug for TransparentGroup {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.items.len() {
0 => write!(f, ";"),
1 => self.items[0].fmt(f),
_ => fmt_items(f, &self.items)
}
}
}
impl fmt::Debug for Block {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt_items(f, &self.items)
}
}
impl fmt::Debug for Case {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for cond in &self.conds {
writeln!(f, "{cond:?}:")?;
}
fmt_items(f, &self.items)
}
}
impl fmt::Debug for Cast {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({:?})({:?})", self.ty, self.arg)
}
}
impl fmt::Debug for Call {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}({:?})", self.callee, self.args)
}
}
impl fmt::Debug for Expr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?} {:?}", self.loc, self.kind)
}
}
impl fmt::Debug for If {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "if {:?} {{\n{:?}\n}}\n", self.cond, self.body)?;
if let Some(ref alt) = self.alt {
write!(f, "else {{\n{alt:?}\n}}\n")?;
}
Ok(())
}
}
impl fmt::Debug for BinaryOperator {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({:?} {:?} {:?})", self.left, self.kind, self.right)
}
}
impl fmt::Debug for UnaryOperator {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}({:?})", self.kind, self.arg)
}
}
impl fmt::Debug for Loc {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.start_line != 0 {
write!(f, ":{}", self.start_line)?;
if self.line_len > 0 {
write!(f, "-{}", self.start_line + u32::from(self.line_len))?;
} else {
write!(f, ":{}", self.start_col)?;
}
} else {
write!(f, "-")?;
}
Ok(())
}
}