use std::borrow::{Borrow, Cow};
use derive_more::{Deref, Display, IsVariant, Unwrap};
use enum_as_inner::EnumAsInner;
use super::value::Value;
#[derive(Clone, Debug, IsVariant, PartialEq)]
pub enum Expr {
Literal(Literal),
Ref(Ident),
#[cfg(glam)]
Vector(Vec<Expr>),
Call(Box<Expr>, Vec<Expr>),
Subscript(Box<Expr>, Box<Expr>),
Access(Box<Expr>, Ident),
Unary(UnaryOp, Box<Expr>),
Binary(BinaryOp, Box<Expr>, Box<Expr>),
}
#[cfg(serde)]
impl<'de> serde::Deserialize<'de> for Expr {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: serde::Deserializer<'de>
{
<String as serde::Deserialize>::deserialize(deserializer)
.and_then(|expr| crate::parse(expr).map_err(serde::de::Error::custom))
}
}
impl Expr {
pub fn literal(lit: impl Into<Literal>) -> Self {
Self::Literal(lit.into())
}
pub fn ref_(ident: impl Into<Ident>) -> Self {
Self::Ref(ident.into())
}
#[cfg(glam)]
pub fn vector(items: impl IntoIterator<Item=Expr>) -> Self {
Self::Vector(items.into_iter().collect())
}
pub fn call(callable: Expr, args: impl IntoIterator<Item=Expr>) -> Self {
Self::Call(Box::new(callable), args.into_iter().collect())
}
pub fn subscript(value: Expr, index: Expr) -> Self {
Self::Subscript(Box::new(value), Box::new(index))
}
pub fn access(value: Expr, member: impl Into<Ident>) -> Self {
Self::Access(Box::new(value), member.into())
}
pub fn unary(op: UnaryOp, arg: Expr) -> Self {
Self::Unary(op, Box::new(arg))
}
pub fn binary(op: BinaryOp, lhs: Expr, rhs: Expr) -> Self {
Self::Binary(op, Box::new(lhs), Box::new(rhs))
}
}
#[cfg(serde)]
impl serde::Serialize for Expr {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: serde::Serializer
{
use crate::parser::Handler;
fn dump(fmt: &mut crate::parser::FormatHandler, expr: &Expr) -> String {
match expr {
Expr::Literal(lit) => match lit {
Literal::Bool(b) => fmt.bool(&b.to_string()),
Literal::Integer(i) => fmt.int(&i.to_string()),
Literal::Float(f) => fmt.float(&f.to_string()),
Literal::Symbol(s) => fmt.symbol(s),
},
Expr::Ref(ident) => fmt.ident(ident.as_str()),
#[cfg(glam)] Expr::Vector(v) => {
let items: Vec<_> = v.iter().map(|item| dump(fmt, item)).collect();
fmt.vector(items)
},
Expr::Call(target, args) => {
let target = dump(fmt, target);
let args: Vec<_> = args.iter().map(|item| dump(fmt, item)).collect();
fmt.call(target, args)
},
Expr::Subscript(target, index) => {
let target = dump(fmt, target);
let index = dump(fmt, index);
fmt.subscript(target, index)
},
Expr::Access(target, member) => {
let target = dump(fmt, target);
fmt.access(target, member.as_str())
},
Expr::Unary(op, arg) => {
let arg = dump(fmt, arg);
fmt.unary_expr(*op, arg)
},
Expr::Binary(op, lhs, rhs) => {
let lhs = dump(fmt, lhs);
let rhs = dump(fmt, rhs);
format!("({})", fmt.binary_expr(lhs, *op, rhs))
},
}
}
let mut formatter = crate::parser::FormatHandler::default();
let expr = dump(&mut formatter, self);
serializer.serialize_str(&expr)
}
}
#[derive(Clone, Debug, EnumAsInner, PartialEq, Unwrap)]
pub enum Literal {
Bool(bool),
Integer(i64),
Float(f32),
Symbol(String),
}
impl Literal {
pub fn symbol(s: impl Into<String>) -> Self {
Self::Symbol(s.into())
}
}
macro_rules! impl_Literal_from {
($ty:ty => $variant:ident) => {
impl From<$ty> for Literal {
fn from(v: $ty) -> Self {
Self::$variant(v)
}
}
}
}
impl_Literal_from!(bool => Bool);
impl_Literal_from!(i64 => Integer);
impl_Literal_from!(f32 => Float);
impl From<&Literal> for Value {
fn from(literal: &Literal) -> Self {
match literal {
Literal::Bool(b) => Value::Bool(*b),
Literal::Integer(i) => Value::Integer(*i),
Literal::Float(f) => Value::Float(*f),
Literal::Symbol(s) => Value::symbol(s),
}
}
}
impl From<Literal> for Value {
fn from(literal: Literal) -> Self {
match literal {
Literal::Symbol(s) => Value::symbol(s),
lit => Value::from(&lit),
}
}
}
#[derive(Clone, Debug, Default, Deref, Display, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Ident(Cow<'static, str>);
impl From<&'static str> for Ident {
fn from(s: &'static str) -> Self {
Ident(Cow::Borrowed(s))
}
}
impl From<String> for Ident {
fn from(s: String) -> Self {
Ident(Cow::Owned(s))
}
}
impl Ident {
pub fn as_str(&self) -> &str {
&self.0
}
}
impl AsRef<str> for Ident {
fn as_ref(&self) -> &str {
self.0.as_ref()
}
}
impl Borrow<str> for Ident {
fn borrow(&self) -> &str {
self.as_ref()
}
}
#[derive(Clone, Copy, Debug, Display, Eq, Hash, IsVariant, PartialEq)]
pub enum UnaryOp {
#[display(fmt = "-")]
Neg,
#[display(fmt = "!")]
Not,
}
#[derive(Clone, Copy, Debug, Display, Eq, Hash, IsVariant, PartialEq)]
pub enum BinaryOp {
#[display(fmt = "+")]
Add,
#[display(fmt = "-")]
Sub,
#[display(fmt = "*")]
Mul,
#[display(fmt = "/")]
Div,
#[display(fmt = "^")]
Pow,
#[display(fmt = "==")]
Eq,
#[display(fmt = "!=")]
NotEq,
#[display(fmt = "<")]
Less,
#[display(fmt = "<=")]
LessOrEq,
#[display(fmt = ">")]
Greater,
#[display(fmt = ">=")]
GreaterOrEq,
#[display(fmt = "&&")]
And,
#[display(fmt = "||")]
Or,
}