use super::Span;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Expr {
Literal(Literal),
Ident(String),
Binary {
left: Box<Expr>,
op: BinaryOp,
right: Box<Expr>,
#[serde(skip_serializing_if = "Option::is_none")]
span: Option<Span>,
},
Unary {
op: UnaryOp,
expr: Box<Expr>,
#[serde(skip_serializing_if = "Option::is_none")]
span: Option<Span>,
},
Call {
callee: Box<Expr>,
args: Vec<Expr>,
#[serde(skip_serializing_if = "Option::is_none")]
span: Option<Span>,
},
Member {
object: Box<Expr>,
property: Box<Expr>,
computed: bool,
#[serde(skip_serializing_if = "Option::is_none")]
span: Option<Span>,
},
Array(Vec<Expr>),
Object(Vec<(String, Expr)>),
Function(Box<crate::Function>),
Conditional {
test: Box<Expr>,
consequent: Box<Expr>,
alternate: Box<Expr>,
#[serde(skip_serializing_if = "Option::is_none")]
span: Option<Span>,
},
Assign {
target: Box<Expr>,
value: Box<Expr>,
#[serde(skip_serializing_if = "Option::is_none")]
span: Option<Span>,
},
TemplateLiteral(Vec<TemplatePart>),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum TemplatePart {
Text(String),
Expr(Box<Expr>),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Literal {
Null,
Bool(bool),
Number(f64),
String(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum BinaryOp {
Add,
Sub,
Mul,
Div,
Mod,
Eq,
Ne,
Lt,
Le,
Gt,
Ge,
And,
Or,
Concat,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum UnaryOp {
Neg,
Not,
}
impl Expr {
pub fn null() -> Self {
Expr::Literal(Literal::Null)
}
pub fn bool(v: bool) -> Self {
Expr::Literal(Literal::Bool(v))
}
pub fn number(v: impl Into<f64>) -> Self {
Expr::Literal(Literal::Number(v.into()))
}
pub fn string(v: impl Into<String>) -> Self {
Expr::Literal(Literal::String(v.into()))
}
pub fn ident(name: impl Into<String>) -> Self {
Expr::Ident(name.into())
}
pub fn binary(left: Expr, op: BinaryOp, right: Expr) -> Self {
Expr::Binary {
left: Box::new(left),
op,
right: Box::new(right),
span: None,
}
}
pub fn unary(op: UnaryOp, expr: Expr) -> Self {
Expr::Unary {
op,
expr: Box::new(expr),
span: None,
}
}
pub fn call(callee: Expr, args: Vec<Expr>) -> Self {
Expr::Call {
callee: Box::new(callee),
args,
span: None,
}
}
pub fn member(object: Expr, property: impl Into<String>) -> Self {
Expr::Member {
object: Box::new(object),
property: Box::new(Expr::string(property)),
computed: false,
span: None,
}
}
pub fn index(object: Expr, index: Expr) -> Self {
Expr::Member {
object: Box::new(object),
property: Box::new(index),
computed: true,
span: None,
}
}
pub fn array(items: Vec<Expr>) -> Self {
Expr::Array(items)
}
pub fn object(pairs: Vec<(String, Expr)>) -> Self {
Expr::Object(pairs)
}
pub fn conditional(test: Expr, consequent: Expr, alternate: Expr) -> Self {
Expr::Conditional {
test: Box::new(test),
consequent: Box::new(consequent),
alternate: Box::new(alternate),
span: None,
}
}
pub fn assign(target: Expr, value: Expr) -> Self {
Expr::Assign {
target: Box::new(target),
value: Box::new(value),
span: None,
}
}
pub fn template_literal(parts: Vec<TemplatePart>) -> Self {
Expr::TemplateLiteral(parts)
}
pub fn with_span(self, span: Span) -> Self {
match self {
Expr::Binary {
left, op, right, ..
} => Expr::Binary {
left,
op,
right,
span: Some(span),
},
Expr::Unary { op, expr, .. } => Expr::Unary {
op,
expr,
span: Some(span),
},
Expr::Call { callee, args, .. } => Expr::Call {
callee,
args,
span: Some(span),
},
Expr::Member {
object,
property,
computed,
..
} => Expr::Member {
object,
property,
computed,
span: Some(span),
},
Expr::Conditional {
test,
consequent,
alternate,
..
} => Expr::Conditional {
test,
consequent,
alternate,
span: Some(span),
},
Expr::Assign { target, value, .. } => Expr::Assign {
target,
value,
span: Some(span),
},
other => other,
}
}
}