<commit_before>use std::time::Duration;
use std::time::{SystemTime, UNIX_EPOCH};

#[derive(PartialEq, Eq, Debug, Copy, Clone)]
pub enum TickUnit {
    Nanos,
    Micros,
    Millis,
    Secs,
}

impl TickUnit {
    #[inline]
    pub fn from_id(id: u8) -> TickUnit {
        match id {
            9 => TickUnit::Nanos,
            6 => TickUnit::Micros,
            3 => TickUnit::Millis,
            1 => TickUnit::Secs,
            _ => panic!("Unknown time unit id {}", id),
        }
    }
    #[inline]
    pub fn id(&self) -> u8 {
        match self {
            TickUnit::Nanos => 9,
            TickUnit::Micros => 6,
            TickUnit::Millis => 3,
            TickUnit::Secs => 0,
        }
    }

    #[inline]
    pub fn convert(&self, duration: Duration) -> u64 {
        match self {
            TickUnit::Nanos => duration.as_nanos() as u64,
            TickUnit::Micros => duration.as_micros() as u64,
            TickUnit::Millis => duration.as_millis() as u64,
            TickUnit::Secs => duration.as_secs(),
        }
    }

    #[inline]
    pub fn nix_time(&self) -> u64 {
        self.convert(SystemTime::now().duration_since(UNIX_EPOCH).unwrap())
    }
}
<commit_msg>Improved documentation and unit tests for the tick module.<commit_after>use std::time::Duration;
use std::time::{SystemTime, UNIX_EPOCH};

///A TickUnit represents a specific time duration but does not maintain time information, it only helps define the time granularity
///required to used in various contexts by all kekbit components which *share a given channel*.
///For each channel it's TickUnit will be spcified at creation and will *never be changed*
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
pub enum TickUnit {
    ///TickUnit representing one thousandth of a microsecond.
    Nanos,
    ///TickUnit representing one thousandth of a millisecond.
    Micros,
    ///TickUnit representing one thousandth of a second.
    Millis,
    ///TickUnit representing one second.
    Secs,
}

impl TickUnit {
    ///Returns the unique u8 id assigned to every TickUnit. This id it's used for serialization it would never change.
    ///
    /// #Examples
    /// ```
    /// use kekbit_core::tick::TickUnit::*;
    ///
    /// assert_eq!(Nanos.id(), 9);
    /// assert_eq!(Micros.id(), 6);
    /// assert_eq!(Millis.id(), 3);
    /// assert_eq!(Secs.id(), 0);
    /// ```
    #[inline]
    pub fn id(&self) -> u8 {
        match self {
            TickUnit::Nanos => 9,
            TickUnit::Micros => 6,
            TickUnit::Millis => 3,
            TickUnit::Secs => 0,
        }
    }

    /// Returns the tick unit with the given id
    ///
    /// # Arguments
    ///
    /// * `id` - The identifier of the tick unit as u8. In the curent kekbit version it must be **0, 3, 6 or 9**
    ///
    /// # Panics
    ///
    /// If the specified id has no tick unit attached
    ///
    #[inline]
    pub fn from_id(id: u8) -> TickUnit {
        match id {
            9 => TickUnit::Nanos,
            6 => TickUnit::Micros,
            3 => TickUnit::Millis,
            0 => TickUnit::Secs,
            _ => panic!("Unknown time unit id {}", id),
        }
    }
    /// Returns the total number of tick units contained by this `Duration` as a u64.
    /// If the tiemstamp size is longer than 64 bits, it will be truncated to the lower 64 bits
    ///
    /// # Examples
    ///
    /// ```
    /// use std::time::Duration;
    /// use kekbit_core::tick::TickUnit::*;
    ///
    ///let duration = Duration::new(1, 500_000_000); //1 sec and a half
    ///assert_eq!(Nanos.convert(duration), 1_500_000_000);
    ///assert_eq!(Micros.convert(duration), 1_500_000);
    ///assert_eq!(Millis.convert(duration), 1_500);
    ///assert_eq!(Secs.convert(duration), 1);
    /// ```
    #[inline]
    pub fn convert(&self, duration: Duration) -> u64 {
        match self {
            TickUnit::Nanos => duration.as_nanos() as u64,
            TickUnit::Micros => duration.as_micros() as u64,
            TickUnit::Millis => duration.as_millis() as u64,
            TickUnit::Secs => duration.as_secs(),
        }
    }
    ///Returns the difference, measured in the current tick unit, between the current time and midnight, January 1, 1970 UTC.
    ///
    /// # Examples
    ///  ```
    /// use kekbit_core::tick::TickUnit::*;
    ///
    /// println!("{}ms since January 1, 1970 UTC", Millis.nix_time());
    /// ```
    #[inline]
    pub fn nix_time(&self) -> u64 {
        self.convert(SystemTime::now().duration_since(UNIX_EPOCH).unwrap())
    }
}

#[cfg(test)]
mod tests {
    use super::TickUnit::*;
    use super::*;
    use std::time::Duration;
    #[test]
    fn check_ids_symetry() {
        assert_eq!(Nanos.id(), TickUnit::from_id(Nanos.id()).id());
        assert_eq!(Micros.id(), TickUnit::from_id(Micros.id()).id());
        assert_eq!(Millis.id(), TickUnit::from_id(Millis.id()).id());
        assert_eq!(Secs.id(), TickUnit::from_id(Secs.id()).id());
    }

    #[test]
    #[should_panic]
    fn check_wrong_id() {
        TickUnit::from_id(123);
    }

    #[test]
    fn test_coversion() {
        let duration = Duration::new(1, 500_000_000); //1 sec and a half
        assert_eq!(Nanos.convert(duration), 1_500_000_000);
        assert_eq!(Micros.convert(duration), 1_500_000);
        assert_eq!(Millis.convert(duration), 1_500);
        assert_eq!(Secs.convert(duration), 1);
    }

    #[test]
    fn check_ids() {
        assert_eq!(Nanos.id(), 9);
        assert_eq!(Micros.id(), 6);
        assert_eq!(Millis.id(), 3);
        assert_eq!(Secs.id(), 0);
    }

    #[test]
    fn check_nix_time() {
        let t1 = Nanos.nix_time();
        let t2 = Nanos.nix_time();
        assert!(t1 <= t2);
    }
}
<|endoftext|>


<commit_before>use fall_tree::NodeType;

use tree_builder::{Node, TokenSequence};

use {SynRule, Expr, PrattVariant};

pub fn parse(
    node_types: &[NodeType],
    rules: &[SynRule],
    tokens: TokenSequence
) -> (Node, u64) {
    Parser { node_types, rules: rules, start_rule: Expr::Rule(0) }.parse(tokens)
}

struct Ctx<'p> {
    ticks: u64,
    predicate_mode: bool,
    contexts: [bool; 16],
    args: [Option<&'p Expr>; 16],
    prev: Option<NodeType>,
    replacement: Option<NodeType>,
}

impl<'p> Ctx<'p> {
    fn create_composite_node(&mut self, ty: Option<NodeType>) -> Node {
        Node::composite(ty)
    }

    fn create_error_node(&mut self) -> Node {
        Node::error()
    }

    fn create_leaf_node<'t>(&mut self, tokens: TokenSequence<'t>) -> (Node, TokenSequence<'t>) {
        tokens.bump()
    }

    fn create_contextual_leaf_node<'t>(&mut self, tokens: TokenSequence<'t>, ty: NodeType, text: &str)
                                       -> Option<(Node, TokenSequence<'t>)> {
        tokens.bump_by_text(ty, text)
    }

    fn create_success_node<'t>(&mut self, tokens: TokenSequence<'t>) -> (Node, TokenSequence<'t>) {
        Node::success(tokens)
    }

    fn push_child(&self, parent: &mut Node, child: Node) {
        if self.predicate_mode {
            return;
        }
        match child {
            // Microoptimization: don't store empty success nodes
            Node::Composite { ty: None, ref children, .. } if children.is_empty() => return,
            _ => {}
        }
        parent.push_child(child)
    }
}

struct Parser<'r> {
    node_types: &'r [NodeType],
    rules: &'r [SynRule],
    start_rule: Expr,
}

impl<'r> Parser<'r> {
    fn parse(&self, tokens: TokenSequence) -> (Node, u64) {
        let mut ctx = Ctx {
            ticks: 0,
            predicate_mode: false,
            contexts: [false; 16],
            args: [None; 16],
            prev: None,
            replacement: None,
        };
        let (mut file_node, mut leftover) = self
            .parse_exp(&self.start_rule, tokens, &mut ctx)
            .unwrap_or_else(|| {
                let ty = match self.rules[0].body {
                    Expr::Pub { ty_idx, .. } => self.node_type(ty_idx),
                    _ => panic!("First rule must be public"),
                };
                (ctx.create_composite_node(Some(ty)), tokens)
            });

        let mut error = ctx.create_error_node();
        let mut skipped = false;
        while leftover.current().is_some() {
            skipped = true;
            let p = ctx.create_leaf_node(leftover);
            leftover = p.1;
            ctx.push_child(&mut error, p.0)
        }
        if skipped {
            ctx.push_child(&mut file_node, error)
        }
        (file_node, ctx.ticks)
    }

