use num_bigint::BigInt;
use std::fmt;
use crate::file_definition::{FileID, FileLocation};
use crate::nonempty_vec::NonEmptyVec;
use super::degree_meta::DegreeKnowledge;
use super::type_meta::TypeKnowledge;
use super::value_meta::ValueKnowledge;
use super::variable_meta::VariableKnowledge;
type Index = usize;
type Version = usize;
#[derive(Clone, Default)]
pub struct Meta {
pub location: FileLocation,
pub file_id: Option<FileID>,
degree_knowledge: DegreeKnowledge,
type_knowledge: TypeKnowledge,
value_knowledge: ValueKnowledge,
variable_knowledge: VariableKnowledge,
}
impl Meta {
#[must_use]
pub fn new(location: &FileLocation, file_id: &Option<FileID>) -> Meta {
Meta {
location: location.clone(),
file_id: *file_id,
degree_knowledge: DegreeKnowledge::default(),
type_knowledge: TypeKnowledge::default(),
value_knowledge: ValueKnowledge::default(),
variable_knowledge: VariableKnowledge::default(),
}
}
#[must_use]
pub fn start(&self) -> usize {
self.location.start
}
#[must_use]
pub fn end(&self) -> usize {
self.location.end
}
#[must_use]
pub fn file_id(&self) -> Option<FileID> {
self.file_id
}
#[must_use]
pub fn file_location(&self) -> FileLocation {
self.location.clone()
}
#[must_use]
pub fn degree_knowledge(&self) -> &DegreeKnowledge {
&self.degree_knowledge
}
#[must_use]
pub fn type_knowledge(&self) -> &TypeKnowledge {
&self.type_knowledge
}
#[must_use]
pub fn value_knowledge(&self) -> &ValueKnowledge {
&self.value_knowledge
}
#[must_use]
pub fn variable_knowledge(&self) -> &VariableKnowledge {
&self.variable_knowledge
}
#[must_use]
pub fn degree_knowledge_mut(&mut self) -> &mut DegreeKnowledge {
&mut self.degree_knowledge
}
#[must_use]
pub fn type_knowledge_mut(&mut self) -> &mut TypeKnowledge {
&mut self.type_knowledge
}
#[must_use]
pub fn value_knowledge_mut(&mut self) -> &mut ValueKnowledge {
&mut self.value_knowledge
}
#[must_use]
pub fn variable_knowledge_mut(&mut self) -> &mut VariableKnowledge {
&mut self.variable_knowledge
}
}
impl std::hash::Hash for Meta {
fn hash<H>(&self, state: &mut H)
where
H: std::hash::Hasher,
{
self.location.hash(state);
self.file_id.hash(state);
state.finish();
}
}
impl PartialEq for Meta {
fn eq(&self, other: &Meta) -> bool {
self.location == other.location && self.file_id == other.file_id
}
}
impl Eq for Meta {}
#[derive(Clone)]
#[allow(clippy::large_enum_variant)]
pub enum Statement {
Declaration {
meta: Meta,
names: NonEmptyVec<VariableName>,
var_type: VariableType,
dimensions: Vec<Expression>,
},
IfThenElse {
meta: Meta,
cond: Expression,
true_index: Index,
false_index: Option<Index>,
},
Return {
meta: Meta,
value: Expression,
},
Substitution {
meta: Meta,
var: VariableName,
op: AssignOp,
rhe: Expression,
},
ConstraintEquality {
meta: Meta,
lhe: Expression,
rhe: Expression,
},
LogCall {
meta: Meta,
args: Vec<LogArgument>,
},
Assert {
meta: Meta,
arg: Expression,
},
}
#[derive(Clone)]
pub enum Expression {
InfixOp {
meta: Meta,
lhe: Box<Expression>,
infix_op: ExpressionInfixOpcode,
rhe: Box<Expression>,
},
PrefixOp { meta: Meta, prefix_op: ExpressionPrefixOpcode, rhe: Box<Expression> },
SwitchOp {
meta: Meta,
cond: Box<Expression>,
if_true: Box<Expression>,
if_false: Box<Expression>,
},
Variable { meta: Meta, name: VariableName },
Number(Meta, BigInt),
Call { meta: Meta, name: String, args: Vec<Expression> },
InlineArray { meta: Meta, values: Vec<Expression> },
Access { meta: Meta, var: VariableName, access: Vec<AccessType> },
Update { meta: Meta, var: VariableName, access: Vec<AccessType>, rhe: Box<Expression> },
Phi { meta: Meta, args: Vec<VariableName> },
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum VariableType {
Local,
Component,
Signal(SignalType),
}
impl fmt::Display for VariableType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
use SignalType::*;
use VariableType::*;
match self {
Local => write!(f, "var"),
Component => write!(f, "component"),
Signal(signal_type) => {
if matches!(signal_type, Intermediate) {
write!(f, "signal")
} else {
write!(f, "signal {signal_type}")
}
}
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub enum SignalType {
Input,
Output,
Intermediate,
}
impl fmt::Display for SignalType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
use SignalType::*;
match self {
Input => write!(f, "input"),
Output => write!(f, "output"),
Intermediate => Ok(()), }
}
}
#[derive(Clone, Hash, PartialEq, Eq)]
pub struct VariableName {
name: String,
suffix: Option<String>,
version: Option<Version>,
}
impl VariableName {
#[must_use]
pub fn from_name<N: ToString>(name: N) -> VariableName {
VariableName { name: name.to_string(), suffix: None, version: None }
}
#[must_use]
pub fn name(&self) -> &String {
&self.name
}
#[must_use]
pub fn suffix(&self) -> &Option<String> {
&self.suffix
}
#[must_use]
pub fn version(&self) -> &Option<Version> {
&self.version
}
#[must_use]
pub fn with_suffix<S: ToString>(&self, suffix: S) -> VariableName {
let mut result = self.clone();
result.suffix = Some(suffix.to_string());
result
}
#[must_use]
pub fn with_version(&self, version: Version) -> VariableName {
let mut result = self.clone();
result.version = Some(version);
result
}
#[must_use]
pub fn without_suffix(&self) -> VariableName {
let mut result = self.clone();
result.suffix = None;
result
}
#[must_use]
pub fn without_version(&self) -> VariableName {
let mut result = self.clone();
result.version = None;
result
}
}
impl fmt::Display for VariableName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
write!(f, "{}", self.name)
}
}
impl fmt::Debug for VariableName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
write!(f, "{}", self.name)?;
if let Some(suffix) = self.suffix() {
write!(f, "_{suffix}")?;
}
if let Some(version) = self.version() {
write!(f, ".{version}")?;
}
Ok(())
}
}
#[derive(Clone, Hash, Eq, PartialEq)]
pub enum AccessType {
ArrayAccess(Box<Expression>),
ComponentAccess(String),
}
#[derive(Copy, Clone, Hash, Eq, PartialEq)]
pub enum AssignOp {
AssignSignal,
AssignConstraintSignal,
AssignLocalOrComponent,
}
#[derive(Copy, Clone, Hash, Eq, PartialEq)]
pub enum ExpressionInfixOpcode {
Mul,
Div,
Add,
Sub,
Pow,
IntDiv,
Mod,
ShiftL,
ShiftR,
LesserEq,
GreaterEq,
Lesser,
Greater,
Eq,
NotEq,
BoolOr,
BoolAnd,
BitOr,
BitAnd,
BitXor,
}
#[derive(Copy, Clone, Hash, Eq, PartialEq)]
pub enum ExpressionPrefixOpcode {
Sub,
BoolNot,
Complement,
}
#[derive(Clone)]
pub enum LogArgument {
String(String),
Expr(Box<Expression>),
}