use std::fmt;
use super::expression::{BExpression, Expression};
use super::return_value::{LabelSetOp, ReturnKind, ReturnValue};
use super::misc::Span;
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum OperatorKind {
Power,
Multiply, Divide, Modulo,
Add, Subtract,
Equal, NotEqual,
LessThan, LessThanEqual,
GreaterThan, GreaterThanEqual,
And, Unless, Or
}
impl OperatorKind {
pub fn as_str(self) -> &'static str {
use OperatorKind::*;
match self {
Power => "^",
Multiply => "*",
Divide => "/",
Modulo => "%",
Add => "+",
Subtract => "-",
Equal => "==",
NotEqual => "!=",
LessThan => "<",
LessThanEqual => "<=",
GreaterThan => ">",
GreaterThanEqual => ">=",
And => "and",
Unless => "unless",
Or => "or"
}
}
}
impl fmt::Display for OperatorKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum MatchingGroupOp {
Left,
Right
}
impl fmt::Display for MatchingGroupOp {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
MatchingGroupOp::Left => write!(f, "group_left"),
MatchingGroupOp::Right => write!(f, "group_right")
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct MatchingGroup {
pub op: MatchingGroupOp,
pub labels: Vec<String>,
pub span: Option<Span>
}
impl MatchingGroup {
pub fn new(op: MatchingGroupOp) -> Self {
MatchingGroup {
op,
labels: vec![],
span: None
}
}
pub fn left() -> Self {
MatchingGroup::new(MatchingGroupOp::Left)
}
pub fn right() -> Self {
MatchingGroup::new(MatchingGroupOp::Right)
}
pub fn op(mut self, op: MatchingGroupOp) -> Self {
self.op = op;
self
}
pub fn label<S: Into<String>>(mut self, label: S) -> Self {
self.labels.push(label.into());
self
}
pub fn labels(mut self, labels: &[&str]) -> Self {
self.labels = labels.iter().map(|l| (*l).to_string()).collect();
self
}
pub fn clear_labels(mut self) -> Self {
self.labels.clear();
self
}
pub fn span<S: Into<Span>>(mut self, span: S) -> Self {
self.span = Some(span.into());
self
}
}
impl fmt::Display for MatchingGroup {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.op)?;
if !self.labels.is_empty() {
write!(f, "(")?;
for (i, label) in self.labels.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", label)?;
}
write!(f, ")")?;
}
Ok(())
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum MatchingOp {
On,
Ignoring
}
impl fmt::Display for MatchingOp {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
MatchingOp::On => write!(f, "on"),
MatchingOp::Ignoring => write!(f, "ignoring")
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Matching {
pub op: MatchingOp,
pub labels: Vec<String>,
pub group: Option<MatchingGroup>,
pub span: Option<Span>
}
impl Matching {
pub fn new(op: MatchingOp) -> Self {
Matching {
op,
labels: vec![],
group: None,
span: None
}
}
pub fn on() -> Self {
Matching::new(MatchingOp::On)
}
pub fn ignoring() -> Self {
Matching::new(MatchingOp::Ignoring)
}
pub fn op(mut self, op: MatchingOp) -> Self {
self.op = op;
self
}
pub fn label<S: Into<String>>(mut self, label: S) -> Self {
self.labels.push(label.into());
self
}
pub fn labels(mut self, labels: &[&str]) -> Self {
self.labels = labels.iter().map(|l| (*l).to_string()).collect();
self
}
pub fn clear_labels(mut self) -> Self {
self.labels.clear();
self
}
pub fn group(mut self, group: MatchingGroup) -> Self {
self.group = Some(group);
self
}
pub fn clear_group(mut self) -> Self {
self.group = None;
self
}
pub fn span<S: Into<Span>>(mut self, span: S) -> Self {
self.span = Some(span.into());
self
}
}
impl fmt::Display for Matching {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}(", self.op)?;
for (i, label) in self.labels.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", label)?;
}
write!(f, ")")?;
if let Some(group) = &self.group {
write!(f, " {}", group)?;
}
Ok(())
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct Operator {
pub kind: OperatorKind,
pub lhs: BExpression,
pub rhs: BExpression,
pub matching: Option<Matching>,
pub span: Option<Span>
}
impl Operator {
pub fn new(kind: OperatorKind, lhs: Expression, rhs: Expression) -> Self {
Operator {
kind,
lhs: Box::new(lhs),
rhs: Box::new(rhs),
matching: None,
span: None
}
}
pub fn matching(mut self, matching: Matching) -> Self {
self.matching = Some(matching);
self
}
pub fn clear_matching(mut self) -> Self {
self.matching = None;
self
}
pub fn span<S: Into<Span>>(mut self, span: S) -> Self {
self.span = Some(span.into());
self
}
pub fn wrap(self) -> Expression {
Expression::Operator(self)
}
pub fn return_value(&self) -> ReturnValue {
let lhs_ret = self.lhs.return_value();
let rhs_ret = self.rhs.return_value();
if !lhs_ret.kind.is_operator_valid() {
return ReturnValue::unknown(
format!("lhs return type ({:?}) is not valid in an operator", &lhs_ret.kind),
self.clone().wrap()
);
}
if !rhs_ret.kind.is_operator_valid() {
return ReturnValue::unknown(
format!("rhs return type ({:?}) is not valid in an operator", &rhs_ret.kind),
self.clone().wrap()
);
}
let kind;
let mut label_ops;
if lhs_ret.kind.is_scalar() && rhs_ret.kind.is_scalar() {
kind = ReturnKind::Scalar;
label_ops = vec![LabelSetOp::clear(self.clone().wrap(), self.span)];
} else if lhs_ret.kind.is_scalar() {
kind = ReturnKind::InstantVector;
label_ops = rhs_ret.label_ops;
} else if rhs_ret.kind.is_scalar() {
kind = ReturnKind::InstantVector;
label_ops = lhs_ret.label_ops;
} else {
kind = ReturnKind::InstantVector;
if let Some(matching) = &self.matching {
if let Some(group) = &matching.group {
match &group.op {
MatchingGroupOp::Left => label_ops = lhs_ret.label_ops,
MatchingGroupOp::Right => label_ops = rhs_ret.label_ops
};
label_ops.push(LabelSetOp::append(
self.clone().wrap(),
group.span,
group.labels.iter().cloned().collect(),
));
} else {
label_ops = lhs_ret.label_ops;
}
} else {
label_ops = lhs_ret.label_ops;
}
};
ReturnValue { kind, label_ops }
}
}
impl fmt::Display for Operator {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {}", self.lhs, self.kind)?;
if let Some(matching) = &self.matching {
write!(f, " {}", matching)?;
}
write!(f, " {}", self.rhs)?;
Ok(())
}
}