use rucc_ast::{BinaryOp, UnaryOp};
use rucc_base::{Idx, IdxRange};
use rucc_types::TypeId;
use crate::decl::DeclId;
use crate::stmt::StmtId;
use crate::tast::{ConstId, LabelId, StrId};
pub type ExprId = Idx<Expr>;
#[derive(Debug)]
pub struct ExprRef;
pub type ExprList = IdxRange<ExprRef>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Expr {
pub kind: ExprKind,
pub ty: TypeId,
pub category: Category,
}
impl Expr {
#[must_use]
pub const fn new(kind: ExprKind, ty: TypeId, category: Category) -> Expr {
Expr { kind, ty, category }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Category {
Rvalue,
Lvalue,
Bitfield,
Function,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExprKind {
Error,
Const(ConstId),
Str(StrId),
Decl(DeclId),
Member {
base: ExprId,
field: u32,
},
Subscript {
base: ExprId,
index: ExprId,
},
Call {
callee: ExprId,
args: ExprList,
},
Unary {
op: UnaryOp,
operand: ExprId,
},
Binary {
op: BinaryOp,
lhs: ExprId,
rhs: ExprId,
},
Assign {
op: Option<BinaryOp>,
computation: TypeId,
lhs: ExprId,
rhs: ExprId,
},
Cond {
cond: ExprId,
then: ExprId,
otherwise: ExprId,
},
Comma {
lhs: ExprId,
rhs: ExprId,
},
Cast(ExprId),
Convert {
kind: Conversion,
operand: ExprId,
},
CompoundLiteral(DeclId),
StmtExpr(StmtId),
LabelAddr(LabelId),
VaArg {
list: ExprId,
},
VaStart {
list: ExprId,
},
VaEnd {
list: ExprId,
},
VaCopy {
dst: ExprId,
src: ExprId,
},
Classify {
op: Classify,
lhs: ExprId,
rhs: Option<ExprId>,
},
FpClassify {
value: ExprId,
answers: ExprList,
},
Sign {
op: Sign,
lhs: ExprId,
rhs: Option<ExprId>,
},
Abs {
operand: ExprId,
},
ByteSwap {
operand: ExprId,
},
BitCount {
operand: ExprId,
count: BitCount,
},
Overflow {
op: OverflowOp,
at: TypeId,
args: ExprList,
},
Atomic {
op: AtomicOp,
order: Ordering,
args: ExprList,
},
Unreachable,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BitCount {
Leading,
Trailing,
Ones,
Parity,
FirstSet,
}
impl BitCount {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
BitCount::Leading => "leading-zeroes",
BitCount::Trailing => "trailing-zeroes",
BitCount::Ones => "set-bits",
BitCount::Parity => "parity",
BitCount::FirstSet => "first-set",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OverflowOp {
Add,
Sub,
Mul,
}
impl OverflowOp {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
OverflowOp::Add => "add",
OverflowOp::Sub => "sub",
OverflowOp::Mul => "mul",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AtomicOp {
Load,
Store,
Fence,
}
impl AtomicOp {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
AtomicOp::Load => "load",
AtomicOp::Store => "store",
AtomicOp::Fence => "fence",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Ordering {
Relaxed,
Acquire,
Release,
AcqRel,
SeqCst,
}
impl Ordering {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Ordering::Relaxed => "relaxed",
Ordering::Acquire => "acquire",
Ordering::Release => "release",
Ordering::AcqRel => "acq_rel",
Ordering::SeqCst => "seq_cst",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Classify {
Unordered,
LessGreater,
Nan,
Infinite,
Finite,
Normal,
SignBit,
InfiniteSign,
}
impl Classify {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Classify::Unordered => "unordered",
Classify::LessGreater => "less-greater",
Classify::Nan => "nan",
Classify::Infinite => "infinite",
Classify::Finite => "finite",
Classify::Normal => "normal",
Classify::SignBit => "signbit",
Classify::InfiniteSign => "infinite-sign",
}
}
#[must_use]
pub const fn is_pair(self) -> bool {
matches!(self, Classify::Unordered | Classify::LessGreater)
}
#[must_use]
pub const fn answers_a_bit(self) -> bool {
!matches!(self, Classify::InfiniteSign)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Sign {
Clear,
Of,
}
impl Sign {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Sign::Clear => "clear",
Sign::Of => "of",
}
}
#[must_use]
pub const fn is_pair(self) -> bool {
matches!(self, Sign::Of)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Conversion {
Lvalue,
ArrayDecay,
FunctionDecay,
Arithmetic,
Pointer,
Bool,
NullPointer,
Void,
Broadcast,
}
impl Conversion {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Conversion::Lvalue => "lvalue",
Conversion::ArrayDecay => "array-decay",
Conversion::FunctionDecay => "function-decay",
Conversion::Arithmetic => "arithmetic",
Conversion::Pointer => "pointer",
Conversion::Bool => "bool",
Conversion::NullPointer => "null-pointer",
Conversion::Void => "void",
Conversion::Broadcast => "broadcast",
}
}
}