easter 0.0.5

Type definitions for ECMAScript abstract syntax trees.
Documentation
use std::fmt;
use std::fmt::{Debug, Formatter};
use joker::track::{TrackingRef, TrackingMut, Span, Untrack};
use joker::token::{NumberLiteral, StringLiteral, RegExpLiteral};

use obj::{DotKey, Prop};
use fun::Fun;
use punc::{Unop, Binop, Assop, Logop};
use id::Id;
use patt::{Patt, AssignTarget};

pub enum Expr {
    This(Option<Span>),
    Id(Id),
    Arr(Option<Span>, Vec<Option<Expr>>),
    Obj(Option<Span>, Vec<Prop>),
    Fun(Fun),
    Seq(Option<Span>, Vec<Expr>),
    Unop(Option<Span>, Unop, Box<Expr>),
    Binop(Option<Span>, Binop, Box<Expr>, Box<Expr>),
    Logop(Option<Span>, Logop, Box<Expr>, Box<Expr>),
    PreInc(Option<Span>, Box<Expr>),
    PostInc(Option<Span>, Box<Expr>),
    PreDec(Option<Span>, Box<Expr>),
    PostDec(Option<Span>, Box<Expr>),
    Assign(Option<Span>, Assop, Patt<AssignTarget>, Box<Expr>),
    Cond(Option<Span>, Box<Expr>, Box<Expr>, Box<Expr>),
    Call(Option<Span>, Box<Expr>, Vec<Expr>),
    New(Option<Span>, Box<Expr>, Option<Vec<Expr>>),
    Dot(Option<Span>, Box<Expr>, DotKey),
    Brack(Option<Span>, Box<Expr>, Box<Expr>),
    NewTarget(Option<Span>),
    True(Option<Span>),
    False(Option<Span>),
    Null(Option<Span>),
    Number(Option<Span>, NumberLiteral),
    RegExp(Option<Span>, RegExpLiteral),
    String(Option<Span>, StringLiteral)
}

impl TrackingRef for Expr {
    fn tracking_ref(&self) -> &Option<Span> {
        match *self {
            Expr::This(ref location)
          | Expr::Arr(ref location, _)
          | Expr::Obj(ref location, _)
          | Expr::Seq(ref location, _)
          | Expr::Unop(ref location, _, _)
          | Expr::Binop(ref location, _, _, _)
          | Expr::Logop(ref location, _, _, _)
          | Expr::PreInc(ref location, _)
          | Expr::PostInc(ref location, _)
          | Expr::PreDec(ref location, _)
          | Expr::PostDec(ref location, _)
          | Expr::Assign(ref location, _, _, _)
          | Expr::Cond(ref location, _, _, _)
          | Expr::Call(ref location, _, _)
          | Expr::New(ref location, _, _)
          | Expr::Dot(ref location, _, _)
          | Expr::Brack(ref location, _, _)
          | Expr::NewTarget(ref location)
          | Expr::True(ref location)
          | Expr::False(ref location)
          | Expr::Null(ref location)
          | Expr::Number(ref location, _)
          | Expr::RegExp(ref location, _)
          | Expr::String(ref location, _) => location,
            Expr::Id(ref id) => id.tracking_ref(),
            Expr::Fun(ref fun) => fun.tracking_ref()
        }
    }
}

impl TrackingMut for Expr {
    fn tracking_mut(&mut self) -> &mut Option<Span> {
        match *self {
            Expr::This(ref mut location)
          | Expr::Arr(ref mut location, _)
          | Expr::Obj(ref mut location, _)
          | Expr::Seq(ref mut location, _)
          | Expr::Unop(ref mut location, _, _)
          | Expr::Binop(ref mut location, _, _, _)
          | Expr::Logop(ref mut location, _, _, _)
          | Expr::PreInc(ref mut location, _)
          | Expr::PostInc(ref mut location, _)
          | Expr::PreDec(ref mut location, _)
          | Expr::PostDec(ref mut location, _)
          | Expr::Assign(ref mut location, _, _, _)
          | Expr::Cond(ref mut location, _, _, _)
          | Expr::Call(ref mut location, _, _)
          | Expr::New(ref mut location, _, _)
          | Expr::Dot(ref mut location, _, _)
          | Expr::Brack(ref mut location, _, _)
          | Expr::NewTarget(ref mut location)
          | Expr::True(ref mut location)
          | Expr::False(ref mut location)
          | Expr::Null(ref mut location)
          | Expr::Number(ref mut location, _)
          | Expr::RegExp(ref mut location, _)
          | Expr::String(ref mut location, _) => location,
            Expr::Id(ref mut id) => id.tracking_mut(),
            Expr::Fun(ref mut fun) => fun.tracking_mut()
        }
    }
}

