use crate::facet::Facets;
use crate::node::member::EnumeratorNode;
use crate::node::module::ModuleNode;
use crate::node::type_::TypeNode;
use alloc::string::String;
use alloc::vec::Vec;
use core::fmt;
use zerodds_ast_core::{Id, NodeId, Ref};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ConstNode {
pub node_id: NodeId,
pub name: String,
pub module: Id<ModuleNode>,
pub scope: Option<String>,
pub type_: Ref<TypeNode>,
pub expr: Id<ConstExprNode>,
pub facets: Facets,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Literal {
Boolean(bool),
Integer(i128),
Float {
mantissa: String,
exponent: Option<String>,
},
Fixed {
digits: String,
scale: u8,
},
Char(char),
WChar(u32),
String(String),
WString(Vec<u32>),
Enumerator(Ref<EnumeratorNode>),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum UnaryOp {
Plus,
Minus,
Not,
}
impl UnaryOp {
pub const ALL: [Self; 3] = [Self::Plus, Self::Minus, Self::Not];
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Plus => "+",
Self::Minus => "-",
Self::Not => "~",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BinaryOp {
Or,
Xor,
And,
Shl,
Shr,
Add,
Sub,
Mul,
Div,
Mod,
}
impl BinaryOp {
pub const ALL: [Self; 10] = [
Self::Or,
Self::Xor,
Self::And,
Self::Shl,
Self::Shr,
Self::Add,
Self::Sub,
Self::Mul,
Self::Div,
Self::Mod,
];
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Or => "|",
Self::Xor => "^",
Self::And => "&",
Self::Shl => "<<",
Self::Shr => ">>",
Self::Add => "+",
Self::Sub => "-",
Self::Mul => "*",
Self::Div => "/",
Self::Mod => "%",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ConstExpr {
Literal(Literal),
NameRef(Ref<ConstNode>),
Unary {
op: UnaryOp,
operand: Id<ConstExprNode>,
},
Binary {
op: BinaryOp,
lhs: Id<ConstExprNode>,
rhs: Id<ConstExprNode>,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ConstExprNode {
pub node_id: NodeId,
pub expr: ConstExpr,
pub facets: Facets,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum EvalError {
Unresolved {
at: NodeId,
},
DanglingExpr,
DivisionByZero {
at: NodeId,
},
Overflow {
at: NodeId,
},
InvalidShift {
at: NodeId,
},
NotIntegral {
at: NodeId,
},
TooDeep,
MixedOperands {
at: NodeId,
},
NotFloatingOperator {
at: NodeId,
},
NotFixedOperator {
at: NodeId,
},
LongDouble {
at: NodeId,
},
}
impl fmt::Display for EvalError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Unresolved { at } => write!(f, "expression {at:?} reaches an unresolved name"),
Self::DanglingExpr => write!(f, "expression tree contains a dangling handle"),
Self::DivisionByZero { at } => write!(f, "division by zero in expression {at:?}"),
Self::Overflow { at } => write!(f, "arithmetic overflow in expression {at:?}"),
Self::InvalidShift { at } => write!(f, "invalid shift distance in expression {at:?}"),
Self::NotIntegral { at } => write!(f, "expression {at:?} is not integral"),
Self::TooDeep => write!(f, "expression nests too deeply to evaluate"),
Self::MixedOperands { at } => write!(
f,
"expression {at:?} combines a floating-point operand with one that is not"
),
Self::NotFloatingOperator { at } => write!(
f,
"expression {at:?} applies an operator floating-point values do not take"
),
Self::NotFixedOperator { at } => write!(
f,
"expression {at:?} applies an operator fixed-point values do not take"
),
Self::LongDouble { at } => write!(
f,
"expression {at:?} needs long double arithmetic, which this build does not have"
),
}
}
}
impl core::error::Error for EvalError {}
pub const MAX_EXPR_DEPTH: usize = 256;
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum ConstValue {
Boolean(bool),
Integer(i128),
Float {
mantissa: String,
exponent: Option<String>,
},
Fixed {
digits: String,
scale: u8,
},
Char(char),
WChar(u32),
String(String),
WString(Vec<u32>),
}