    fn parse_exp<'t, 'p>(&'p self, expr: &'p Expr, tokens: TokenSequence<'t>, ctx: &mut Ctx<'p>)
                         -> Option<(Node, TokenSequence<'t>)> {
        ctx.ticks += 1;
        match *expr {
            Expr::Pub { ty_idx, ref body, replaceable } => {
                if replaceable {
                    ctx.replacement = None;
                }
                match self.parse_exp(body, tokens, ctx) {
                    Some((node, ts)) => {
                        let node_type = match (replaceable, ctx.replacement) {
                            (true, Some(ty)) => ty,
                            _ => self.node_type(ty_idx),
                        };
                        let mut result = ctx.create_composite_node(Some(node_type));
                        ctx.push_child(&mut result, node);

                        ctx.prev = Some(node_type);
                        Some((result, ts))
                    }
                    _ => {
                        None
                    }
                }
            }
            Expr::PubReplace { ty_idx, ref body } => {
                match self.parse_exp(body, tokens, ctx) {
                    Some((node, ts)) => {
                        let node_type = self.node_type(ty_idx);
                        ctx.replacement = Some(node_type);
                        Some((node, ts))
                    }
                    _ => {
                        None
                    }
                }
            }

            Expr::Or(ref parts) => self.parse_any(parts.iter(), tokens, ctx),

            Expr::And(ref parts, commit) => {
                let mut node = ctx.create_composite_node(None);
                let commit = commit.unwrap_or(parts.len());
                let mut tokens = tokens;
                for (i, p) in parts.iter().enumerate() {
                    if let Some((n, ts)) = self.parse_exp(p, tokens, ctx) {
                        tokens = ts;
                        ctx.push_child(&mut node, n);
                    } else {
                        if i < commit {
                            return None;
                        }
                        let error_node = ctx.create_error_node();
                        ctx.push_child(&mut node, error_node);
                        break
                    }
                }
                Some((node, tokens))
            }

            Expr::Rule(id) => self.parse_exp(&self.rules[id].body, tokens, ctx),

            Expr::Token(ty) => {
                if let Some(current) = tokens.current() {
                    if self.node_type(ty) == current.ty {
                        return Some(ctx.create_leaf_node(tokens));
                    }
                }
                None
            }

            Expr::ContextualToken(ty, ref text) => {
                ctx.create_contextual_leaf_node(tokens, self.node_type(ty), &*text)
            }

            Expr::Opt(ref body) => self.parse_exp(body, tokens, ctx).or_else(|| {
                Some(ctx.create_success_node(tokens))
            }),
            Expr::Not(ref e) => if self.parse_exp(e, tokens, ctx).is_some() {
                None
            } else {
                Some(ctx.create_success_node(tokens))
            },
            Expr::Eof => if tokens.current().is_none() {
                Some(ctx.create_success_node(tokens))
            } else {
                None
            },
            Expr::Any => if tokens.current().is_some() {
                Some(ctx.create_leaf_node(tokens))
            } else {
                None
            },
            Expr::Layer(ref l, ref e) => {
                if let Some(rest) = self.parse_exp_pred(l, tokens, ctx) {
                    let mut result = ctx.create_composite_node(None);
                    let layer = tokens.prefix(rest);
                    if let Some((layer_contents, mut leftovers)) = self.parse_exp(e, layer, ctx) {
                        ctx.push_child(&mut result, layer_contents);
                        if leftovers.current().is_some() {
                            let mut error = ctx.create_error_node();
                            while leftovers.current().is_some() {
                                let p = ctx.create_leaf_node(leftovers);
                                ctx.push_child(&mut error, p.0);
                                leftovers = p.1;
                            }
                            ctx.push_child(&mut result, error)
                        }
                    };
                    return Some((result, rest));
                };
                None
            }

            Expr::Rep(ref body) => {
                let mut node = ctx.create_composite_node(None);
                let mut tokens = tokens;
                loop {
                    if let Some((n, t)) = self.parse_exp(body, tokens, ctx) {
                        ctx.push_child(&mut node, n);
                        tokens = t;
                    } else {
                        break;
                    }
                }
                Some((node, tokens))
            }

            Expr::WithSkip(ref first, ref body) => {
                let mut error = ctx.create_error_node();
                let mut result = ctx.create_composite_node(None);
                let mut skipped = false;
                let mut tokens = tokens;
                loop {
                    if tokens.current().is_none() {
                        return None;
                    }
                    if let Some(_) = self.parse_exp_pred(first, tokens, ctx) {
                        if let Some((node, ts)) = self.parse_exp(body, tokens, ctx) {
                            if skipped {
                                ctx.push_child(&mut result, error);
                            }
                            ctx.push_child(&mut result, node);
                            return Some((result, ts));
                        }
                    }

                    skipped = true;
                    let (node, new_tokens) = ctx.create_leaf_node(tokens);
                    tokens = new_tokens;
                    ctx.push_child(&mut error, node);
                }
            }

            Expr::Pratt(ref g) => self.parse_pratt(&*g, tokens, ctx, 0),

            Expr::Enter(idx, ref e) => {
                let idx = idx as usize;
                let old = ctx.contexts[idx];
                ctx.contexts[idx] = true;
                let result = self.parse_exp(&*e, tokens, ctx);
                ctx.contexts[idx] = old;
                result
            }

            Expr::Exit(idx, ref e) => {
                let idx = idx as usize;
                let old = ctx.contexts[idx];
                ctx.contexts[idx] = false;
                let result = self.parse_exp(&*e, tokens, ctx);
                ctx.contexts[idx] = old;
                result
            }

            Expr::IsIn(idx) => if ctx.contexts[idx as usize] {
                Some(ctx.create_success_node(tokens))
            } else {
                None
            },

            Expr::Call(ref body, ref args) => {
                let old = ctx.args;
                for &(arg_pos, ref arg) in args.iter() {
                    let arg = match *arg {
                        Expr::Var(i) => ctx.args[i as usize].unwrap(),
                        _ => arg
                    };

                    ctx.args[arg_pos as usize] = Some(arg);
                }
                let result = self.parse_exp(body, tokens, ctx);
                ctx.args = old;
                result
            }

            Expr::Var(i) => {
                let expr = ctx.args[i as usize].unwrap();
                self.parse_exp(expr, tokens, ctx)
            }

            Expr::PrevIs(ref ts) => {
                if let Some(prev) = ctx.prev {
                    for &t in ts {
                        let t = self.node_type(t);
                        if t == prev {
                            return Some(ctx.create_success_node(tokens));
                        }
                    }
                }
                None
            }
        }
    }

    fn parse_any<'t, 'p, I: Iterator<Item=&'p Expr>>(&'p self, options: I, tokens: TokenSequence<'t>, ctx: &mut Ctx<'p>)
                                                     -> Option<(Node, TokenSequence<'t>)> {
        for p in options {
            if let Some(result) = self.parse_exp(p, tokens, ctx) {
                return Some(result);
            }
        }
        None
    }

    fn parse_pratt<'t, 'p>(&'p self, expr_grammar: &'p [PrattVariant], tokens: TokenSequence<'t>, ctx: &mut Ctx<'p>, min_prior: u32)
                           -> Option<(Node, TokenSequence<'t>)> {
        let (mut lhs, mut tokens) = match self.parse_pratt_prefix(expr_grammar, tokens, ctx) {
            Some(p) => p,
            None => return None,
        };

        'postfix: loop {
            let postfix = expr_grammar.iter().filter_map(|v| {
                match *v {
                    PrattVariant::Postfix { ty, ref op } => {
                        Some((self.node_type(ty), op.as_ref()))
                    }
                    _ => None
                }
            });
            for (ty, op) in postfix {
                if let Some((op_node, rest)) = self.parse_exp(op, tokens, ctx) {
                    let mut node = ctx.create_composite_node(Some(ty));
                    ::std::mem::swap(&mut node, &mut lhs);
                    ctx.push_child(&mut lhs, node);
                    ctx.push_child(&mut lhs, op_node);
                    tokens = rest;
                    ctx.prev = Some(ty);
                    continue 'postfix;
                }
            }
            break;
        }

        'bin: loop {
            let bins = expr_grammar.iter().filter_map(|v| {
                match *v {
                    PrattVariant::Binary { ty, ref op, priority } if priority > min_prior => {
                        Some((self.node_type(ty), op.as_ref(), priority))
                    }
                    _ => None
                }
            });

            for (ty, op, p) in bins {
                if let Some((op_node, rest)) = self.parse_exp(op, tokens, ctx) {
                    if let Some((rhs_node, rest)) = self.parse_pratt(expr_grammar, rest, ctx, p) {
                        let mut node = ctx.create_composite_node(Some(ty));
                        ::std::mem::swap(&mut node, &mut lhs);
                        ctx.push_child(&mut lhs, node);
                        ctx.push_child(&mut lhs, op_node);
                        ctx.push_child(&mut lhs, rhs_node);
                        tokens = rest;
                        ctx.prev = Some(ty);
                        continue 'bin;
                    }
                }
            }
            break;
        }
        Some((lhs, tokens))
    }

    fn parse_pratt_prefix<'t, 'p>(&'p self, expr_grammar: &'p [PrattVariant], tokens: TokenSequence<'t>, ctx: &mut Ctx<'p>)
                                  -> Option<(Node, TokenSequence<'t>)> {
        let prefix = expr_grammar.iter().filter_map(|v| {
            match *v {
                PrattVariant::Prefix { ty, ref op } => Some((self.node_type(ty), op.as_ref())),
                _ => None
            }
        });

        for (ty, op) in prefix {
            if let Some((op_node, rest)) = self.parse_exp(op, tokens, ctx) {
                let mut node = ctx.create_composite_node(Some(ty));
                ctx.push_child(&mut node, op_node);
                if let Some((expr, rest)) = self.parse_pratt(expr_grammar, rest, ctx, 999) {
                    ctx.push_child(&mut node, expr);
                    ctx.prev = Some(ty);
                    return Some((node, rest));
                }
            }
        }

        let atoms = expr_grammar.iter().filter_map(|v| {
            match *v {
                PrattVariant::Atom { ref body } => Some(body.as_ref()),
                _ => None
            }
        });
        self.parse_any(atoms, tokens, ctx)
    }

    fn parse_exp_pred<'t, 'p>(&'p self, expr: &'p Expr, tokens: TokenSequence<'t>, ctx: &mut Ctx<'p>)
                              -> Option<(TokenSequence<'t>)> {
        let old_mode = ctx.predicate_mode;
        ctx.predicate_mode = true;
        let result = self.parse_exp(expr, tokens, ctx);
        ctx.predicate_mode = old_mode;
        result.map(|(_, ts)| ts)
    }

    fn node_type(&self, idx: usize) -> NodeType {
        self.node_types[idx]
    }
}
<commit_msg>Jettison parser<commit_after>use fall_tree::NodeType;

use tree_builder::{Node, TokenSequence};

use {SynRule, Expr, PrattVariant};

pub fn parse(
    node_types: &[NodeType],
    rules: &[SynRule],
    tokens: TokenSequence
) -> (Node, u64) {
    let start_rule = Expr::Rule(0);

    let defs = Defs {
        node_types: node_types,
        rules: rules,
        start_rule: &start_rule
    };

    let mut ctx = Ctx {
        ticks: 0,
        predicate_mode: false,
        contexts: [false; 16],
        args: [None; 16],
        prev: None,
        replacement: None,
    };

    parse_file(&defs, &mut ctx, tokens)
}

struct Defs<'p> {
    node_types: &'p [NodeType],
    rules: &'p [SynRule],
    start_rule: &'p Expr,
}

impl<'r> Defs<'r> {
    fn node_type(&self, idx: usize) -> NodeType {
        self.node_types[idx]
    }
}

struct Ctx<'p> {
    ticks: u64,
    predicate_mode: bool,
    contexts: [bool; 16],
    args: [Option<&'p Expr>; 16],
    prev: Option<NodeType>,
    replacement: Option<NodeType>,
}

impl<'p> Ctx<'p> {
    fn create_composite_node(&mut self, ty: Option<NodeType>) -> Node {
        Node::composite(ty)
    }

    fn create_error_node(&mut self) -> Node {
        Node::error()
    }

    fn create_leaf_node<'t>(&mut self, tokens: TokenSequence<'t>) -> (Node, TokenSequence<'t>) {
        tokens.bump()
    }

    fn create_contextual_leaf_node<'t>(&mut self, tokens: TokenSequence<'t>, ty: NodeType, text: &str)
                                       -> Option<(Node, TokenSequence<'t>)> {
        tokens.bump_by_text(ty, text)
    }

    fn create_success_node<'t>(&mut self, tokens: TokenSequence<'t>) -> (Node, TokenSequence<'t>) {
        Node::success(tokens)
    }

    fn push_child(&self, parent: &mut Node, child: Node) {
        if self.predicate_mode {
            return;
        }
        match child {
            // Microoptimization: don't store empty success nodes
            Node::Composite { ty: None, ref children, .. } if children.is_empty() => return,
            _ => {}
        }
        parent.push_child(child)
    }
}

fn parse_file<'p>(defs: &Defs<'p>, ctx: &mut Ctx<'p>, tokens: TokenSequence) -> (Node, u64) {
    let (mut file_node, mut leftover) =
        parse_exp(defs, ctx, defs.start_rule, tokens)
            .unwrap_or_else(|| {
                let ty = match defs.rules[0].body {
                    Expr::Pub { ty_idx, .. } => defs.node_type(ty_idx),
                    _ => panic!("First rule must be public"),
                };
                (ctx.create_composite_node(Some(ty)), tokens)
            });

    let mut error = ctx.create_error_node();
    let mut skipped = false;
    while leftover.current().is_some() {
        skipped = true;
        let p = ctx.create_leaf_node(leftover);
        leftover = p.1;
        ctx.push_child(&mut error, p.0)
    }
    if skipped {
        ctx.push_child(&mut file_node, error)
    }
    (file_node, ctx.ticks)
}