impl PartialEq for Expr {
    fn eq(&self, other: &Self) -> bool {
        if *self.tracking_ref() != *other.tracking_ref() {
            return false;
        }
        match (self, other) {
            (&Expr::This(_),                      &Expr::This(_))                      => true,
            (&Expr::Id(ref id_l),                 &Expr::Id(ref id_r))                 => id_l == id_r,
            (&Expr::Arr(_, ref elts_l),           &Expr::Arr(_, ref elts_r))           => elts_l == elts_r,
            (&Expr::Obj(_, ref props_l),          &Expr::Obj(_, ref props_r))          => props_l == props_r,
            (&Expr::Fun(ref fun_l),               &Expr::Fun(ref fun_r))               => fun_l == fun_r,
            (&Expr::Seq(_, ref exprs_l),          &Expr::Seq(_, ref exprs_r))          => exprs_l == exprs_r,
            (&Expr::Unop(_, ref op_l, ref arg_l), &Expr::Unop(_, ref op_r, ref arg_r)) => (op_l, arg_l) == (op_r, arg_r),
            (&Expr::Binop(_, ref op_l, ref arg1_l, ref arg2_l),
             &Expr::Binop(_, ref op_r, ref arg1_r, ref arg2_r))                        => (op_l, arg1_l, arg2_l) == (op_r, arg1_r, arg2_r),
            (&Expr::Logop(_, ref op_l, ref arg1_l, ref arg2_l),
             &Expr::Logop(_, ref op_r, ref arg1_r, ref arg2_r))                        => (op_l, arg1_l, arg2_l) == (op_r, arg1_r, arg2_r),
            (&Expr::PreInc(_, ref arg_l),         &Expr::PreInc(_, ref arg_r))
          | (&Expr::PostInc(_, ref arg_l),        &Expr::PostInc(_, ref arg_r))
          | (&Expr::PreDec(_, ref arg_l),         &Expr::PreDec(_, ref arg_r))
          | (&Expr::PostDec(_, ref arg_l),        &Expr::PostDec(_, ref arg_r))        => arg_l == arg_r,
            (&Expr::Assign(_, ref op_l, ref patt_l, ref arg_l),
             &Expr::Assign(_, ref op_r, ref patt_r, ref arg_r))                        => (op_l, patt_l, arg_l) == (op_r, patt_r, arg_r),
            (&Expr::Cond(_, ref test_l, ref cons_l, ref alt_l),
             &Expr::Cond(_, ref test_r, ref cons_r, ref alt_r))                        => (test_l, cons_l, alt_l) == (test_r, cons_r, alt_r),
            (&Expr::Call(_, ref callee_l, ref args_l),
             &Expr::Call(_, ref callee_r, ref args_r))                                 => (callee_l, args_l) == (callee_r, args_r),
            (&Expr::New(_, ref callee_l, None),   &Expr::New(_, ref callee_r, None))   => callee_l == callee_r,
            (&Expr::New(_, ref callee_l, None),   &Expr::New(_, ref callee_r, Some(ref args)))
          | (&Expr::New(_, ref callee_l, Some(ref args)),
             &Expr::New(_, ref callee_r, None))                                        => (callee_l == callee_r) && args.is_empty(),
            (&Expr::New(_, ref callee_l, Some(ref args_l)),
             &Expr::New(_, ref callee_r, Some(ref args_r)))                            => (callee_l, args_l) == (callee_r, args_r),
            (&Expr::Dot(_, ref obj_l, ref key_l), &Expr::Dot(_, ref obj_r, ref key_r)) => (obj_l, key_l) == (obj_r, key_r),
            (&Expr::Brack(_, ref obj_l, ref prop_l),
             &Expr::Brack(_, ref obj_r, ref prop_r))                                   => (obj_l, prop_l) == (obj_r, prop_r),
            (&Expr::NewTarget(_),          &Expr::NewTarget(_))                        => true,
            (&Expr::True(_),               &Expr::True(_))                             => true,
            (&Expr::False(_),              &Expr::False(_))                            => true,
            (&Expr::Null(_),               &Expr::Null(_))                             => true,
            (&Expr::Number(_, ref lit_l),  &Expr::Number(_, ref lit_r))                => lit_l == lit_r,
            (&Expr::RegExp(_, ref lit_l),  &Expr::RegExp(_, ref lit_r))                => lit_l == lit_r,
            (&Expr::String(_, ref lit_l),  &Expr::String(_, ref lit_r))                => lit_l == lit_r,
            _ => false
        }
    }
}

