use serde::Deserialize;
use crate::result::{diagnostic::Location, CompilerResult};
#[derive(Clone, PartialEq, Debug)]
pub struct Test {
pub test_body: TestBody,
pub aborts: Vec<Abort>,
}
#[derive(Clone, PartialEq, Debug)]
pub struct TestBody {
pub statements: Vec<Statement>,
}
#[derive(Clone, PartialEq, Debug)]
pub struct Abort {
pub name: String,
pub statements: Vec<Statement>,
}
#[derive(Clone, PartialEq, Debug, Default)]
pub struct Timing {
pub minutes: Option<u128>,
pub seconds: Option<u128>,
pub milliseconds: Option<u128>,
}
#[derive(Clone, PartialEq, Debug)]
pub enum Statement {
Section(SectionStatement),
Relay(RelayStatement),
Sensor(SensorStatement),
}
#[derive(Clone, PartialEq, Debug)]
pub struct SectionStatement {
pub name: String,
pub time: SectionTime,
pub statements: Vec<Statement>,
pub metadata: Location,
}
#[derive(Clone, PartialEq, Debug)]
pub struct SectionTime {
pub start: u128,
pub duration: u128,
}
#[derive(Clone, PartialEq, Debug)]
pub struct RelayStatement {
pub time: u128,
pub id: String,
pub op: RelayOp,
pub metadata: Location,
}
#[derive(Clone, PartialEq, Debug)]
pub enum RelayOp {
Set,
Unset,
}
#[derive(Clone, PartialEq, Debug)]
pub struct SensorStatement {
pub time: SensorTime,
pub constraints: Vec<SensorConstraint>,
pub abort: String,
pub metadata: Location,
}
#[derive(Clone, PartialEq, Debug)]
pub enum SensorTime {
Instant { time: u128 },
Interval { start: u128, end: u128 },
}
#[derive(Clone, PartialEq, Debug)]
pub struct SensorConstraint {
pub id: String,
pub sensor_bound: SensorBound,
pub abort: String,
pub metadata: Location,
}
#[derive(Clone, PartialEq, Debug, Deserialize)]
pub enum SensorBound {
Boolean(bool),
Numeric(SensorBoundNumeric),
}
#[derive(Clone, PartialEq, Debug, Deserialize)]
pub struct SensorBoundNumeric {
pub left: f64,
pub right: f64,
pub unit: String,
}
impl Abort {
pub const HARD_ABORT: &'static str = "HARD_ABORT";
}
#[derive(Clone, PartialEq, Debug)]
pub struct Metadata {
pub contents: String,
pub line: u16,
}
impl Metadata {
pub fn to_error_msg(&self, error_msg: &str) -> String {
return format!(
"\tLine: {}\n\t{}\n\n\t{}",
self.line, self.contents, error_msg
);
}
}
impl Timing {
pub fn to_ms(&self) -> u128 {
((self.minutes.unwrap_or_default() * 60) + self.seconds.unwrap_or_default()) * 1000
+ self.milliseconds.unwrap_or_default()
}
pub fn can_be_simplified(&self) -> bool {
self.seconds.unwrap_or_default() >= 60 || self.milliseconds.unwrap_or_default() >= 1000
}
}
impl Statement {
fn to_absolute(&self, offset: u128) -> CompilerResult<Vec<Statement>> {
let mut res = CompilerResult::new("Convert statement to absolute time");
let mut absolute_statements: Vec<Statement> = Vec::new();
match self {
Statement::Section(statement) => {
let statements_abs: Vec<Statement> = check!(res, statement.to_absolute());
for statement_abs in statements_abs {
let mut statement_abs =
check!(res, Statement::to_absolute(&statement_abs, offset));
absolute_statements.append(&mut statement_abs);
}
}
Statement::Sensor(statement) => {
let statement_abs = check!(res, SensorStatement::to_absolute(statement, offset));
absolute_statements.push(statement_abs);
}
Statement::Relay(statement) => {
let statement_abs = check!(res, RelayStatement::to_absolute(statement, offset));
absolute_statements.push(statement_abs);
}
}
res.with_value(absolute_statements)
}
}
impl RelayStatement {
fn to_absolute(&self, offset: u128) -> CompilerResult<Statement> {
let res = CompilerResult::new("Convert relay statement to absolute time");
let mut relay_statement = self.clone();
relay_statement.time += offset;
res.with_value(Statement::Relay(relay_statement))
}
}
impl SensorStatement {
fn to_absolute(&self, offset: u128) -> CompilerResult<Statement> {
let res = CompilerResult::new("Convert sensor statement to absolute time");
let mut sensor_statement = self.clone();
match sensor_statement.time {
SensorTime::Instant { time } => {
let absolute_time = time + offset;
sensor_statement.time = SensorTime::Instant {
time: absolute_time,
};
}
SensorTime::Interval { start, end } => {
let absolute_start = start + offset;
let absolute_end = end + offset;
sensor_statement.time = SensorTime::Interval {
start: absolute_start,
end: absolute_end,
};
}
}
res.with_value(Statement::Sensor(sensor_statement))
}
}
impl SensorTime {
pub fn get_start(&self) -> u128 {
match self {
SensorTime::Instant { time } => *time as u128,
SensorTime::Interval { start, end: _ } => *start as u128,
}
}
pub fn get_end(&self) -> u128 {
match self {
SensorTime::Instant { time } => *time as u128,
SensorTime::Interval { start: _, end } => *end as u128,
}
}
}
impl SectionStatement {
pub fn check_statements_within_bounds(&self) -> CompilerResult<()> {
let mut res = CompilerResult::status_only(
"Check all statements stay within start/end bounds of the section",
);
for statement in &self.statements {
let end = self.time.duration;
match statement {
Statement::Section(statement) => {
res.require(statement.check_statements_within_bounds());
let statement_end = statement.time.start + statement.time.duration;
if end < statement_end {
res.error((statement.metadata, "This section statement extends past the end of the section it is within!"));
}
}
Statement::Sensor(statement) => {
let statement_end = match statement.time {
SensorTime::Instant { time } => time,
SensorTime::Interval { start: _, end } => end,
};
if end < statement_end {
res.error((statement.metadata, "This sensor statement extends past the end of the section it is within!"));
}
}
Statement::Relay(statement) => {
let statement_end = statement.time;
if end < statement_end {
res.error((statement.metadata, "This relay statement extends past the end of the section it is within!"));
}
}
}
}
res
}
pub fn to_absolute(&self) -> CompilerResult<Vec<Statement>> {
let mut res = CompilerResult::new("Retrieve statements from section with absolute time");
let mut absolute_statements: Vec<Statement> = Vec::new();
for statement in &self.statements {
absolute_statements.append(&mut check!(
res,
Statement::to_absolute(statement, self.time.start)
));
}
res.with_value(absolute_statements)
}
}