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,
LoadInto,
Store,
Fence,
CompareExchange,
SwapBool,
SwapValue,
Exchange,
ExchangeInto,
TestAndSet,
Fetch(Rmw),
Update(Rmw),
}
impl AtomicOp {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
AtomicOp::Load => "load",
AtomicOp::LoadInto => "load_into",
AtomicOp::Store => "store",
AtomicOp::Fence => "fence",
AtomicOp::CompareExchange => "compare_exchange",
AtomicOp::SwapBool => "swap_bool",
AtomicOp::SwapValue => "swap_value",
AtomicOp::Exchange => "exchange",
AtomicOp::ExchangeInto => "exchange_into",
AtomicOp::TestAndSet => "test_and_set",
AtomicOp::Fetch(Rmw::Add) => "fetch_add",
AtomicOp::Fetch(Rmw::Sub) => "fetch_sub",
AtomicOp::Fetch(Rmw::And) => "fetch_and",
AtomicOp::Fetch(Rmw::Nand) => "fetch_nand",
AtomicOp::Fetch(Rmw::Or) => "fetch_or",
AtomicOp::Fetch(Rmw::Xor) => "fetch_xor",
AtomicOp::Update(Rmw::Add) => "add_fetch",
AtomicOp::Update(Rmw::Sub) => "sub_fetch",
AtomicOp::Update(Rmw::And) => "and_fetch",
AtomicOp::Update(Rmw::Nand) => "nand_fetch",
AtomicOp::Update(Rmw::Or) => "or_fetch",
AtomicOp::Update(Rmw::Xor) => "xor_fetch",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Rmw {
Add,
Sub,
And,
Nand,
Or,
Xor,
}
#[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",
}
}
}