use crate::parser::{Error, Result};
use std::fmt;
#[derive(Clone, Debug, PartialEq)]
pub enum Expr {
Boolean(bool),
Double(f64),
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>),
Modulo(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>),
Call(VarRef, Vec<Expr>),
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum VarType {
Auto,
Boolean,
Double,
Integer,
Text,
Void,
}
impl VarType {
pub fn annotation(&self) -> &'static str {
match self {
VarType::Auto => "",
VarType::Boolean => "?",
VarType::Double => "#",
VarType::Integer => "%",
VarType::Text => "$",
VarType::Void => "",
}
}
}
#[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) -> Result<String> {
if self.ref_type != VarType::Auto {
return Err(Error::Bad(format!("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::Double, Value::Double(_)) => 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 {
write!(f, "{}{}", self.name, self.ref_type().annotation())
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum Value {
Boolean(bool),
Double(f64),
Integer(i32),
Text(String), }
#[derive(Debug, Eq, PartialEq)]
pub enum ArgSep {
End,
Short,
Long,
}
#[derive(Debug, PartialEq)]
pub enum Statement {
Assignment(VarRef, Expr),
BuiltinCall(String, Vec<(Option<Expr>, ArgSep)>),
If(Vec<(Expr, Vec<Statement>)>),
For(VarRef, Expr, Expr, Expr, Vec<Statement>),
While(Expr, Vec<Statement>),
}