use crate::syntax::ast::{
constant::Const,
op::{BinOp, Operator, UnaryOp},
};
use gc_derive::{Finalize, Trace};
use std::{
collections::btree_map::BTreeMap,
fmt::{Display, Formatter, Result},
};
#[derive(Clone, Trace, Finalize, Debug, PartialEq)]
pub struct Expr {
pub def: ExprDef,
}
impl Expr {
pub fn new(def: ExprDef) -> Self {
Self { def }
}
}
impl Display for Expr {
fn fmt(&self, f: &mut Formatter) -> Result {
write!(f, "{}", self.def)
}
}
#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
pub enum ExprDef {
BinOp(BinOp, Box<Expr>, Box<Expr>),
UnaryOp(UnaryOp, Box<Expr>),
Const(Const),
ConstDecl(Vec<(String, Expr)>),
Construct(Box<Expr>, Vec<Expr>),
Block(Vec<Expr>),
Local(String),
GetConstField(Box<Expr>, String),
GetField(Box<Expr>, Box<Expr>),
Call(Box<Expr>, Vec<Expr>),
WhileLoop(Box<Expr>, Box<Expr>),
If(Box<Expr>, Box<Expr>, Option<Box<Expr>>),
Switch(Box<Expr>, Vec<(Expr, Vec<Expr>)>, Option<Box<Expr>>),
ObjectDecl(Box<BTreeMap<String, Expr>>),
ArrayDecl(Vec<Expr>),
FunctionDecl(Option<String>, Vec<Expr>, Box<Expr>),
ArrowFunctionDecl(Vec<Expr>, Box<Expr>),
Return(Option<Box<Expr>>),
Throw(Box<Expr>),
Assign(Box<Expr>, Box<Expr>),
VarDecl(Vec<(String, Option<Expr>)>),
LetDecl(Vec<(String, Option<Expr>)>),
TypeOf(Box<Expr>),
}
impl Operator for ExprDef {
fn get_assoc(&self) -> bool {
match *self {
ExprDef::Construct(_, _)
| ExprDef::UnaryOp(_, _)
| ExprDef::TypeOf(_)
| ExprDef::If(_, _, _)
| ExprDef::Assign(_, _) => false,
_ => true,
}
}
fn get_precedence(&self) -> u64 {
match self {
ExprDef::GetField(_, _) | ExprDef::GetConstField(_, _) => 1,
ExprDef::Call(_, _) | ExprDef::Construct(_, _) => 2,
ExprDef::UnaryOp(UnaryOp::IncrementPost, _)
| ExprDef::UnaryOp(UnaryOp::IncrementPre, _)
| ExprDef::UnaryOp(UnaryOp::DecrementPost, _)
| ExprDef::UnaryOp(UnaryOp::DecrementPre, _) => 3,
ExprDef::UnaryOp(UnaryOp::Not, _)
| ExprDef::UnaryOp(UnaryOp::Tilde, _)
| ExprDef::UnaryOp(UnaryOp::Minus, _)
| ExprDef::TypeOf(_) => 4,
ExprDef::BinOp(op, _, _) => op.get_precedence(),
ExprDef::If(_, _, _) => 15,
ExprDef::Assign(_, _) => 17,
_ => 19,
}
}
}
impl Display for ExprDef {
fn fmt(&self, f: &mut Formatter) -> Result {
match *self {
ExprDef::Const(ref c) => write!(f, "{}", c),
ExprDef::Block(ref block) => {
write!(f, "{{")?;
for expr in block.iter() {
write!(f, "{};", expr)?;
}
write!(f, "}}")
}
ExprDef::Local(ref s) => write!(f, "{}", s),
ExprDef::GetConstField(ref ex, ref field) => write!(f, "{}.{}", ex, field),
ExprDef::GetField(ref ex, ref field) => write!(f, "{}[{}]", ex, field),
ExprDef::Call(ref ex, ref args) => {
write!(f, "{}(", ex)?;
let arg_strs: Vec<String> = args.iter().map(ToString::to_string).collect();
write!(f, "{})", arg_strs.join(","))
}
ExprDef::Construct(ref func, ref args) => {
f.write_fmt(format_args!("new {}", func))?;
f.write_str("(")?;
let mut first = true;
for e in args.iter() {
if !first {
f.write_str(", ")?;
}
first = false;
Display::fmt(e, f)?;
}
f.write_str(")")
}
ExprDef::WhileLoop(ref cond, ref expr) => write!(f, "while({}) {}", cond, expr),
ExprDef::If(ref cond, ref expr, None) => write!(f, "if({}) {}", cond, expr),
ExprDef::If(ref cond, ref expr, Some(ref else_e)) => {
write!(f, "if({}) {} else {}", cond, expr, else_e)
}
ExprDef::Switch(ref val, ref vals, None) => {
f.write_fmt(format_args!("switch({})", val))?;
f.write_str(" {")?;
for e in vals.iter() {
f.write_fmt(format_args!("case {}: \n", e.0))?;
join_expr(f, &e.1)?;
}
f.write_str("}")
}
ExprDef::Switch(ref val, ref vals, Some(ref def)) => {
f.write_fmt(format_args!("switch({})", val))?;
f.write_str(" {")?;
for e in vals.iter() {
f.write_fmt(format_args!("case {}: \n", e.0))?;
join_expr(f, &e.1)?;
}
f.write_str("default: \n")?;
Display::fmt(def, f)?;
f.write_str("}")
}
ExprDef::ObjectDecl(ref map) => {
f.write_str("{")?;
for (key, value) in map.iter() {
f.write_fmt(format_args!("{}: {},", key, value))?;
}
f.write_str("}")
}
ExprDef::ArrayDecl(ref arr) => {
f.write_str("[")?;
join_expr(f, arr)?;
f.write_str("]")
}
ExprDef::FunctionDecl(ref name, ref args, ref expr) => {
write!(f, "function ")?;
if let Some(func_name) = name {
f.write_fmt(format_args!("{}", func_name))?;
}
write!(f, "{{")?;
join_expr(f, args)?;
write!(f, "}} {}", expr)
}
ExprDef::ArrowFunctionDecl(ref args, ref expr) => {
write!(f, "(")?;
join_expr(f, args)?;
write!(f, ") => {}", expr)
}
ExprDef::BinOp(ref op, ref a, ref b) => write!(f, "{} {} {}", a, op, b),
ExprDef::UnaryOp(ref op, ref a) => write!(f, "{}{}", op, a),
ExprDef::Return(Some(ref ex)) => write!(f, "return {}", ex),
ExprDef::Return(None) => write!(f, "return"),
ExprDef::Throw(ref ex) => write!(f, "throw {}", ex),
ExprDef::Assign(ref ref_e, ref val) => write!(f, "{} = {}", ref_e, val),
ExprDef::VarDecl(ref vars) | ExprDef::LetDecl(ref vars) => {
if let ExprDef::VarDecl(_) = *self {
f.write_str("var ")?;
} else {
f.write_str("let ")?;
}
for (key, val) in vars.iter() {
match val {
Some(x) => f.write_fmt(format_args!("{} = {}", key, x))?,
None => f.write_fmt(format_args!("{}", key))?,
}
}
Ok(())
}
ExprDef::ConstDecl(ref vars) => {
f.write_str("const ")?;
for (key, val) in vars.iter() {
f.write_fmt(format_args!("{} = {}", key, val))?
}
Ok(())
}
ExprDef::TypeOf(ref e) => write!(f, "typeof {}", e),
}
}
}
fn join_expr(f: &mut Formatter, expr: &[Expr]) -> Result {
let mut first = true;
for e in expr.iter() {
if !first {
f.write_str(", ")?;
}
first = false;
Display::fmt(e, f)?;
}
Ok(())
}