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
use std::fmt;
use std::fmt::{Display, Formatter};
use joker::track::{Span, TrackingRef};
use expr::Expr;
use patt::{Patt, AssignTarget, CompoundPatt, PropPatt};
use obj::{Prop, PropVal};

#[derive(Debug, PartialEq)]
pub enum Error {
    InvalidAssignTarget(Option<Span>),
    InvalidPropPatt(Option<Span>)
}

impl Display for Error {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match self {
            &Error::InvalidAssignTarget(_) => {
                fmt.write_str("invalid assignment pattern")
            }
            &Error::InvalidPropPatt(_) => {
                fmt.write_str("invalid object property in assignment pattern")
            }
        }
    }
}

pub trait IntoAssignPatt {
    fn into_assign_patt(self) -> Result<Patt<AssignTarget>, Error>;
}

impl IntoAssignPatt for Expr {
    fn into_assign_patt(self) -> Result<Patt<AssignTarget>, Error> {
        Ok(match self {
            Expr::Id(id)                     => Patt::Simple(AssignTarget::Id(id)),
            Expr::Dot(location, obj, key)    => Patt::Simple(AssignTarget::Dot(location, obj, key)),
            Expr::Brack(location, obj, prop) => Patt::Simple(AssignTarget::Brack(location, obj, prop)),
            Expr::Obj(location, props) => {
                let mut prop_patts = Vec::with_capacity(props.len());
                for prop in props {
                    prop_patts.push(try!(prop.into_assign_prop()));
                }
                Patt::Compound(CompoundPatt::Obj(location, prop_patts))
            }
            Expr::Arr(location, exprs) => {
                let mut patts = Vec::with_capacity(exprs.len());
                for expr in exprs {
                    patts.push(match expr {
                        Some(expr) => Some(try!(expr.into_assign_patt())),
                        None => None
                    });
                }
                Patt::Compound(CompoundPatt::Arr(location, patts))
            }
            _ => { return Err(Error::InvalidAssignTarget(*self.tracking_ref())); }
        })
    }
}

pub trait IntoAssignProp {
    fn into_assign_prop(self) -> Result<PropPatt<AssignTarget>, Error>;
}

impl IntoAssignProp for Prop {
    fn into_assign_prop(self) -> Result<PropPatt<AssignTarget>, Error> {
        let location = *self.tracking_ref();
        let key = self.key;
        let patt = match self.val {
            PropVal::Init(expr) => try!(expr.into_assign_patt()),
            _ => { return Err(Error::InvalidPropPatt(*self.val.tracking_ref())); }
        };
        Ok(PropPatt { location: location, key: key, patt: patt })
    }
}