use rucc_base::Symbol;
use crate::ast::{CharId, DesignatorList, ExprList, FloatId, GenericList, IntId, StrId};
use crate::decl::TypeNameId;
use crate::init::InitId;
use crate::stmt::StmtId;
pub type ExprId = rucc_base::Idx<Expr>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Expr {
Error,
Name(Symbol),
Int(IntId),
Float(FloatId),
Char(CharId),
Str(StrId),
Bool(bool),
Nullptr,
Index {
base: ExprId,
index: ExprId,
},
Call {
callee: ExprId,
args: ExprList,
},
Member {
base: ExprId,
name: Symbol,
arrow: bool,
},
Unary {
op: UnaryOp,
operand: ExprId,
},
Binary {
op: BinaryOp,
lhs: ExprId,
rhs: ExprId,
},
Assign {
op: Option<BinaryOp>,
lhs: ExprId,
rhs: ExprId,
},
Cond {
cond: ExprId,
then: Option<ExprId>,
otherwise: ExprId,
},
Comma {
lhs: ExprId,
rhs: ExprId,
},
Cast {
ty: TypeNameId,
operand: ExprId,
},
CompoundLiteral {
ty: TypeNameId,
init: InitId,
},
SizeofExpr(ExprId),
SizeofType(TypeNameId),
AlignofExpr(ExprId),
AlignofType(TypeNameId),
Generic {
control: ExprId,
assocs: GenericList,
},
StmtExpr(StmtId),
LabelAddr(Symbol),
Offsetof {
ty: TypeNameId,
path: DesignatorList,
},
ChooseExpr {
cond: ExprId,
then: ExprId,
otherwise: ExprId,
},
TypesCompatible {
a: TypeNameId,
b: TypeNameId,
},
VaArg {
list: ExprId,
ty: TypeNameId,
},
VaStart {
list: ExprId,
last: Option<ExprId>,
},
VaEnd {
list: ExprId,
},
VaCopy {
dst: ExprId,
src: ExprId,
},
Extension(ExprId),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnaryOp {
Plus,
Minus,
Not,
BitNot,
Deref,
AddrOf,
PreInc,
PreDec,
PostInc,
PostDec,
Real,
Imag,
}
impl UnaryOp {
#[must_use]
pub const fn spelling(self) -> &'static str {
match self {
UnaryOp::Plus => "+",
UnaryOp::Minus => "-",
UnaryOp::Not => "!",
UnaryOp::BitNot => "~",
UnaryOp::Deref => "*",
UnaryOp::AddrOf => "&",
UnaryOp::PreInc | UnaryOp::PostInc => "++",
UnaryOp::PreDec | UnaryOp::PostDec => "--",
UnaryOp::Real => "__real__",
UnaryOp::Imag => "__imag__",
}
}
#[must_use]
pub const fn is_postfix(self) -> bool {
matches!(self, UnaryOp::PostInc | UnaryOp::PostDec)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinaryOp {
Mul,
Div,
Rem,
Add,
Sub,
Shl,
Shr,
Lt,
Gt,
Le,
Ge,
Eq,
Ne,
BitAnd,
BitXor,
BitOr,
LogAnd,
LogOr,
}
impl BinaryOp {
#[must_use]
pub const fn spelling(self) -> &'static str {
match self {
BinaryOp::Mul => "*",
BinaryOp::Div => "/",
BinaryOp::Rem => "%",
BinaryOp::Add => "+",
BinaryOp::Sub => "-",
BinaryOp::Shl => "<<",
BinaryOp::Shr => ">>",
BinaryOp::Lt => "<",
BinaryOp::Gt => ">",
BinaryOp::Le => "<=",
BinaryOp::Ge => ">=",
BinaryOp::Eq => "==",
BinaryOp::Ne => "!=",
BinaryOp::BitAnd => "&",
BinaryOp::BitXor => "^",
BinaryOp::BitOr => "|",
BinaryOp::LogAnd => "&&",
BinaryOp::LogOr => "||",
}
}
#[must_use]
pub const fn is_short_circuit(self) -> bool {
matches!(self, BinaryOp::LogAnd | BinaryOp::LogOr)
}
#[must_use]
pub const fn is_comparison(self) -> bool {
matches!(
self,
BinaryOp::Lt | BinaryOp::Gt | BinaryOp::Le | BinaryOp::Ge | BinaryOp::Eq | BinaryOp::Ne
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct GenericAssoc {
pub ty: Option<TypeNameId>,
pub value: ExprId,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn an_expression_is_sixteen_bytes() {
assert_eq!(size_of::<Expr>(), 16);
}
#[test]
fn an_expression_id_is_four_bytes_even_when_optional() {
assert_eq!(size_of::<ExprId>(), 4);
assert_eq!(size_of::<Option<ExprId>>(), 4);
}
#[test]
fn postfix_increment_is_the_only_kind_that_is_postfix() {
assert!(UnaryOp::PostInc.is_postfix());
assert!(UnaryOp::PostDec.is_postfix());
assert!(!UnaryOp::PreInc.is_postfix());
assert_eq!(UnaryOp::PostInc.spelling(), UnaryOp::PreInc.spelling());
}
#[test]
fn the_six_relational_and_equality_operators_are_the_comparisons() {
let all =
[BinaryOp::Lt, BinaryOp::Gt, BinaryOp::Le, BinaryOp::Ge, BinaryOp::Eq, BinaryOp::Ne];
assert!(all.iter().all(|op| op.is_comparison()));
assert!(!BinaryOp::Add.is_comparison());
assert!(!BinaryOp::LogAnd.is_comparison());
}
#[test]
fn only_the_logical_operators_short_circuit() {
assert!(BinaryOp::LogAnd.is_short_circuit());
assert!(BinaryOp::LogOr.is_short_circuit());
assert!(!BinaryOp::BitAnd.is_short_circuit());
}
}