fn parse_exp<'t, 'p>(defs: &Defs<'p>, ctx: &mut Ctx<'p>, expr: &'p Expr, tokens: TokenSequence<'t>)
                     -> Option<(Node, TokenSequence<'t>)> {
    ctx.ticks += 1;
    match *expr {
        Expr::Pub { ty_idx, ref body, replaceable } => {
            if replaceable {
                ctx.replacement = None;
            }
            match parse_exp(defs, ctx, body, tokens) {
                Some((node, ts)) => {
                    let node_type = match (replaceable, ctx.replacement) {
                        (true, Some(ty)) => ty,
                        _ => defs.node_type(ty_idx),
                    };
                    let mut result = ctx.create_composite_node(Some(node_type));
                    ctx.push_child(&mut result, node);

                    ctx.prev = Some(node_type);
                    Some((result, ts))
                }
                _ => {
                    None
                }
            }
        }
        Expr::PubReplace { ty_idx, ref body } => {
            match parse_exp(defs, ctx, body, tokens) {
                Some((node, ts)) => {
                    let node_type = defs.node_type(ty_idx);
                    ctx.replacement = Some(node_type);
                    Some((node, ts))
                }
                _ => {
                    None
                }
            }
        }

        Expr::Or(ref parts) => parse_any(defs, ctx, parts.iter(), tokens),

        Expr::And(ref parts, commit) => {
            let mut node = ctx.create_composite_node(None);
            let commit = commit.unwrap_or(parts.len());
            let mut tokens = tokens;
            for (i, p) in parts.iter().enumerate() {
                if let Some((n, ts)) = parse_exp(defs, ctx, p, tokens) {
                    tokens = ts;
                    ctx.push_child(&mut node, n);
                } else {
                    if i < commit {
                        return None;
                    }
                    let error_node = ctx.create_error_node();
                    ctx.push_child(&mut node, error_node);
                    break
                }
            }
            Some((node, tokens))
        }

        Expr::Rule(id) => parse_exp(defs, ctx, &defs.rules[id].body, tokens),

        Expr::Token(ty) => {
            if let Some(current) = tokens.current() {
                if defs.node_type(ty) == current.ty {
                    return Some(ctx.create_leaf_node(tokens));
                }
            }
            None
        }

        Expr::ContextualToken(ty, ref text) => {
            ctx.create_contextual_leaf_node(tokens, defs.node_type(ty), &*text)
        }

        Expr::Opt(ref body) => parse_exp(defs, ctx, body, tokens).or_else(|| {
            Some(ctx.create_success_node(tokens))
        }),
        Expr::Not(ref e) => if parse_exp(defs, ctx, e, tokens).is_some() {
            None
        } else {
            Some(ctx.create_success_node(tokens))
        },
        Expr::Eof => if tokens.current().is_none() {
            Some(ctx.create_success_node(tokens))
        } else {
            None
        },
        Expr::Any => if tokens.current().is_some() {
            Some(ctx.create_leaf_node(tokens))
        } else {
            None
        },
        Expr::Layer(ref l, ref e) => {
            if let Some(rest) = parse_exp_pred(defs, ctx, l, tokens) {
                let mut result = ctx.create_composite_node(None);
                let layer = tokens.prefix(rest);
                if let Some((layer_contents, mut leftovers)) = parse_exp(defs, ctx, e, layer) {
                    ctx.push_child(&mut result, layer_contents);
                    if leftovers.current().is_some() {
                        let mut error = ctx.create_error_node();
                        while leftovers.current().is_some() {
                            let p = ctx.create_leaf_node(leftovers);
                            ctx.push_child(&mut error, p.0);
                            leftovers = p.1;
                        }
                        ctx.push_child(&mut result, error)
                    }
                };
                return Some((result, rest));
            };
            None
        }

        Expr::Rep(ref body) => {
            let mut node = ctx.create_composite_node(None);
            let mut tokens = tokens;
            loop {
                if let Some((n, t)) = parse_exp(defs, ctx, body, tokens) {
                    ctx.push_child(&mut node, n);
                    tokens = t;
                } else {
                    break;
                }
            }
            Some((node, tokens))
        }

        Expr::WithSkip(ref first, ref body) => {
            let mut error = ctx.create_error_node();
            let mut result = ctx.create_composite_node(None);
            let mut skipped = false;
            let mut tokens = tokens;
            loop {
                if tokens.current().is_none() {
                    return None;
                }
                if let Some(_) = parse_exp_pred(defs, ctx, first, tokens) {
                    if let Some((node, ts)) = parse_exp(defs, ctx, body, tokens) {
                        if skipped {
                            ctx.push_child(&mut result, error);
                        }
                        ctx.push_child(&mut result, node);
                        return Some((result, ts));
                    }
                }

                skipped = true;
                let (node, new_tokens) = ctx.create_leaf_node(tokens);
                tokens = new_tokens;
                ctx.push_child(&mut error, node);
            }
        }

        Expr::Pratt(ref g) => parse_pratt(defs, ctx, &*g, tokens, 0),

        Expr::Enter(idx, ref e) => {
            let idx = idx as usize;
            let old = ctx.contexts[idx];
            ctx.contexts[idx] = true;
            let result = parse_exp(defs, ctx, &*e, tokens);
            ctx.contexts[idx] = old;
            result
        }

        Expr::Exit(idx, ref e) => {
            let idx = idx as usize;
            let old = ctx.contexts[idx];
            ctx.contexts[idx] = false;
            let result = parse_exp(defs, ctx, &*e, tokens);
            ctx.contexts[idx] = old;
            result
        }

        Expr::IsIn(idx) => if ctx.contexts[idx as usize] {
            Some(ctx.create_success_node(tokens))
        } else {
            None
        },

        Expr::Call(ref body, ref args) => {
            let old = ctx.args;
            for &(arg_pos, ref arg) in args.iter() {
                let arg = match *arg {
                    Expr::Var(i) => ctx.args[i as usize].unwrap(),
                    _ => arg
                };

                ctx.args[arg_pos as usize] = Some(arg);
            }
            let result = parse_exp(defs, ctx, body, tokens);
            ctx.args = old;
            result
        }

        Expr::Var(i) => {
            let expr = ctx.args[i as usize].unwrap();
            parse_exp(defs, ctx, expr, tokens)
        }

        Expr::PrevIs(ref ts) => {
            if let Some(prev) = ctx.prev {
                for &t in ts {
                    let t = defs.node_type(t);
                    if t == prev {
                        return Some(ctx.create_success_node(tokens));
                    }
                }
            }
            None
        }
    }
}

fn parse_any<'t, 'p, I: Iterator<Item=&'p Expr>>(
    defs: &Defs<'p>,
    ctx: &mut Ctx<'p>,
    options: I,
    tokens: TokenSequence<'t>
) -> Option<(Node, TokenSequence<'t>)> {
    for p in options {
        if let Some(result) = parse_exp(defs, ctx, p, tokens) {
            return Some(result);
        }
    }
    None
}

fn parse_pratt<'t, 'p>(defs: &Defs<'p>, ctx: &mut Ctx<'p>, expr_grammar: &'p [PrattVariant], tokens: TokenSequence<'t>, min_prior: u32)
                       -> Option<(Node, TokenSequence<'t>)> {
    let (mut lhs, mut tokens) = match parse_pratt_prefix(defs, ctx, expr_grammar, tokens) {
        Some(p) => p,
        None => return None,
    };

    'postfix: loop {
        let postfix = expr_grammar.iter().filter_map(|v| {
            match *v {
                PrattVariant::Postfix { ty, ref op } => {
                    Some((defs.node_type(ty), op.as_ref()))
                }
                _ => None
            }
        });
        for (ty, op) in postfix {
            if let Some((op_node, rest)) = parse_exp(defs, ctx, op, tokens) {
                let mut node = ctx.create_composite_node(Some(ty));
                ::std::mem::swap(&mut node, &mut lhs);
                ctx.push_child(&mut lhs, node);
                ctx.push_child(&mut lhs, op_node);
                tokens = rest;
                ctx.prev = Some(ty);
                continue 'postfix;
            }
        }
        break;
    }

    'bin: loop {
        let bins = expr_grammar.iter().filter_map(|v| {
            match *v {
                PrattVariant::Binary { ty, ref op, priority } if priority > min_prior => {
                    Some((defs.node_type(ty), op.as_ref(), priority))
                }
                _ => None
            }
        });

        for (ty, op, p) in bins {
            if let Some((op_node, rest)) = parse_exp(defs, ctx, op, tokens) {
                if let Some((rhs_node, rest)) = parse_pratt(defs, ctx, expr_grammar, rest, p) {
                    let mut node = ctx.create_composite_node(Some(ty));
                    ::std::mem::swap(&mut node, &mut lhs);
                    ctx.push_child(&mut lhs, node);
                    ctx.push_child(&mut lhs, op_node);
                    ctx.push_child(&mut lhs, rhs_node);
                    tokens = rest;
                    ctx.prev = Some(ty);
                    continue 'bin;
                }
            }
        }
        break;
    }
    Some((lhs, tokens))
}

fn parse_pratt_prefix<'t, 'p>(defs: &Defs<'p>, ctx: &mut Ctx<'p>, expr_grammar: &'p [PrattVariant], tokens: TokenSequence<'t>)
                              -> Option<(Node, TokenSequence<'t>)> {
    let prefix = expr_grammar.iter().filter_map(|v| {
        match *v {
            PrattVariant::Prefix { ty, ref op } => Some((defs.node_type(ty), op.as_ref())),
            _ => None
        }
    });

    for (ty, op) in prefix {
        if let Some((op_node, rest)) = parse_exp(defs, ctx, op, tokens) {
            let mut node = ctx.create_composite_node(Some(ty));
            ctx.push_child(&mut node, op_node);
            if let Some((expr, rest)) = parse_pratt(defs, ctx, expr_grammar, rest, 999) {
                ctx.push_child(&mut node, expr);
                ctx.prev = Some(ty);
                return Some((node, rest));
            }
        }
    }

    let atoms = expr_grammar.iter().filter_map(|v| {
        match *v {
            PrattVariant::Atom { ref body } => Some(body.as_ref()),
            _ => None
        }
    });
    parse_any(defs, ctx, atoms, tokens)
}

fn parse_exp_pred<'t, 'p>(defs: &Defs<'p>, ctx: &mut Ctx<'p>, expr: &'p Expr, tokens: TokenSequence<'t>)
                          -> Option<(TokenSequence<'t>)> {
    let old_mode = ctx.predicate_mode;
    ctx.predicate_mode = true;
    let result = parse_exp(defs, ctx, expr, tokens);
    ctx.predicate_mode = old_mode;
    result.map(|(_, ts)| ts)
}
<|endoftext|>


