esprit 0.0.5

An ECMAScript parser library.
Documentation
use std::collections::HashMap;
use std::rc::Rc;
use std::mem::replace;
use joker::word::Name;
use joker::track::span;
use easter::stmt::Stmt;
use easter::id::Id;
use result::Result;
use parser::Parser;

pub trait WithContext {
    fn with_labels<F>(&mut self, mut labels: Vec<Id>, label_type: LabelType, op: F) -> Result<Stmt>
      where F: FnOnce(&mut Self) -> Result<Stmt>;
    fn allow_in<F, T>(&mut self, allow_in: bool, parse: F) -> Result<T>
      where F: FnOnce(&mut Self) -> Result<T>;
}

impl<I: Iterator<Item=char>> WithContext for Parser<I> {
    fn with_labels<F>(&mut self, mut labels: Vec<Id>, label_type: LabelType, op: F) -> Result<Stmt>
      where F: FnOnce(&mut Self) -> Result<Stmt>
    {
        let mut label_strings = Vec::new();
        for id in labels.iter() {
            let label = Rc::new(id.name.clone());
            self.parser_cx.labels.insert(label.clone(), label_type);
            label_strings.push(label);
        }
        let result = op(self);
        for label in label_strings {
            self.parser_cx.labels.remove(&label);
        }
        let mut body = try!(result);
        labels.reverse();
        for id in labels {
            let location = span(&id, &body);
            body = Stmt::Label(location, id, Box::new(body));
        }
        Ok(body)
    }

    fn allow_in<F, T>(&mut self, allow_in: bool, parse: F) -> Result<T>
      where F: FnOnce(&mut Self) -> Result<T>
    {
        let allow_in = replace(&mut self.parser_cx.allow_in, allow_in);
        let result = parse(self);
        replace(&mut self.parser_cx.allow_in, allow_in);
        result
    }
}

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum LabelType {
    Statement,
    Iteration
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Context {
    pub function: bool,
    pub iteration: bool,
    pub switch: bool,
    pub allow_in: bool,
    pub labels: HashMap<Rc<Name>, LabelType>
}

impl Context {
    pub fn new() -> Context {
        Context {
            function: false,
            iteration: false,
            switch: false,
            allow_in: true,
            labels: HashMap::new()
        }
    }

    pub fn new_function() -> Context {
        Context {
            function: true,
            iteration: false,
            switch: false,
            allow_in: true,
            labels: HashMap::new()
        }
    }
}