1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
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(_, _)                                      => { }
        }
    }
}