use std::ops::{Deref, DerefMut};
use joker::word::Name;
use joker::track::{TrackingRef, TrackingMut, Untrack, Span};

use expr::Expr;
use decl::Dtor;
use patt::Patt;

#[derive(Debug, Eq, PartialEq, Clone, TrackingRef, TrackingMut)]
pub struct Id {
    pub location: Option<Span>,
    pub name: Name
}

impl Deref for Id {
    type Target = Option<Span>;

    fn deref(&self) -> &Option<Span> {
        &self.location
    }
}

impl DerefMut for Id {
    fn deref_mut(&mut self) -> &mut Option<Span> {
        &mut self.location
    }
}

impl Untrack for Id {
    fn untrack(&mut self) { self.location = None; }
}

pub trait IdExt {
    fn new(Name, Option<Span>) -> Id;
    fn into_patt(self) -> Patt<Id>;
    fn into_expr(self) -> Expr;
    fn into_dtor(self) -> Dtor;
}

impl IdExt for Id {
    fn new(name: Name, location: Option<Span>) -> Id {
        Id {
            location: location,
            name: name
        }
    }

    fn into_patt(self) -> Patt<Id> {
        Patt::Simple(self)
    }

    fn into_expr(self) -> Expr {
        Expr::Id(self)
    }

    fn into_dtor(self) -> Dtor {
        Dtor::Simple(*self.tracking_ref(), self, None)
    }
}

use joker::word::Name;
use joker::track::{TrackingRef, TrackingMut, Untrack, Span};

use expr::Expr;
use decl::Dtor;
use patt::Patt;

#[derive(Debug, Eq, PartialEq, Clone, TrackingRef, TrackingMut)]
pub struct Id {
    pub location: Option<Span>,
    pub name: Name
}

impl Untrack for Id {
    fn untrack(&mut self) { self.location = None; }
}

pub trait IdExt {
    fn new(Name, Option<Span>) -> Id;
    fn into_patt(self) -> Patt<Id>;
    fn into_expr(self) -> Expr;
    fn into_dtor(self) -> Dtor;
}

impl IdExt for Id {
    fn new(name: Name, location: Option<Span>) -> Id {
        Id {
            location: location,
            name: name
        }
    }

    fn into_patt(self) -> Patt<Id> {
        Patt::Simple(self)
    }

    fn into_expr(self) -> Expr {
        Expr::Id(self)
    }

    fn into_dtor(self) -> Dtor {
        Dtor::Simple(*self.tracking_ref(), self, None)
    }
}

Remove Id -> Option<Span> deref
Remove Id -> Option<Span> deref

This is somewhat implicit (not very obvious) way of coversion, and we
don't do this for any other types, so  I guess we should prefer API
consumer to get locations via explicit .tracking_ref() / .tracking_mut().
