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
use joker::track::*;

use id::Id;
use expr::Expr;
use obj::{PropKey, DotKey};

#[derive(Debug, PartialEq)]
pub enum CompoundPatt<T> {
    Arr(Option<Span>, Vec<Option<Patt<T>>>),
    Obj(Option<Span>, Vec<PropPatt<T>>)
}

impl<T> TrackingRef for CompoundPatt<T> {
    fn tracking_ref(&self) -> &Option<Span> {
        match *self {
            CompoundPatt::Arr(ref location, _)
          | CompoundPatt::Obj(ref location, _) => location
        }
    }
}

impl<T> TrackingMut for CompoundPatt<T> {
    fn tracking_mut(&mut self) -> &mut Option<Span> {
        match *self {
            CompoundPatt::Arr(ref mut location, _)
          | CompoundPatt::Obj(ref mut location, _) => { location }
        }
    }
}

impl<T: Untrack> Untrack for CompoundPatt<T> {
    fn untrack(&mut self) {
        match *self {
            CompoundPatt::Arr(ref mut location, ref mut patts) => {
                *location = None;
                patts.untrack();
            }
            CompoundPatt::Obj(ref mut location, ref mut props) => {
                *location = None;
                props.untrack();
            }
        }
    }
}

#[derive(Debug, PartialEq)]
pub struct PropPatt<T> {
    pub location: Option<Span>,
    pub key: PropKey,
    pub patt: Patt<T>
}

impl<T> TrackingRef for PropPatt<T> {
    fn tracking_ref(&self) -> &Option<Span> { &self.location }
}

impl<T> TrackingMut for PropPatt<T> {
    fn tracking_mut(&mut self) -> &mut Option<Span> { &mut self.location }
}

impl<T: Untrack> Untrack for PropPatt<T> {
    fn untrack(&mut self) {
        self.location = None;
        self.key.untrack();
        self.patt.untrack();
    }
}

#[derive(Debug, PartialEq)]
pub enum Patt<T> {
    Simple(T),
    Compound(CompoundPatt<T>)
}

impl<T> Patt<T> {
    pub fn is_simple(&self) -> bool {
        match *self {
            Patt::Simple(_)   => true,
            Patt::Compound(_) => false
        }
    }
}

impl<T: TrackingRef> TrackingRef for Patt<T> {
    fn tracking_ref(&self) -> &Option<Span> {
        match *self {
            Patt::Simple(ref simple) => simple.tracking_ref(),
            Patt::Compound(ref patt) => patt.tracking_ref()
        }
    }
}

impl<T: TrackingMut> TrackingMut for Patt<T> {
    fn tracking_mut(&mut self) -> &mut Option<Span> {
        match *self {
            Patt::Simple(ref mut simple) => simple.tracking_mut(),
            Patt::Compound(ref mut patt) => patt.tracking_mut()
        }
    }
}

impl<T: Untrack> Untrack for Patt<T> {
    fn untrack(&mut self) {
        match *self {
            Patt::Simple(ref mut simple) => { simple.untrack(); }
            Patt::Compound(ref mut patt) => { patt.untrack(); }
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum AssignTarget {
    Id(Id),
    Dot(Option<Span>, Box<Expr>, DotKey),
    Brack(Option<Span>, Box<Expr>, Box<Expr>)
}

impl TrackingRef for AssignTarget {
    fn tracking_ref(&self) -> &Option<Span> {
        match *self {
            AssignTarget::Id(ref id) => id.tracking_ref(),
            AssignTarget::Dot(ref location, _, _)
          | AssignTarget::Brack(ref location, _, _) => location
        }
    }
}

impl TrackingMut for AssignTarget {
    fn tracking_mut(&mut self) -> &mut Option<Span> {
        match *self {
            AssignTarget::Id(ref mut id) => id.tracking_mut(),
            AssignTarget::Dot(ref mut location, _, _)
          | AssignTarget::Brack(ref mut location, _, _) => location
        }
    }
}

impl Untrack for AssignTarget {
    fn untrack(&mut self) {
        match *self {
            AssignTarget::Id(ref mut id) => {
                id.untrack();
            }
            AssignTarget::Dot(ref mut location, ref mut obj, ref mut prop) => {
                *location = None;
                obj.untrack();
                prop.untrack();
            }
            AssignTarget::Brack(ref mut location, ref mut obj, ref mut prop) => {
                *location = None;
                obj.untrack();
                prop.untrack();
            }
        }
    }
}