<commit_before>use ast::{TIdent, TNumber, TString, TSemicolon, TComment, TColon, TDot, TEqual, TOpenParen, TCloseParen, TComma, TOpenBlock, TCloseBlock, TOpenArray, TCloseArray, TQuestion, TNumOp, TBitOp, TCompOp, TLogOp, TArrow};
use ast::{OpAdd, OpSub, OpMul, OpDiv, OpMod};
use ast::{BitAnd, BitOr, BitXor};
use ast::{CompEqual, CompNotEqual, CompLessThan, CompGreaterThan, CompLessThanOrEqual, CompGreaterThanOrEqual};
use ast::{LogAnd, LogOr};
use ast::{Token, TokenData};
use std::io::{BufReader, BufferedReader, Reader};
use std::strbuf::StrBuf;
use std::char::from_u32;
use std::num::from_str_radix;
use std::io::{IoResult, EndOfFile};
use std::char::is_whitespace;
#[deriving(Clone)]
#[deriving(Eq)]
#[deriving(Show)]
/// The type of string used
pub enum StringType {
	/// Double-quoted
	DoubleQuote,
	/// Single-quoted
	SingleQuote
}
#[deriving(Clone)]
#[deriving(Eq)]
#[deriving(Show)]
/// The type of comment used
pub enum CommentType {
	/// Multi-line comment
	MultiLineComment,
	/// Single-line comment
	SingleLineComment
}
#[deriving(Clone, Eq, Show)]
/// The type of number used
pub enum NumberType {
	/// Decimal number
	DecimalNumber,
	/// Hexadecimal number
	HexadecimalNumber
}
/// The Javascript Lexer
pub struct Lexer {
	/// The list of tokens generated so far
	pub tokens : Vec<Token>,
	/// The string buffer for identities
	ident_buffer : StrBuf,
	/// The string buffer for strings
	string_buffer : StrBuf,
	/// The string buffer for comments
	comment_buffer : StrBuf,
	/// The string buffer for numbers
	num_buffer : StrBuf,
	/// The kind of string - i.e. double quote or single quote or none if it isn't in a string
	string_start : Option<StringType>,
	/// The kind of comment
	current_comment : Option<CommentType>,
	/// The kind of number
	current_number : Option<NumberType>,
	/// If a backwards slash has just been read
	escaped : bool,
	/// The current line number
	line_number : uint,
	/// The current column number
	column_number : uint
}
impl Lexer {
	/// Creates a new lexer with empty buffers
	pub fn new() -> ~Lexer {
		return ~Lexer {
			tokens: Vec::new(),
			ident_buffer: StrBuf::with_capacity(32),
			string_buffer: StrBuf::with_capacity(256),
			num_buffer: StrBuf::with_capacity(16),
			comment_buffer: StrBuf::with_capacity(32),
			string_start: None,
			current_comment: None,
			current_number: None,
			escaped: false,
			line_number: 1,
			column_number: 0
		};
	}
	fn clear_buffer(&mut self) {
		if self.ident_buffer.len() > 0 {
			let ident = self.ident_buffer.clone().into_owned();
			self.push_token(TIdent(ident));
			self.ident_buffer.truncate(0);
		}
		if self.current_number.is_some() {
			let num : f64 = match self.current_number {
				Some(HexadecimalNumber) => from_str_radix(self.num_buffer.as_slice(), 16).unwrap(),
				Some(DecimalNumber) => from_str(self.num_buffer.as_slice()).unwrap(),
				None => unreachable!()
			};
			self.push_token(TNumber(num));
			self.num_buffer.truncate(0);
			self.current_number = None;
		}
	}
	fn push_token(&mut self, tk:TokenData) {
		self.tokens.push(Token::new(tk, self.line_number, self.column_number))
	}
	/// Processes an input stream from a string into an array of tokens
	pub fn lex_str(&mut self, script:~str) -> IoResult<()> {
		let script_bytes:&[u8] = script.as_bytes();
		let reader = BufReader::new(script_bytes);
		let buf_reader = BufferedReader::new(reader);
		self.lex(buf_reader)
	}
	/// Processes an input stream from a BufferedReader into an array of tokens
	pub fn lex<R : Reader>(&mut self, mut reader : BufferedReader<R>) -> IoResult<()> {
		let mut iter = reader.chars().peekable();
		loop {
			let ch = match iter.next() {
				Some(Ok(ch)) => ch,
				Some(Err(ref err)) if err.kind == EndOfFile => break,
				Some(Err(err)) => return Err(err),
				None => break
			};
			self.column_number += 1;
			match ch {
				_ if self.escaped => {
					self.escaped = false;
					if ch != '\n' {
						self.string_buffer.push_char(match ch {
							'n' => '\n',
							'r' => '\r',
							't' => '\t',
							'b' => '\x08',
							'f' => '\x0c',
							'0' => '\0',
							'x' => {
								let mut nums = ~"";
								for _ in range(0, 2) {
									nums = format!("{}{}", nums, try!(iter.next().unwrap().clone()));
								}
								self.column_number += 2;
								let as_num = match from_str_radix(nums, 16) {
									Some(v) => v,
									None => 0
								};
								match from_u32(as_num) {
									Some(v) => v,
									None => fail!("Line {}, Column {}: {} is not a valid unicode scalar value", self.line_number, self.column_number, as_num)
								}
							},
							'u' => {
								let mut nums = ~"";
								for _ in range(0, 4) {
									nums = format!("{}{}", nums, try!(iter.next().unwrap().clone()));
								}
								self.column_number += 4;
								let as_num = match from_str_radix(nums, 16) {
									Some(v) => v,
									None => 0
								};
								match from_u32(as_num) {
									Some(v) => v,
									None => fail!("Line {}, Column {}: {} is not a valid unicode scalar value", self.line_number, self.column_number, as_num)
								}
							},
							'\'' if self.string_start == Some(SingleQuote) => '\'',
							'"' if self.string_start == Some(DoubleQuote) => '"',
							_ => fail!("Line {}, Column {}: Invalid escape `{}`", self.line_number, self.column_number, ch)
						});
					}
				},
				'\n' if self.current_comment == Some(SingleLineComment) => {
					let comment = self.comment_buffer.clone().into_owned();
					self.push_token(TComment(comment));
					self.comment_buffer.truncate(0);
					self.current_comment = None;
				},
				'*' if self.current_comment == Some(MultiLineComment) && try!(iter.peek().unwrap().clone()) == '/' => {
					iter.next();
					let comment = self.comment_buffer.clone().into_owned();
					self.push_token(TComment(comment));
					self.comment_buffer.truncate(0);
					self.current_comment = None;
				},
				_ if self.current_comment.is_some() => {
					self.comment_buffer.push_char(ch);
				},
				'"' if self.string_start == Some(DoubleQuote) => {
					self.string_start = None;
					let string = self.string_buffer.clone().into_owned();
					self.push_token(TString(string));
					self.string_buffer.truncate(0);
				},
				'\'' if self.string_start == Some(SingleQuote) => {
					self.string_start = None;
					let string = self.string_buffer.clone().into_owned();
					self.push_token(TString(string));
					self.string_buffer.truncate(0);
				},
				'\\' if self.string_start.is_some() => self.escaped = true,
				_ if self.string_start.is_some() => self.string_buffer.push_char(ch),
				'"' if self.string_start.is_none() => self.string_start = Some(DoubleQuote),
				'0' if try!(iter.peek().unwrap().clone()) == 'x' => {
					iter.next();
					self.current_number = Some(HexadecimalNumber);
				},
				'0'.. '9' if self.string_start.is_none() && self.ident_buffer.len() == 0 => {
					self.num_buffer.push_char(ch);
					self.current_number = Some(DecimalNumber);
				},
				'A'.. 'F' | 'a' .. 'f' if self.current_number == Some(HexadecimalNumber) => {
					self.num_buffer.push_char(ch);
				},
				'\'' if self.string_start.is_none() => self.string_start = Some(SingleQuote),
				'.' if self.current_number.is_some() && !self.num_buffer.as_slice().contains(".") => {
					self.num_buffer.push_char(ch);
				},
				';' => {
					self.clear_buffer();
					self.push_token(TSemicolon);
				},
				':' => {
					self.clear_buffer();
					self.push_token(TColon);
				},
				'.' => {
					self.clear_buffer();
					self.push_token(TDot);
				},
				'(' => {
					self.clear_buffer();
					self.push_token(TOpenParen);
				},
				')' => {
					self.clear_buffer();
					self.push_token(TCloseParen);
				},
				',' => {
					self.clear_buffer();
					self.push_token(TComma);
				},
				'{' => {
					self.clear_buffer();
					self.push_token(TOpenBlock);
				},
				'}' => {
					self.clear_buffer();
					self.push_token(TCloseBlock);
				},
				'[' => {
					self.clear_buffer();
					self.push_token(TOpenArray);
				},
				']' => {
					self.clear_buffer();
					self.push_token(TCloseArray);
				},
				'?' => {
					self.clear_buffer();
					self.push_token(TQuestion);
				},
				'/' if try!(iter.peek().unwrap().clone()) == '/' => {
					iter.next();
					self.current_comment = Some(SingleLineComment);
				},
				'/' if try!(iter.peek().unwrap().clone()) == '*' => {
					iter.next();
					self.current_comment = Some(MultiLineComment);
				},
				'/' => {
					self.clear_buffer();
					self.push_token(TNumOp(OpDiv));
				},
				'*' => {
					self.clear_buffer();
					self.push_token(TNumOp(OpMul));
				},
				'+' => {
					self.clear_buffer();
					self.push_token(TNumOp(OpAdd));
				},
				'-' => {
					self.clear_buffer();
					self.push_token(TNumOp(OpSub));
				},
				'%' => {
					self.clear_buffer();
					self.push_token(TNumOp(OpMod));
				},
				'|' if try!(iter.peek().unwrap().clone()) == '|' => {
					iter.next();
					self.clear_buffer();
					self.push_token(TLogOp(LogOr));
				},
				'|' => {
					self.clear_buffer();
					self.push_token(TBitOp(BitOr));
				},
				'&' if try!(iter.peek().unwrap().clone()) == '&' => {
					iter.next();
					self.clear_buffer();
					self.push_token(TLogOp(LogAnd));
				},
				'&' => {
					self.clear_buffer();
					self.push_token(TBitOp(BitAnd));
				},
				'^' => {
					self.clear_buffer();
					self.push_token(TBitOp(BitXor));
				},
				'=' if try!(iter.peek().unwrap().clone()) == '>' => {
					iter.next();
					self.clear_buffer();
					self.push_token(TArrow);
				},
				'=' if try!(iter.peek().unwrap().clone()) == '=' => {
					iter.next();
					self.clear_buffer();
					self.push_token(TCompOp(CompEqual));
				},
				'=' => {
					self.clear_buffer();
					self.push_token(TEqual);
				},
				'<' if try!(iter.peek().unwrap().clone()) == '=' => {
					iter.next();
					self.clear_buffer();
					self.push_token(TCompOp(CompLessThanOrEqual));
				},
				'<' => {
					self.clear_buffer();
					self.push_token(TCompOp(CompLessThan));
				},
				'>' if try!(iter.peek().unwrap().clone()) == '=' => {
					iter.next();
					self.clear_buffer();
					self.push_token(TCompOp(CompGreaterThanOrEqual));
				},
				'>' => {
					self.clear_buffer();
					self.push_token(TCompOp(CompGreaterThan));
				},
				'!' if try!(iter.peek().unwrap().clone()) == '=' => {
					iter.next();
					self.clear_buffer();
					self.push_token(TCompOp(CompNotEqual));
				},
				'\n' => {
					self.clear_buffer();
					self.line_number += 1;
					self.column_number = 0;
				},
				'\r' => {
					self.clear_buffer();
					self.column_number = 0;
				},
				_ if is_whitespace(ch) => self.clear_buffer(),
				_ => self.ident_buffer.push_char(ch)
			};
		}
		self.clear_buffer();
		Ok(())
	}
}<commit_msg>Octal constants<commit_after>use ast::{TIdent, TNumber, TString, TSemicolon, TComment, TColon, TDot, TEqual, TOpenParen, TCloseParen, TComma, TOpenBlock, TCloseBlock, TOpenArray, TCloseArray, TQuestion, TNumOp, TBitOp, TCompOp, TLogOp, TArrow};
use ast::{OpAdd, OpSub, OpMul, OpDiv, OpMod};
use ast::{BitAnd, BitOr, BitXor};
use ast::{CompEqual, CompNotEqual, CompLessThan, CompGreaterThan, CompLessThanOrEqual, CompGreaterThanOrEqual};
use ast::{LogAnd, LogOr};
use ast::{Token, TokenData};
use std::io::{BufReader, BufferedReader, Reader};
use std::strbuf::StrBuf;
use std::char::from_u32;
use std::num::from_str_radix;
use std::io::{IoResult, EndOfFile};
use std::char::is_whitespace;
#[deriving(Clone)]
#[deriving(Eq)]
#[deriving(Show)]
/// The type of string used
pub enum StringType {
	/// Double-quoted
	DoubleQuote,
	/// Single-quoted
	SingleQuote
}
#[deriving(Clone)]
#[deriving(Eq)]
#[deriving(Show)]
/// The type of comment used
pub enum CommentType {
	/// Multi-line comment
	MultiLineComment,
	/// Single-line comment
	SingleLineComment
}
#[deriving(Clone, Eq, Show)]
/// The type of number used
pub enum NumberType {
	/// Decimal number
	DecimalNumber,
	/// Hexadecimal number
	HexadecimalNumber,
	/// Octal number
	OctalNumber
}
/// The Javascript Lexer
pub struct Lexer {
	/// The list of tokens generated so far
	pub tokens : Vec<Token>,
	/// The string buffer for identities
	ident_buffer : StrBuf,
	/// The string buffer for strings
	string_buffer : StrBuf,
	/// The string buffer for comments
	comment_buffer : StrBuf,
	/// The string buffer for numbers
	num_buffer : StrBuf,
	/// The kind of string - i.e. double quote or single quote or none if it isn't in a string
	string_start : Option<StringType>,
	/// The kind of comment
	current_comment : Option<CommentType>,
	/// The kind of number
	current_number : Option<NumberType>,
	/// If a backwards slash has just been read
	escaped : bool,
	/// The current line number
	line_number : uint,
	/// The current column number
	column_number : uint
}
impl Lexer {
	/// Creates a new lexer with empty buffers
	pub fn new() -> ~Lexer {
		return ~Lexer {
			tokens: Vec::new(),
			ident_buffer: StrBuf::with_capacity(32),
			string_buffer: StrBuf::with_capacity(256),
			num_buffer: StrBuf::with_capacity(16),
			comment_buffer: StrBuf::with_capacity(32),
			string_start: None,
			current_comment: None,
			current_number: None,
			escaped: false,
			line_number: 1,
			column_number: 0
		};
	}
	fn clear_buffer(&mut self) {
		if self.ident_buffer.len() > 0 {
			let ident = self.ident_buffer.clone().into_owned();
			self.push_token(TIdent(ident));
			self.ident_buffer.truncate(0);
		}
		if self.current_number.is_some() {
			let num : f64 = match self.current_number {
				Some(HexadecimalNumber) => from_str_radix(self.num_buffer.as_slice(), 16).unwrap(),
				Some(OctalNumber) => from_str_radix(self.num_buffer.as_slice(), 8).unwrap(),
				Some(DecimalNumber) => from_str(self.num_buffer.as_slice()).unwrap(),
				None => unreachable!()
			};
			self.push_token(TNumber(num));
			self.num_buffer.truncate(0);
			self.current_number = None;
		}
	}
	fn push_token(&mut self, tk:TokenData) {
		self.tokens.push(Token::new(tk, self.line_number, self.column_number))
	}
	/// Processes an input stream from a string into an array of tokens
	pub fn lex_str(&mut self, script:~str) -> IoResult<()> {
		let script_bytes:&[u8] = script.as_bytes();
		let reader = BufReader::new(script_bytes);
		let buf_reader = BufferedReader::new(reader);
		self.lex(buf_reader)
	}
	/// Processes an input stream from a BufferedReader into an array of tokens
	pub fn lex<R : Reader>(&mut self, mut reader : BufferedReader<R>) -> IoResult<()> {
		let mut iter = reader.chars().peekable();
		loop {
			let ch = match iter.next() {
				Some(Ok(ch)) => ch,
				Some(Err(ref err)) if err.kind == EndOfFile => break,
				Some(Err(err)) => return Err(err),
				None => break
			};
			self.column_number += 1;
			match ch {
				_ if self.escaped => {
					self.escaped = false;
					if ch != '\n' {
						self.string_buffer.push_char(match ch {
							'n' => '\n',
							'r' => '\r',
							't' => '\t',
							'b' => '\x08',
							'f' => '\x0c',
							'0' => '\0',
							'x' => {
								let mut nums = ~"";
								for _ in range(0, 2) {
									nums = format!("{}{}", nums, try!(iter.next().unwrap().clone()));
								}
								self.column_number += 2;
								let as_num = match from_str_radix(nums, 16) {
									Some(v) => v,
									None => 0
								};
								match from_u32(as_num) {
									Some(v) => v,
									None => fail!("Line {}, Column {}: {} is not a valid unicode scalar value", self.line_number, self.column_number, as_num)
								}
							},
							'u' => {
								let mut nums = ~"";
								for _ in range(0, 4) {
									nums = format!("{}{}", nums, try!(iter.next().unwrap().clone()));
								}
								self.column_number += 4;
								let as_num = match from_str_radix(nums, 16) {
									Some(v) => v,
									None => 0
								};
								match from_u32(as_num) {
									Some(v) => v,
									None => fail!("Line {}, Column {}: {} is not a valid unicode scalar value", self.line_number, self.column_number, as_num)
								}
							},
							'\'' if self.string_start == Some(SingleQuote) => '\'',
							'"' if self.string_start == Some(DoubleQuote) => '"',
							_ => fail!("Line {}, Column {}: Invalid escape `{}`", self.line_number, self.column_number, ch)
						});
					}
				},
				'\n' if self.current_comment == Some(SingleLineComment) => {
					let comment = self.comment_buffer.clone().into_owned();
					self.push_token(TComment(comment));
					self.comment_buffer.truncate(0);
					self.current_comment = None;
				},
				'*' if self.current_comment == Some(MultiLineComment) && try!(iter.peek().unwrap().clone()) == '/' => {
					iter.next();
					let comment = self.comment_buffer.clone().into_owned();
					self.push_token(TComment(comment));
					self.comment_buffer.truncate(0);
					self.current_comment = None;
				},
				_ if self.current_comment.is_some() => {
					self.comment_buffer.push_char(ch);
				},
				'"' if self.string_start == Some(DoubleQuote) => {
					self.string_start = None;
					let string = self.string_buffer.clone().into_owned();
					self.push_token(TString(string));
					self.string_buffer.truncate(0);
				},
				'\'' if self.string_start == Some(SingleQuote) => {
					self.string_start = None;
					let string = self.string_buffer.clone().into_owned();
					self.push_token(TString(string));
					self.string_buffer.truncate(0);
				},
				'\\' if self.string_start.is_some() => self.escaped = true,
				_ if self.string_start.is_some() => self.string_buffer.push_char(ch),
				'"' if self.string_start.is_none() => self.string_start = Some(DoubleQuote),
				'0' if try!(iter.peek().unwrap().clone()) == 'x' => {
					iter.next();
					self.current_number = Some(HexadecimalNumber);
				},
				'0' if self.string_start.is_none() && self.ident_buffer.len() == 0 => {
					self.num_buffer.push_char(ch);
					self.current_number = Some(OctalNumber);
				},
				'8' .. '9' if self.current_number == Some(OctalNumber) => {
					self.num_buffer.push_char(ch);
					self.current_number = Some(DecimalNumber);
				},
				'0'.. '9' if self.string_start.is_none() && self.ident_buffer.len() == 0 => {
					self.num_buffer.push_char(ch);
					self.current_number = Some(DecimalNumber);
				},
				'A'.. 'F' | 'a' .. 'f' if self.current_number == Some(HexadecimalNumber) => {
					self.num_buffer.push_char(ch);
				},
				'\'' if self.string_start.is_none() => self.string_start = Some(SingleQuote),
				'.' if self.current_number.is_some() && !self.num_buffer.as_slice().contains(".") => {
					self.num_buffer.push_char(ch);
				},
				';' => {
					self.clear_buffer();
					self.push_token(TSemicolon);
				},
				':' => {
					self.clear_buffer();
					self.push_token(TColon);
				},
				'.' => {
					self.clear_buffer();
					self.push_token(TDot);
				},
				'(' => {
					self.clear_buffer();
					self.push_token(TOpenParen);
				},
				')' => {
					self.clear_buffer();
					self.push_token(TCloseParen);
				},
				',' => {
					self.clear_buffer();
					self.push_token(TComma);
				},
				'{' => {
					self.clear_buffer();
					self.push_token(TOpenBlock);
				},
				'}' => {
					self.clear_buffer();
					self.push_token(TCloseBlock);
				},
				'[' => {
					self.clear_buffer();
					self.push_token(TOpenArray);
				},
				']' => {
					self.clear_buffer();
					self.push_token(TCloseArray);
				},
				'?' => {
					self.clear_buffer();
					self.push_token(TQuestion);
				},
				'/' if try!(iter.peek().unwrap().clone()) == '/' => {
					iter.next();
					self.current_comment = Some(SingleLineComment);
				},
				'/' if try!(iter.peek().unwrap().clone()) == '*' => {
					iter.next();
					self.current_comment = Some(MultiLineComment);
				},
				'/' => {
					self.clear_buffer();
					self.push_token(TNumOp(OpDiv));
				},
				'*' => {
					self.clear_buffer();
					self.push_token(TNumOp(OpMul));
				},
				'+' => {
					self.clear_buffer();
					self.push_token(TNumOp(OpAdd));
				},
				'-' => {
					self.clear_buffer();
					self.push_token(TNumOp(OpSub));
				},
				'%' => {
					self.clear_buffer();
					self.push_token(TNumOp(OpMod));
				},
				'|' if try!(iter.peek().unwrap().clone()) == '|' => {
					iter.next();
					self.clear_buffer();
					self.push_token(TLogOp(LogOr));
				},
				'|' => {
					self.clear_buffer();
					self.push_token(TBitOp(BitOr));
				},
				'&' if try!(iter.peek().unwrap().clone()) == '&' => {
					iter.next();
					self.clear_buffer();
					self.push_token(TLogOp(LogAnd));
				},
				'&' => {
					self.clear_buffer();
					self.push_token(TBitOp(BitAnd));
				},
				'^' => {
					self.clear_buffer();
					self.push_token(TBitOp(BitXor));
				},
				'=' if try!(iter.peek().unwrap().clone()) == '>' => {
					iter.next();
					self.clear_buffer();
					self.push_token(TArrow);
				},
				'=' if try!(iter.peek().unwrap().clone()) == '=' => {
					iter.next();
					self.clear_buffer();
					self.push_token(TCompOp(CompEqual));
				},
				'=' => {
					self.clear_buffer();
					self.push_token(TEqual);
				},
				'<' if try!(iter.peek().unwrap().clone()) == '=' => {
					iter.next();
					self.clear_buffer();
					self.push_token(TCompOp(CompLessThanOrEqual));
				},
				'<' => {
					self.clear_buffer();
					self.push_token(TCompOp(CompLessThan));
				},
				'>' if try!(iter.peek().unwrap().clone()) == '=' => {
					iter.next();
					self.clear_buffer();
					self.push_token(TCompOp(CompGreaterThanOrEqual));
				},
				'>' => {
					self.clear_buffer();
					self.push_token(TCompOp(CompGreaterThan));
				},
				'!' if try!(iter.peek().unwrap().clone()) == '=' => {
					iter.next();
					self.clear_buffer();
					self.push_token(TCompOp(CompNotEqual));
				},
				'\n' => {
					self.clear_buffer();
					self.line_number += 1;
					self.column_number = 0;
				},
				'\r' => {
					self.clear_buffer();
					self.column_number = 0;
				},
				_ if is_whitespace(ch) => self.clear_buffer(),
				_ => self.ident_buffer.push_char(ch)
			};
		}
		self.clear_buffer();
		Ok(())
	}
}<|endoftext|>