impl Debug for Expr {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match self {
            &Expr::This(_)                                => fmt.write_str("This"),
            &Expr::Id(ref id)                             => fmt.debug_tuple("Id").field(id).finish(),
            &Expr::Arr(_, ref elts)                       => fmt.debug_tuple("Arr").field(elts).finish(),
            &Expr::Obj(_, ref props)                      => fmt.debug_tuple("Obj").field(props).finish(),
            &Expr::Fun(ref fun)                           => fmt.debug_tuple("Fun").field(fun).finish(),
            &Expr::Seq(_, ref exprs)                      => fmt.debug_tuple("Seq").field(exprs).finish(),
            &Expr::Unop(_, ref op, ref arg)               => fmt.debug_tuple("Unop").field(op).field(arg).finish(),
            &Expr::Binop(_, ref op, ref left, ref right)  => fmt.debug_tuple("Binop").field(op).field(left).field(right).finish(),
            &Expr::Logop(_, ref op, ref left, ref right)  => fmt.debug_tuple("Logop").field(op).field(left).field(right).finish(),
            &Expr::PreInc(_, ref arg)                     => fmt.debug_tuple("PreInc").field(arg).finish(),
            &Expr::PostInc(_, ref arg)                    => fmt.debug_tuple("PostInc").field(arg).finish(),
            &Expr::PreDec(_, ref arg)                     => fmt.debug_tuple("PreDec").field(arg).finish(),
            &Expr::PostDec(_, ref arg)                    => fmt.debug_tuple("PostDec").field(arg).finish(),
            &Expr::Assign(_, ref op, ref left, ref right) => fmt.debug_tuple("Assign").field(op).field(left).field(right).finish(),
            &Expr::Cond(_, ref test, ref cons, ref alt)   => fmt.debug_tuple("Cond").field(test).field(cons).field(alt).finish(),
            &Expr::Call(_, ref callee, ref args)          => fmt.debug_tuple("Call").field(callee).field(args).finish(),
            &Expr::New(_, ref ctor, None) => {
                let args: Vec<Expr> = vec![];
                fmt.debug_tuple("New").field(ctor).field(&args).finish()
            }
            &Expr::New(_, ref ctor, Some(ref args))       => fmt.debug_tuple("New").field(ctor).field(args).finish(),
            &Expr::Dot(_, ref expr, ref key)              => fmt.debug_tuple("Dot").field(expr).field(key).finish(),
            &Expr::Brack(_, ref expr, ref prop)           => fmt.debug_tuple("Brack").field(expr).field(prop).finish(),
            &Expr::NewTarget(_)                           => fmt.write_str("NewTarget"),
            &Expr::True(_)                                => fmt.write_str("True"),
            &Expr::False(_)                               => fmt.write_str("False"),
            &Expr::Null(_)                                => fmt.write_str("Null"),
            &Expr::Number(_, ref lit)                     => fmt.debug_tuple("Number").field(lit).finish(),
            &Expr::RegExp(_, ref lit)                     => fmt.debug_tuple("RegExp").field(lit).finish(),
            &Expr::String(_, ref lit)                     => fmt.debug_tuple("String").field(lit).finish()
        }
    }
}

impl Untrack for Expr {
    fn untrack(&mut self) {
        *self.tracking_mut() = None;
        match *self {
            Expr::This(_)                                           => { }
            Expr::Id(ref mut id)                                    => { id.untrack(); }
            Expr::Arr(_, ref mut exprs)                             => { exprs.untrack(); }
            Expr::Obj(_, ref mut props)                             => { props.untrack(); }
            Expr::Fun(ref mut fun)                                  => { fun.untrack(); }
            Expr::Seq(_, ref mut exprs)                             => { exprs.untrack(); }
            Expr::Unop(_, ref mut op, ref mut expr)                 => { op.untrack(); expr.untrack(); }
            Expr::Binop(_, ref mut op, ref mut left, ref mut right) => { op.untrack(); left.untrack(); right.untrack(); }
            Expr::Logop(_, ref mut op, ref mut left, ref mut right) => { op.untrack(); left.untrack(); right.untrack(); }
            Expr::PreInc(_, ref mut expr)                           => { expr.untrack(); }
            Expr::PostInc(_, ref mut expr)                          => { expr.untrack(); }
            Expr::PreDec(_, ref mut expr)                           => { expr.untrack(); }
            Expr::PostDec(_, ref mut expr)                          => { expr.untrack(); }
            Expr::Assign(_, ref mut op, ref mut patt, ref mut expr) => { op.untrack(); patt.untrack(); expr.untrack(); }
            Expr::Cond(_, ref mut test, ref mut cons, ref mut alt)  => { test.untrack(); cons.untrack(); alt.untrack(); }
            Expr::Call(_, ref mut callee, ref mut args)             => { callee.untrack(); args.untrack(); }
            Expr::New(_, ref mut ctor, ref mut args)                => { ctor.untrack(); args.untrack(); }
            Expr::Dot(_, ref mut obj, ref mut key)                  => { obj.untrack(); key.untrack(); }
            Expr::Brack(_, ref mut obj, ref mut prop)               => { obj.untrack(); prop.untrack(); }
            Expr::NewTarget(_)                                      => { }
            Expr::True(_)                                           => { }
            Expr::False(_)                                          => { }
            Expr::Null(_)                                           => { }
            Expr::Number(_, _)                                      => { }
            Expr::RegExp(_, _)                                      => { }
            Expr::String(_, _)                                      => { }
        }
    }
}