use failure::Fallible;
use std::fmt;
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Expr {
Boolean(bool),
Integer(i32),
Symbol(VarRef),
Text(String),
Add(Box<Expr>, Box<Expr>),
Subtract(Box<Expr>, Box<Expr>),
Multiply(Box<Expr>, Box<Expr>),
Divide(Box<Expr>, Box<Expr>),
Negate(Box<Expr>),
Equal(Box<Expr>, Box<Expr>),
NotEqual(Box<Expr>, Box<Expr>),
Less(Box<Expr>, Box<Expr>),
LessEqual(Box<Expr>, Box<Expr>),
Greater(Box<Expr>, Box<Expr>),
GreaterEqual(Box<Expr>, Box<Expr>),
And(Box<Expr>, Box<Expr>),
Not(Box<Expr>),
Or(Box<Expr>, Box<Expr>),
Xor(Box<Expr>, Box<Expr>),
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum VarType {
Auto,
Boolean,
Integer,
Text,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct VarRef {
name: String,
ref_type: VarType,
}
impl VarRef {
#[allow(clippy::redundant_field_names)]
pub fn new<T: Into<String>>(name: T, ref_type: VarType) -> Self {
Self {
name: name.into(),
ref_type: ref_type,
}
}
pub fn into_unannotated_string(self) -> Fallible<String> {
ensure!(
self.ref_type == VarType::Auto,
"Type annotation not allowed in {}",
self
);
Ok(self.name)
}
pub fn name(&self) -> &str {
&self.name
}
pub fn ref_type(&self) -> VarType {
self.ref_type
}
pub fn accepts(&self, value: &Value) -> bool {
match (self.ref_type, value) {
(VarType::Auto, _) => true,
(VarType::Boolean, Value::Boolean(_)) => true,
(VarType::Integer, Value::Integer(_)) => true,
(VarType::Text, Value::Text(_)) => true,
(_, _) => false,
}
}
}
impl fmt::Display for VarRef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.ref_type {
VarType::Auto => write!(f, "{}", self.name),
VarType::Boolean => write!(f, "{}?", self.name),
VarType::Integer => write!(f, "{}%", self.name),
VarType::Text => write!(f, "{}$", self.name),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum Value {
Boolean(bool),
Integer(i32),
Text(String), }
#[derive(Debug, Eq, PartialEq)]
pub enum ArgSep {
End,
Short,
Long,
}
#[derive(Debug, Eq, PartialEq)]
pub enum Statement {
Assignment(VarRef, Expr),
BuiltinCall(String, Vec<(Option<Expr>, ArgSep)>),
If(Vec<(Expr, Vec<Statement>)>),
While(Expr, Vec<Statement>),
}