<commit_before>extern crate futures;
extern crate tokio_core;

use std::mem;
use std::thread;
use std::sync::Arc;
use std::time::Duration;

use futures::{Stream, Future, Poll, Async};
use futures::sync::{mpsc, oneshot};
use tokio_core::reactor::Core;

#[derive(Clone, Debug)]
pub enum LoadError {
    Receiver,
    LoadCanceled,
    Custom(String),
}

impl LoadError {
    pub fn custom<S: Into<String>>(s: S) -> LoadError {
        LoadError::Custom(s.into())
    }
}

pub trait BatchFn<K, V> {
    type Error: Into<LoadError>;
    fn load(&self, keys: &Vec<K>) -> Box<Future<Item = Vec<V>, Error = Self::Error>>;

    fn max_batch_size(&self) -> usize {
        200
    }
}

#[derive(Clone)]
pub struct Loader<K, V> {
    tx: Arc<mpsc::UnboundedSender<Message<K, Result<V, LoadError>>>>,
}

impl<K, V> Loader<K, V> {
    pub fn load(&self, key: K) -> LoadFuture<K, V> {
        let (tx, rx) = oneshot::channel();
        let msg = Message::LoadOne {
            key: key,
            reply: tx,
        };
        // This call may not completed as thread are parked in Future
        self.tx.send(msg).unwrap();
        // TODO: fix it, make sure send completed
        thread::sleep(Duration::from_millis(50));
        LoadFuture {
            rx: rx,
            loader: Loader { tx: self.tx.clone() },
        }
    }

    /// Called when poll LoadFuture return NotReady
    fn dispatch_rest(&self) {
        // This call may not completed as thread are parked in Future
        self.tx.send(Message::LoadRest).unwrap();
        // TODO: fix it, make sure send completed
        thread::sleep(Duration::from_millis(50));
    }
}

impl<K, V> Loader<K, V>
    where K: 'static + Send,
          V: 'static + Send
{
    pub fn new<F>(batch_fn: F) -> Loader<K, V>
        where F: 'static + Send + BatchFn<K, V>
    {
        assert!(batch_fn.max_batch_size() > 0);

        let (tx, rx) = mpsc::unbounded();
        let inner_handle = Arc::new(tx);
        let loader = Loader { tx: inner_handle };

        // worker thread to call batch_fn for load requests
        thread::spawn(move || {
            let batch_fn = Arc::new(batch_fn);
            let mut core = Core::new().unwrap();
            let handle = core.handle();

            let inner = Inner {
                rx: rx,
                max_batch_size: batch_fn.max_batch_size(),
                items: Vec::with_capacity(10),
                err: None,
            };

            let load_batch = batch_fn.clone();
            let loader =
                inner.for_each(move |requests: Vec<(K, oneshot::Sender<Result<V, LoadError>>)>| {
                    let (keys, replys) = requests.into_iter()
                        .fold((Vec::new(), Vec::new()), |mut soa, i| {
                            soa.0.push(i.0);
                            soa.1.push(i.1);
                            soa
                        });
                    let batch_job = load_batch.load(&keys).then(move |x| {
                        match x {
                            Ok(values) => {
                                for r in replys.into_iter().zip(values) {
                                    r.0.complete(Ok(r.1));
                                }
                            }
                            Err(e) => {
                                let err = e.into();
                                for r in replys {
                                    r.complete(Err(err.clone()));
                                }
                            }
                        };
                        Ok(())
                    });
                    handle.spawn(batch_job);
                    Ok(())
                });
            core.run(loader).unwrap();

            // Run until all batch jobs completed
            core.turn(None);
        });

        loader
    }
}

pub struct LoadFuture<K, V> {
    rx: oneshot::Receiver<Result<V, LoadError>>,
    loader: Loader<K, V>,
}

impl<K, V> Future for LoadFuture<K, V> {
    type Item = V;
    type Error = LoadError;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match self.rx.poll() {
            Ok(Async::NotReady) => {
                // request may pending in the queue, dispatch requests in the queue as batch
                self.loader.dispatch_rest();
                Ok(Async::NotReady)
            }
            Ok(Async::Ready(Ok(v))) => Ok(Async::Ready(v)),
            Ok(Async::Ready(Err(e))) => Err(e),
            Err(_) => Err(LoadError::LoadCanceled),
        }
    }
}

// Message pass between loader and worker thread
enum Message<K, V> {
    LoadOne { key: K, reply: oneshot::Sender<V> },
    LoadRest,
}

struct Inner<K, V> {
    rx: mpsc::UnboundedReceiver<Message<K, Result<V, LoadError>>>,
    max_batch_size: usize,
    items: Vec<(K, oneshot::Sender<Result<V, LoadError>>)>,
    err: Option<LoadError>,
}

impl<K, V> Stream for Inner<K, V> {
    type Item = Vec<(K, oneshot::Sender<Result<V, LoadError>>)>;
    type Error = LoadError;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        if let Some(err) = self.err.take() {
            return Err(err);
        }

        loop {
            match self.rx.poll() {

                Ok(Async::NotReady) => {
                    return Ok(Async::NotReady);
                }

                Ok(Async::Ready(Some(msg))) => {
                    match msg {
                        Message::LoadOne { key, reply } => {
                            //println!("get one request");
                            self.items.push((key, reply));
                            if self.items.len() >= self.max_batch_size {
                                //println!("get one batch");
                                let batch = mem::replace(&mut self.items,
                                                         Vec::with_capacity(self.max_batch_size));
                                return Ok(Some(batch).into());
                            }
                        }
                        Message::LoadRest => {
                            println!("LoadRest");
                            return if self.items.len() > 0 {
                                //println!("make request in queue into one batch");
                                let rest = mem::replace(&mut self.items, Vec::new());
                                Ok(Some(rest).into())
                            } else {
                                return Ok(Async::NotReady);
                            };
                        }
                    }
                }

                Ok(Async::Ready(None)) => {
                    return if self.items.len() > 0 {
                        let rest = mem::replace(&mut self.items, Vec::new());
                        Ok(Some(rest).into())
                    } else {
                        Ok(Async::Ready(None))
                    }
                }

                Err(_) => {
                    if self.items.len() == 0 {
                        return Err(LoadError::Receiver);
                    } else {
                        self.err = Some(LoadError::Receiver);
                        let rest = mem::replace(&mut self.items, Vec::new());
                        return Ok(Some(rest).into());
                    }
                }
            }
        }
    }
}
<commit_msg>Fix inner creation<commit_after>extern crate futures;
extern crate tokio_core;

use std::mem;
use std::thread;
use std::sync::Arc;
use std::time::Duration;

use futures::{Stream, Future, Poll, Async};
use futures::sync::{mpsc, oneshot};
use tokio_core::reactor::Core;

#[derive(Clone, Debug)]
pub enum LoadError {
    Receiver,
    LoadCanceled,
    Custom(String),
}

impl LoadError {
    pub fn custom<S: Into<String>>(s: S) -> LoadError {
        LoadError::Custom(s.into())
    }
}

pub trait BatchFn<K, V> {
    type Error: Into<LoadError>;
    fn load(&self, keys: &Vec<K>) -> Box<Future<Item = Vec<V>, Error = Self::Error>>;

    fn max_batch_size(&self) -> usize {
        200
    }
}

#[derive(Clone)]
pub struct Loader<K, V> {
    tx: Arc<mpsc::UnboundedSender<Message<K, Result<V, LoadError>>>>,
}

impl<K, V> Loader<K, V> {
    pub fn load(&self, key: K) -> LoadFuture<K, V> {
        let (tx, rx) = oneshot::channel();
        let msg = Message::LoadOne {
            key: key,
            reply: tx,
        };
        // This call may not completed as thread are parked in Future
        self.tx.send(msg).unwrap();
        // TODO: fix it, make sure send completed
        thread::sleep(Duration::from_millis(50));
        LoadFuture {
            rx: rx,
            loader: Loader { tx: self.tx.clone() },
        }
    }

    /// Called when poll LoadFuture return NotReady
    fn dispatch_rest(&self) {
        // This call may not completed as thread are parked in Future
        self.tx.send(Message::LoadRest).unwrap();
        // TODO: fix it, make sure send completed
        thread::sleep(Duration::from_millis(50));
    }
}

impl<K, V> Loader<K, V>
    where K: 'static + Send,
          V: 'static + Send
{
    pub fn new<F>(batch_fn: F) -> Loader<K, V>
        where F: 'static + Send + BatchFn<K, V>
    {
        assert!(batch_fn.max_batch_size() > 0);

        let (tx, rx) = mpsc::unbounded();
        let inner_handle = Arc::new(tx);
        let loader = Loader { tx: inner_handle };

        // worker thread to call batch_fn for load requests
        thread::spawn(move || {
            let batch_fn = Arc::new(batch_fn);
            let mut core = Core::new().unwrap();
            let handle = core.handle();

            let inner = Inner {
                rx: rx,
                max_batch_size: batch_fn.max_batch_size(),
                items: Vec::with_capacity(batch_fn.max_batch_size()),
                err: None,
            };

            let load_batch = batch_fn.clone();
            let loader =
                inner.for_each(move |requests: Vec<(K, oneshot::Sender<Result<V, LoadError>>)>| {
                    let (keys, replys) = requests.into_iter()
                        .fold((Vec::new(), Vec::new()), |mut soa, i| {
                            soa.0.push(i.0);
                            soa.1.push(i.1);
                            soa
                        });
                    let batch_job = load_batch.load(&keys).then(move |x| {
                        match x {
                            Ok(values) => {
                                for r in replys.into_iter().zip(values) {
                                    r.0.complete(Ok(r.1));
                                }
                            }
                            Err(e) => {
                                let err = e.into();
                                for r in replys {
                                    r.complete(Err(err.clone()));
                                }
                            }
                        };
                        Ok(())
                    });
                    handle.spawn(batch_job);
                    Ok(())
                });
            core.run(loader).unwrap();

            // Run until all batch jobs completed
            core.turn(None);
        });

        loader
    }
}

pub struct LoadFuture<K, V> {
    rx: oneshot::Receiver<Result<V, LoadError>>,
    loader: Loader<K, V>,
}

impl<K, V> Future for LoadFuture<K, V> {
    type Item = V;
    type Error = LoadError;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match self.rx.poll() {
            Ok(Async::NotReady) => {
                // request may pending in the queue, dispatch requests in the queue as batch
                self.loader.dispatch_rest();
                Ok(Async::NotReady)
            }
            Ok(Async::Ready(Ok(v))) => Ok(Async::Ready(v)),
            Ok(Async::Ready(Err(e))) => Err(e),
            Err(_) => Err(LoadError::LoadCanceled),
        }
    }
}

// Message pass between loader and worker thread
enum Message<K, V> {
    LoadOne { key: K, reply: oneshot::Sender<V> },
    LoadRest,
}

struct Inner<K, V> {
    rx: mpsc::UnboundedReceiver<Message<K, Result<V, LoadError>>>,
    max_batch_size: usize,
    items: Vec<(K, oneshot::Sender<Result<V, LoadError>>)>,
    err: Option<LoadError>,
}

impl<K, V> Stream for Inner<K, V> {
    type Item = Vec<(K, oneshot::Sender<Result<V, LoadError>>)>;
    type Error = LoadError;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        if let Some(err) = self.err.take() {
            return Err(err);
        }

        loop {
            match self.rx.poll() {

                Ok(Async::NotReady) => {
                    return Ok(Async::NotReady);
                }

                Ok(Async::Ready(Some(msg))) => {
                    match msg {
                        Message::LoadOne { key, reply } => {
                            //println!("get one request");
                            self.items.push((key, reply));
                            if self.items.len() >= self.max_batch_size {
                                //println!("get one batch");
                                let batch = mem::replace(&mut self.items,
                                                         Vec::with_capacity(self.max_batch_size));
                                return Ok(Some(batch).into());
                            }
                        }
                        Message::LoadRest => {
                            println!("LoadRest");
                            return if self.items.len() > 0 {
                                //println!("make request in queue into one batch");
                                let rest = mem::replace(&mut self.items, Vec::new());
                                Ok(Some(rest).into())
                            } else {
                                return Ok(Async::NotReady);
                            };
                        }
                    }
                }

                Ok(Async::Ready(None)) => {
                    return if self.items.len() > 0 {
                        let rest = mem::replace(&mut self.items, Vec::new());
                        Ok(Some(rest).into())
                    } else {
                        Ok(Async::Ready(None))
                    }
                }

                Err(_) => {
                    if self.items.len() == 0 {
                        return Err(LoadError::Receiver);
                    } else {
                        self.err = Some(LoadError::Receiver);
                        let rest = mem::replace(&mut self.items, Vec::new());
                        return Ok(Some(rest).into());
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! _**tini** is a **t**iny **ini**-file reader and writer_
//!
//! This small library provides basic functions to operate with ini-files
//! # Examples
//! ## Read from buffer and get string values
//! ````
//! use tini::Ini;
//!
//! let conf = Ini::from_buffer(["[search]",
//!                              "g = google.com",
//!                              "dd = duckduckgo.com"].join("\n"));
//!
//! let g: String = conf.get("search", "g").unwrap();
//! let dd: String = conf.get("search", "dd").unwrap();
//!
//! assert_eq!(g, "google.com");
//! assert_eq!(dd, "duckduckgo.com");
//! ````
//! ## Construct in program and get vectors
//! ````
//! use tini::Ini;
//!
//! let conf = Ini::new().section("floats")
//!                      .item("consts", "3.1416, 2.7183")
//!                      .section("integers")
//!                      .item("lost", "4,8,15,16,23,42");
//! let consts: Vec<f64> = conf.get_vec("floats", "consts").unwrap();
//! let lost: Vec<i32> = conf.get_vec("integers", "lost").unwrap();
//!
//! assert_eq!(consts, [3.1416, 2.7183]);
//! assert_eq!(lost, [4, 8, 15, 16, 23, 42]);
//! ````
use std::path::Path;
use std::collections::HashMap;
use std::io::{self, BufReader, Read, BufWriter, Write};
use std::fs::File;
use std::str::FromStr;
use parser::{parse_line, Parsed};
use std::fmt;

type Section = HashMap<String, String>;
type IniParsed = HashMap<String, Section>;

/// Structure for INI-file data
#[derive(Debug)]
pub struct Ini {
    #[doc(hidden)]
    data: IniParsed,
    last_section_name: String,
}

impl Ini {
    /// Create an empty Ini
    pub fn new() -> Ini {
        Ini {
            data: IniParsed::new(),
            last_section_name: String::new(),
        }
    }
    fn from_string(string: &str) -> Ini {
        let mut result = Ini::new();
        for (i, line) in string.lines().enumerate() {
            match parse_line(&line) {
                Parsed::Section(name) => result = result.section(name),
                Parsed::Value(name, value) => result = result.item(name, value),
                Parsed::Error(msg) => println!("line {}: error: {}", i, msg),
                _ => (),
            };
        }
        result
    }
    /// Construct Ini from file
    ///
    /// # Examples
    /// You may use Path
    ///
    /// ```
    /// use std::path::Path;
    /// use tini::Ini;
    ///
    /// let path = Path::new("./examples/example.ini");
    /// let conf = Ini::from_file(path);
    /// assert!(conf.ok().is_some());
    /// ```
    ///
    /// or `&str`
    ///
    /// ```
    /// use tini::Ini;
    ///
    /// let conf = Ini::from_file("./examples/example.ini");
    /// assert!(conf.ok().is_some());
    /// ```
    pub fn from_file<S: AsRef<Path> + ?Sized>(path: &S) -> Result<Ini, io::Error> {
        let file = try!(File::open(path));
        let mut reader = BufReader::new(file);
        let mut buffer = String::new();
        try!(reader.read_to_string(&mut buffer));
        Ok(Ini::from_string(&buffer))
    }
    /// Construct Ini from buffer
    ///
    /// # Example
    /// ```
    /// use tini::Ini;
    ///
    /// let conf = Ini::from_buffer("[section]\none = 1");
    /// let value: Option<u8> = conf.get("section", "one");
    /// assert_eq!(value, Some(1));
    /// ```
    pub fn from_buffer<S: Into<String>>(buf: S) -> Ini {
        Ini::from_string(&buf.into())
    }
    /// Add new empty section to Ini
    ///
    /// # Example
    /// ```
    /// use tini::Ini;
    ///
    /// let conf = Ini::new().section("empty");
    /// assert_eq!(conf.to_buffer(), "[empty]".to_owned());
    /// ```
    pub fn section<S: Into<String>>(mut self, name: S) -> Self {
        self.last_section_name = name.into();
        self.data.insert(self.last_section_name.clone(), Section::new());
        self
    }
    /// Add key-value pair to last section
    ///
    /// # Example
    /// ```
    /// use tini::Ini;
    ///
    /// let conf = Ini::new().section("test")
    ///                      .item("value", "10");
    ///
    /// let value: Option<u8> = conf.get("test", "value");
    /// assert_eq!(value, Some(10));
    /// ```
    pub fn item<S: Into<String>>(mut self, name: S, value: S) -> Self {
        {
            let last_section = self.data
                                   .entry(self.last_section_name.clone())
                                   .or_insert(Section::new());
            last_section.insert(name.into(), value.into());
        }
        self
    }
    /// Write Ini to file. This function is similar to `from_file` in use.
    pub fn to_file<S: AsRef<Path> + ?Sized>(&self, path: &S) -> Result<(), io::Error> {
        let file = try!(File::create(path));
        let mut writer = BufWriter::new(file);
        let result: String = format!("{}", self);
        try!(writer.write_all(result.as_bytes()));
        Ok(())
    }
    /// Write Ini to buffer
    ///
    /// # Example
    /// ```
    /// use tini::Ini;
    ///
    /// let conf = Ini::from_buffer("[section]\none = 1");
    /// // you may use `conf.to_buffer()`
    /// let value: String = conf.to_buffer();
    /// // or format!("{}", conf);
    /// // let value: String = format!("{}", conf);
    /// // but the result will be the same
    /// assert_eq!(value, "[section]\none = 1".to_owned());
    /// ```
    pub fn to_buffer(&self) -> String {
        let buffer = format!("{}", self);
        buffer
    }

    fn get_raw(&self, section: &str, key: &str) -> Option<&String> {
        let s = self.data.get(section);
        match s {
            Some(hm) => hm.get(key),
            None => None,
        }
    }
    /// Get scalar value of key in section
    ///
    /// # Example
    /// ```
    /// use tini::Ini;
    ///
    /// let conf = Ini::from_buffer("[section]\none = 1");
    /// let value: Option<u8> = conf.get("section", "one");
    /// assert_eq!(value, Some(1));
    /// ```
    pub fn get<T: FromStr>(&self, section: &str, key: &str) -> Option<T> {
        let data = self.get_raw(section, key);
        match data {
            Some(x) => x.parse().ok(),
            None => None,
        }
    }
    /// Get vector value of key in section
    ///
    /// The function returns `None` if one of the elements can not be parsed.
    ///
    /// # Example
    /// ```
    /// use tini::Ini;
    ///
    /// let conf = Ini::from_buffer("[section]\nlist = 1, 2, 3, 4");
    /// let value: Option<Vec<u8>> = conf.get_vec("section", "list");
    /// assert_eq!(value, Some(vec![1, 2, 3, 4]));
    /// ```
    pub fn get_vec<T>(&self, section: &str, key: &str) -> Option<Vec<T>>
        where T: FromStr + Copy
    {
        let s = self.get_raw(section, key);
        match s {
            Some(x) => {
                let parsed: Vec<Option<T>> = x.split(',').map(|s| s.trim().parse().ok()).collect();
                if parsed.iter().any(|e| e.is_none()) {
                    return None;
                }
                Some(parsed.iter().map(|s| s.unwrap()).collect())
            }
            None => None,
        }
    }
}

impl fmt::Display for Ini {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut buffer = String::new();
        for section in &self.data {
            buffer.push_str(&format!("[{}]\n", section.0));
            for (key, value) in section.1.iter() {
                buffer.push_str(&format!("{} = {}\n", key, value));
            }
        }
        // remove last '\n'
        buffer.pop();
        write!(f, "{}", buffer)
    }
}

#[cfg(test)]
mod library_test {
    use super::*;

    #[test]
    fn test_bool() {
        let ini = Ini::from_buffer("[string]\nabc = true");
        let abc: Option<bool> = ini.get("string", "abc");
        assert_eq!(abc, Some(true));
    }

    #[test]
    fn test_float() {
        let ini = Ini::from_string("[section]\nname=10.5");
        let name: Option<f64> = ini.get("section", "name");
        assert_eq!(name, Some(10.5));
    }

    #[test]
    fn test_float_vec() {
        let ini = Ini::from_string("[section]\nname=1.2, 3.4, 5.6");
        let name: Option<Vec<f64>> = ini.get_vec("section", "name");
        assert_eq!(name, Some(vec![1.2, 3.4, 5.6]));
    }

    #[test]
    fn test_parse_error() {
        let ini = Ini::from_string("[section]\nlist = 1, 2, --, 4");
        let name: Option<Vec<u8>> = ini.get_vec("section", "list");
        assert_eq!(name, None);
    }

    #[test]
    fn test_get_or_macro() {
        let ini = Ini::from_string("[section]\nlist = 1, 2, --, 4");
        let with_value: Vec<u8> = ini.get_vec("section", "list").unwrap_or(vec![1, 2, 3, 4]);
        assert_eq!(with_value, vec![1, 2, 3, 4]);
    }
}

mod parser {
    #[derive(Debug)]
    pub enum Parsed {
        Error(String),
        Empty,
        Section(String),
        Value(String, String), /* Vector(String, Vec<String>), impossible, because HashMap field has type String, not Vec */
    }

    pub fn parse_line(line: &str) -> Parsed {
        let content = line.split(';').nth(0).unwrap().trim();
        if content.len() == 0 {
            return Parsed::Empty;
        }
        // add checks for content
        if content.starts_with('[') {
            if content.ends_with(']') {
                let section_name = content.trim_matches(|c| c == '[' || c == ']').to_owned();
                return Parsed::Section(section_name);
            } else {
                return Parsed::Error("incorrect section syntax".to_owned());
            }
        } else if content.contains('=') {
            let mut pair = content.split('=').map(|s| s.trim());
            let key = pair.next().unwrap().to_owned();
            let value = pair.next().unwrap().to_owned();
            return Parsed::Value(key, value);
        }
        Parsed::Error("incorrect syntax".to_owned())
    }

    #[cfg(test)]
    mod test {
        use super::*;

        #[test]
        fn test_comment() {
            match parse_line(";------") {
                Parsed::Empty => assert!(true),
                _ => assert!(false),
            }
        }

        #[test]
        fn test_entry() {
            match parse_line("name1 = 100 ; comment") {
                Parsed::Value(name, text) => {
                    assert_eq!(name, String::from("name1"));
                    assert_eq!(text, String::from("100"));
                }
                _ => assert!(false),
            }
        }

        #[test]
        fn test_weird_name() {
            match parse_line("_.,:(){}-#@&*| = 100") {
                Parsed::Value(name, text) => {
                    assert_eq!(name, String::from("_.,:(){}-#@&*|"));
                    assert_eq!(text, String::from("100"));
                }
                _ => assert!(false),
            }
        }

        #[test]
        fn test_text_entry() {
            match parse_line("text_name = hello world!") {
                Parsed::Value(name, text) => {
                    assert_eq!(name, String::from("text_name"));
                    assert_eq!(text, String::from("hello world!"));
                }
                _ => assert!(false),
            }
        }

        #[test]
        fn test_incorrect_token() {
            match parse_line("[section = 1, 2 = value") {
                Parsed::Error(_) => assert!(true),
                _ => assert!(false),
            }
        }
    }
}
<commit_msg>[rm] empty sections<commit_after>//! _**tini** is a **t**iny **ini**-file reader and writer_
//!
//! This small library provides basic functions to operate with ini-files
//! # Examples
//! ## Read from buffer and get string values
//! ````
//! use tini::Ini;
//!
//! let conf = Ini::from_buffer(["[search]",
//!                              "g = google.com",
//!                              "dd = duckduckgo.com"].join("\n"));
//!
//! let g: String = conf.get("search", "g").unwrap();
//! let dd: String = conf.get("search", "dd").unwrap();
//!
//! assert_eq!(g, "google.com");
//! assert_eq!(dd, "duckduckgo.com");
//! ````
//! ## Construct in program and get vectors
//! ````
//! use tini::Ini;
//!
//! let conf = Ini::new().section("floats")
//!                      .item("consts", "3.1416, 2.7183")
//!                      .section("integers")
//!                      .item("lost", "4,8,15,16,23,42");
//! let consts: Vec<f64> = conf.get_vec("floats", "consts").unwrap();
//! let lost: Vec<i32> = conf.get_vec("integers", "lost").unwrap();
//!
//! assert_eq!(consts, [3.1416, 2.7183]);
//! assert_eq!(lost, [4, 8, 15, 16, 23, 42]);
//! ````
use std::path::Path;
use std::collections::HashMap;
use std::io::{self, BufReader, Read, BufWriter, Write};
use std::fs::File;
use std::str::FromStr;
use parser::{parse_line, Parsed};
use std::fmt;

type Section = HashMap<String, String>;
type IniParsed = HashMap<String, Section>;

/// Structure for INI-file data
#[derive(Debug)]
pub struct Ini {
    #[doc(hidden)]
    data: IniParsed,
    last_section_name: String,
}

impl Ini {
    /// Create an empty Ini
    pub fn new() -> Ini {
        Ini {
            data: IniParsed::new(),
            last_section_name: String::new(),
        }
    }
    fn from_string(string: &str) -> Ini {
        let mut result = Ini::new();
        for (i, line) in string.lines().enumerate() {
            match parse_line(&line) {
                Parsed::Section(name) => result = result.section(name),
                Parsed::Value(name, value) => result = result.item(name, value),
                Parsed::Error(msg) => println!("line {}: error: {}", i, msg),
                _ => (),
            };
        }
        result
    }
    /// Construct Ini from file
    ///
    /// # Examples
    /// You may use Path
    ///
    /// ```
    /// use std::path::Path;
    /// use tini::Ini;
    ///
    /// let path = Path::new("./examples/example.ini");
    /// let conf = Ini::from_file(path);
    /// assert!(conf.ok().is_some());
    /// ```
    ///
    /// or `&str`
    ///
    /// ```
    /// use tini::Ini;
    ///
    /// let conf = Ini::from_file("./examples/example.ini");
    /// assert!(conf.ok().is_some());
    /// ```
    pub fn from_file<S: AsRef<Path> + ?Sized>(path: &S) -> Result<Ini, io::Error> {
        let file = try!(File::open(path));
        let mut reader = BufReader::new(file);
        let mut buffer = String::new();
        try!(reader.read_to_string(&mut buffer));
        Ok(Ini::from_string(&buffer))
    }
    /// Construct Ini from buffer
    ///
    /// # Example
    /// ```
    /// use tini::Ini;
    ///
    /// let conf = Ini::from_buffer("[section]\none = 1");
    /// let value: Option<u8> = conf.get("section", "one");
    /// assert_eq!(value, Some(1));
    /// ```
    pub fn from_buffer<S: Into<String>>(buf: S) -> Ini {
        Ini::from_string(&buf.into())
    }
    /// Set section name for following `[item()](#method.item)`s, but don't create section
    ///
    /// # Example
    /// ```
    /// use tini::Ini;
    ///
    /// let conf = Ini::new().section("empty");
    /// assert_eq!(conf.to_buffer(), String::new());
    /// ```
    pub fn section<S: Into<String>>(mut self, name: S) -> Self {
        self.last_section_name = name.into();
        self
    }
    /// Add key-value pair to last section
    ///
    /// # Example
    /// ```
    /// use tini::Ini;
    ///
    /// let conf = Ini::new().section("test")
    ///                      .item("value", "10");
    ///
    /// let value: Option<u8> = conf.get("test", "value");
    /// assert_eq!(value, Some(10));
    /// ```
    pub fn item<S: Into<String>>(mut self, name: S, value: S) -> Self {
        {
            let last_section = self.data
                                   .entry(self.last_section_name.clone())
                                   .or_insert(Section::new());
            last_section.insert(name.into(), value.into());
        }
        self
    }
    /// Write Ini to file. This function is similar to `from_file` in use.
    pub fn to_file<S: AsRef<Path> + ?Sized>(&self, path: &S) -> Result<(), io::Error> {
        let file = try!(File::create(path));
        let mut writer = BufWriter::new(file);
        let result: String = format!("{}", self);
        try!(writer.write_all(result.as_bytes()));
        Ok(())
    }
    /// Write Ini to buffer
    ///
    /// # Example
    /// ```
    /// use tini::Ini;
    ///
    /// let conf = Ini::from_buffer("[section]\none = 1");
    /// // you may use `conf.to_buffer()`
    /// let value: String = conf.to_buffer();
    /// // or format!("{}", conf);
    /// // let value: String = format!("{}", conf);
    /// // but the result will be the same
    /// assert_eq!(value, "[section]\none = 1".to_owned());
    /// ```
    pub fn to_buffer(&self) -> String {
        let buffer = format!("{}", self);
        buffer
    }

    fn get_raw(&self, section: &str, key: &str) -> Option<&String> {
        let s = self.data.get(section);
        match s {
            Some(hm) => hm.get(key),
            None => None,
        }
    }
    /// Get scalar value of key in section
    ///
    /// # Example
    /// ```
    /// use tini::Ini;
    ///
    /// let conf = Ini::from_buffer("[section]\none = 1");
    /// let value: Option<u8> = conf.get("section", "one");
    /// assert_eq!(value, Some(1));
    /// ```
    pub fn get<T: FromStr>(&self, section: &str, key: &str) -> Option<T> {
        let data = self.get_raw(section, key);
        match data {
            Some(x) => x.parse().ok(),
            None => None,
        }
    }
    /// Get vector value of key in section
    ///
    /// The function returns `None` if one of the elements can not be parsed.
    ///
    /// # Example
    /// ```
    /// use tini::Ini;
    ///
    /// let conf = Ini::from_buffer("[section]\nlist = 1, 2, 3, 4");
    /// let value: Option<Vec<u8>> = conf.get_vec("section", "list");
    /// assert_eq!(value, Some(vec![1, 2, 3, 4]));
    /// ```
    pub fn get_vec<T>(&self, section: &str, key: &str) -> Option<Vec<T>>
        where T: FromStr + Copy
    {
        let s = self.get_raw(section, key);
        match s {
            Some(x) => {
                let parsed: Vec<Option<T>> = x.split(',').map(|s| s.trim().parse().ok()).collect();
                if parsed.iter().any(|e| e.is_none()) {
                    return None;
                }
                Some(parsed.iter().map(|s| s.unwrap()).collect())
            }
            None => None,
        }
    }
}

impl fmt::Display for Ini {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut buffer = String::new();
        for section in &self.data {
            buffer.push_str(&format!("[{}]\n", section.0));
            for (key, value) in section.1.iter() {
                buffer.push_str(&format!("{} = {}\n", key, value));
            }
        }
        // remove last '\n'
        buffer.pop();
        write!(f, "{}", buffer)
    }
}

#[cfg(test)]
mod library_test {
    use super::*;

    #[test]
    fn test_bool() {
        let ini = Ini::from_buffer("[string]\nabc = true");
        let abc: Option<bool> = ini.get("string", "abc");
        assert_eq!(abc, Some(true));
    }

    #[test]
    fn test_float() {
        let ini = Ini::from_string("[section]\nname=10.5");
        let name: Option<f64> = ini.get("section", "name");
        assert_eq!(name, Some(10.5));
    }

    #[test]
    fn test_float_vec() {
        let ini = Ini::from_string("[section]\nname=1.2, 3.4, 5.6");
        let name: Option<Vec<f64>> = ini.get_vec("section", "name");
        assert_eq!(name, Some(vec![1.2, 3.4, 5.6]));
    }

    #[test]
    fn test_parse_error() {
        let ini = Ini::from_string("[section]\nlist = 1, 2, --, 4");
        let name: Option<Vec<u8>> = ini.get_vec("section", "list");
        assert_eq!(name, None);
    }

    #[test]
    fn test_get_or_macro() {
        let ini = Ini::from_string("[section]\nlist = 1, 2, --, 4");
        let with_value: Vec<u8> = ini.get_vec("section", "list").unwrap_or(vec![1, 2, 3, 4]);
        assert_eq!(with_value, vec![1, 2, 3, 4]);
    }
}

mod parser {
    #[derive(Debug)]
    pub enum Parsed {
        Error(String),
        Empty,
        Section(String),
        Value(String, String), /* Vector(String, Vec<String>), impossible, because HashMap field has type String, not Vec */
    }

    pub fn parse_line(line: &str) -> Parsed {
        let content = line.split(';').nth(0).unwrap().trim();
        if content.len() == 0 {
            return Parsed::Empty;
        }
        // add checks for content
        if content.starts_with('[') {
            if content.ends_with(']') {
                let section_name = content.trim_matches(|c| c == '[' || c == ']').to_owned();
                return Parsed::Section(section_name);
            } else {
                return Parsed::Error("incorrect section syntax".to_owned());
            }
        } else if content.contains('=') {
            let mut pair = content.split('=').map(|s| s.trim());
            let key = pair.next().unwrap().to_owned();
            let value = pair.next().unwrap().to_owned();
            return Parsed::Value(key, value);
        }
        Parsed::Error("incorrect syntax".to_owned())
    }

    #[cfg(test)]
    mod test {
        use super::*;

        #[test]
        fn test_comment() {
            match parse_line(";------") {
                Parsed::Empty => assert!(true),
                _ => assert!(false),
            }
        }

        #[test]
        fn test_entry() {
            match parse_line("name1 = 100 ; comment") {
                Parsed::Value(name, text) => {
                    assert_eq!(name, String::from("name1"));
                    assert_eq!(text, String::from("100"));
                }
                _ => assert!(false),
            }
        }

        #[test]
        fn test_weird_name() {
            match parse_line("_.,:(){}-#@&*| = 100") {
                Parsed::Value(name, text) => {
                    assert_eq!(name, String::from("_.,:(){}-#@&*|"));
                    assert_eq!(text, String::from("100"));
                }
                _ => assert!(false),
            }
        }

        #[test]
        fn test_text_entry() {
            match parse_line("text_name = hello world!") {
                Parsed::Value(name, text) => {
                    assert_eq!(name, String::from("text_name"));
                    assert_eq!(text, String::from("hello world!"));
                }
                _ => assert!(false),
            }
        }

        #[test]
        fn test_incorrect_token() {
            match parse_line("[section = 1, 2 = value") {
                Parsed::Error(_) => assert!(true),
                _ => assert!(false),
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::cmp::Eq;

use ::symbol_table;

/// Internal edge identifier.
///
/// This type is not exported by the crate because it does not identify the
/// graph that it belongs to, which makes it only slightly less dangerous than a
/// pointer with no lifetime.
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct EdgeId(pub usize);

impl EdgeId {
    /// Converts an `EdgeId` to a usize that is guaranteed to be unique within a
    /// graph.
    pub fn as_usize(self) -> usize {
        let EdgeId(x) = self;
        x
    }
}

/// Internal vertex identifier.
///
/// For a given graph, distinct `VertexId`s are associated with distinct game
/// states. This type is not exported by the crate because it does not identify
/// the graph that it belongs to, which makes it only slightly less dangerous
/// than a pointer with no lifetime.
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct VertexId(pub usize);

impl Default for VertexId {
    fn default() -> Self { VertexId(0) }
}

impl symbol_table::SymbolId for VertexId {
    fn next(&self) -> Self { VertexId(self.0 + 1) }
    fn as_usize(&self) -> usize { self.0 }
}

/// Internal type for graph edges.
///
/// The Hash, Ord, and Eq implementations will conflate parallel edges with
/// identical statistics.
#[derive(Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct RawEdge<A> {
    /// Edge data.
    pub data: A,
    /// Source vertex.
    pub source: VertexId,
    /// Target vertex.
    pub target: VertexId,
}

/// Internal type for graph vertices.
#[derive(Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct RawVertex<S> {
    /// Vertex data.
    pub data: S,
    /// Parent edges pointing into this vertex.
    pub parents: Vec<EdgeId>,
    /// Child edges pointing out of this vertex.
    pub children: Vec<EdgeId>,
}
<commit_msg>Remove unused import.<commit_after>use ::symbol_table;

/// Internal edge identifier.
///
/// This type is not exported by the crate because it does not identify the
/// graph that it belongs to, which makes it only slightly less dangerous than a
/// pointer with no lifetime.
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct EdgeId(pub usize);

impl EdgeId {
    /// Converts an `EdgeId` to a usize that is guaranteed to be unique within a
    /// graph.
    pub fn as_usize(self) -> usize {
        let EdgeId(x) = self;
        x
    }
}

/// Internal vertex identifier.
///
/// For a given graph, distinct `VertexId`s are associated with distinct game
/// states. This type is not exported by the crate because it does not identify
/// the graph that it belongs to, which makes it only slightly less dangerous
/// than a pointer with no lifetime.
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct VertexId(pub usize);

impl Default for VertexId {
    fn default() -> Self { VertexId(0) }
}

impl symbol_table::SymbolId for VertexId {
    fn next(&self) -> Self { VertexId(self.0 + 1) }
    fn as_usize(&self) -> usize { self.0 }
}

/// Internal type for graph edges.
///
/// The Hash, Ord, and Eq implementations will conflate parallel edges with
/// identical statistics.
#[derive(Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct RawEdge<A> {
    /// Edge data.
    pub data: A,
    /// Source vertex.
    pub source: VertexId,
    /// Target vertex.
    pub target: VertexId,
}

/// Internal type for graph vertices.
#[derive(Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct RawVertex<S> {
    /// Vertex data.
    pub data: S,
    /// Parent edges pointing into this vertex.
    pub parents: Vec<EdgeId>,
    /// Child edges pointing out of this vertex.
    pub children: Vec<EdgeId>,
}
<|endoftext|>