<commit_before>use super::*;
use std::collections::HashMap;
use std::collections::hash_map;
use std::iter;
//use linked_hash_map;
//use linked_hash_map::LinkedHashMap;

pub trait ModuleStruct<'a> {
    fn init_module(&mut self);
}

struct TorchBackend {}
pub struct Parameter<'a> {
    data: &'a mut Tensor,
}
impl<'a> Parameter<'a> {
    fn valid(&self) -> bool {
        true
    }
}

pub struct Module<'a> {
    pub _name: &'a str,
    _backend: TorchBackend,
    //	_buffers: HashTable<&str, Tensor>
    //	_backward_hooks:
    //	_forward_hooks:
    //_modulesp: LinkedHashMap<&'a str, *mut Module<'a>>,
    _params: HashMap<&'a str, *mut Parameter<'a>>,
    _modulesp: HashMap<&'a str, *mut Module<'a>>,
    training: bool,
}
pub struct PtrIterMut<'a, T: 'a> {
    //mod_iter: linked_hash_map::IterMut<'a, &'a str, *mut T>,
    mod_iter: hash_map::IterMut<'a, &'a str, *mut T>,
}

impl<'a, T> Iterator for PtrIterMut<'a, T> {
    type Item = (&'a str, &'a mut T);
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((name, t)) = self.mod_iter.next() {
            Some((name, unsafe { &mut **t as &mut T }))
        } else {
            None
        }
    }
}

impl<'a> Module<'a> {
    pub fn new() -> Module<'a> {
        Module {
            _name: "",
            _backend: TorchBackend {},
            _params: HashMap::new(),
            //_modulesp: LinkedHashMap::new(),
            _modulesp: HashMap::new(),
            training: true,
        }
    }
    #[inline]
    fn as_mut_ptr(&mut self) -> *mut Module<'a> {
        self as *mut Module<'a>
    }
    pub fn add_module(&mut self, module: &mut ModIntf<'a>) {
        let m = module.delegate();
        self._modulesp.insert(m._name, m.as_mut_ptr());

    }
    pub fn modules_iter_mut(&mut self) -> PtrIterMut<Module<'a>> {
        PtrIterMut { mod_iter: self._modulesp.iter_mut() }
    }
    pub fn params_iter_mut(&mut self) -> PtrIterMut<Parameter<'a>> {
        PtrIterMut { mod_iter: self._params.iter_mut() }
    }
    fn _apply(&mut self, callback: fn(&mut Tensor)) {
        for (_, module) in self.modules_iter_mut() {
            module._apply(callback)
        }
        for param in self.params_iter_mut()
                .filter_map(|(_, p)| if p.valid() { Some(p) } else { None }) {
            callback(param.data);
            /*
			if let Some(g) = p._grad {
					callback(g.data)
			}
			*/
            /* see also _buffers */
        }
    }
    fn apply(&mut self, callback: fn(&mut Self)) {
        for (_, module) in self.modules_iter_mut() {
            module.apply(callback)
        }
        callback(self)
    }
    pub fn eval(&mut self) {
        self.train(false)
    }
    fn train(&mut self, mode: bool) {
        self.training = mode;
        for (_, module) in self.modules_iter_mut() {
            module.train(mode)
        }

    }
}

pub trait ModIntf<'a> {
    fn delegate(&mut self) -> &mut Module<'a>;
    fn forward(&mut self);
}

#[derive(ModParse)]
pub struct Linear<'a> {
    delegate: Module<'a>,
    in_features: u32,
}

impl<'a> Linear<'a> {
    pub fn new() -> Linear<'a> {
        let mut t = Linear {
            delegate: Module::new(),
            in_features: 0,
        };
        t.init_module();
        t
    }
}

impl<'a> ModIntf<'a> for Linear<'a> {
    fn delegate(&mut self) -> &mut Module<'a> {
        &mut self.delegate
    }
    fn forward(&mut self) {}
}
<commit_msg>further flesh out module interface<commit_after>use super::*;
use std::collections::HashMap;
use std::collections::hash_map;
use std::iter;
//use linked_hash_map;
//use linked_hash_map::LinkedHashMap;

pub trait ModuleStruct<'a> {
    fn init_module(&mut self);
}

struct TorchBackend {}
pub struct Parameter<'a> {
    data: &'a mut Tensor,
}
impl<'a> Parameter<'a> {
    fn valid(&self) -> bool {
        true
    }
}

pub struct Module<'a> {
    pub _name: &'a str,
    _backend: TorchBackend,
//    _root: *mut ModIntf<'a>,

    	_buffers: HashMap<&'a str, &'a mut Tensor>,
    //	_backward_hooks:
    //	_forward_hooks:
    _params: HashMap<&'a str, *mut Parameter<'a>>,
    _modules: HashMap<&'a str, *mut Module<'a>>,
    training: bool,
}
pub struct PtrIterMut<'a, T: 'a> {
    //mod_iter: linked_hash_map::IterMut<'a, &'a str, *mut T>,
    mod_iter: hash_map::IterMut<'a, &'a str, *mut T>,
}
pub struct PtrIter<'a, T: 'a> {
    //mod_iter: linked_hash_map::IterMut<'a, &'a str, *mut T>,
    mod_iter: hash_map::Iter<'a, &'a str, *mut T>,
}

impl<'a, T> Iterator for PtrIterMut<'a, T> {
    type Item = (&'a str, &'a mut T);
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((name, t)) = self.mod_iter.next() {
            Some((name, unsafe { &mut **t as &mut T }))
        } else {
            None
        }
    }
}

impl<'a, T> Iterator for PtrIter<'a, T> {
    type Item = (&'a str, &'a T);
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((name, t)) = self.mod_iter.next() {
            Some((name, unsafe { & **t as & T }))
        } else {
            None
        }
    }
}

impl<'a> Module<'a> {
    pub fn new() -> Module<'a> {
        unsafe { Module {
            _name: "",
            _backend: TorchBackend {},
            _buffers: HashMap::new(),
            _params: HashMap::new(),
            _modules: HashMap::new(),
            training: true,
        }
    }
    }
    #[inline]
    fn as_mut_ptr(&mut self) -> *mut Module<'a> {
        self as *mut Module<'a>
    }
    pub fn add_module(&mut self, module: &mut ModIntf<'a>) {
        let m = module.delegate();
        self._modules.insert(m._name, m.as_mut_ptr());

    }
    pub fn modules_iter_mut(&mut self) -> PtrIterMut<Module<'a>> {
        PtrIterMut { mod_iter: self._modules.iter_mut() }
    }
    pub fn modules_iter(&mut self) -> PtrIter<Module<'a>> {
        PtrIter { mod_iter: self._modules.iter() }
    }
    pub fn params_iter_mut(&mut self) -> PtrIterMut<Parameter<'a>> {
        PtrIterMut { mod_iter: self._params.iter_mut() }
    }
    pub fn register_buffer(&mut self, name: &'a str, tensor: &'a mut Tensor) {
        self._buffers.insert(name, tensor);
    }
    fn _apply(&mut self, callback: fn(&mut Tensor)) {
        for (_, module) in self.modules_iter_mut() {
            module._apply(callback)
        }
        for param in self.params_iter_mut()
                .filter_map(|(_, p)| if p.valid() { Some(p) } else { None }) {
            callback(param.data);
            /*
			if let Some(g) = p._grad {
					callback(g.data)
			}
			*/
            /* see also _buffers */
        }
    }
    fn apply(&mut self, callback: fn(&mut Self)) {
        for (_, module) in self.modules_iter_mut() {
            module.apply(callback)
        }
        callback(self)
    }
    pub fn repr(&mut self) -> String {
        let mut tmpstr = format!("{} (\n", self._name );
        for (key, module) in self.modules_iter_mut() {
            let modstr = module.repr();
            let modstr = format!("  {}", modstr);
            tmpstr = format!("{} ({}): {}\n", tmpstr, key, modstr);
        }
        tmpstr = format!("{})", tmpstr);
        tmpstr
    }
    pub fn eval(&mut self) {
        self.train(false)
    }
    fn train(&mut self, mode: bool) {
        self.training = mode;
        for (_, module) in self.modules_iter_mut() {
            module.train(mode)
        }

    }
}

pub trait ModIntf<'a> {
    fn delegate(&mut self) -> &mut Module<'a>;
    fn forward(&mut self);
}

#[derive(ModParse)]
pub struct Linear<'a> {
    delegate: Module<'a>,
    in_features: u32,
}

impl<'a> Linear<'a> {
    pub fn new() -> Linear<'a> {
        let mut t = Linear {
            delegate: Module::new(),
            in_features: 0,
        };
        t.init_module();
        t
    }
}

impl<'a> ModIntf<'a> for Linear<'a> {
    fn delegate(&mut self) -> &mut Module<'a> {
        &mut self.delegate
    }
    fn forward(&mut self) {}
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use servo_msg::compositor_msg::LayerBuffer;
use font_context::FontContext;
use geometry::Au;
use opts::Opts;

use azure::azure_hl::{B8G8R8A8, Color, ColorPattern, DrawOptions};
use azure::azure_hl::{DrawSurfaceOptions, DrawTarget, Linear, StrokeOptions};
use azure::AzFloat;
use std::libc::types::common::c99::uint16_t;
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use geom::side_offsets::SideOffsets2D;
use servo_net::image::base::Image;
use extra::arc::Arc;

pub struct RenderContext<'self> {
    canvas: &'self ~LayerBuffer,
    font_ctx: @mut FontContext,
    opts: &'self Opts
}

impl<'self> RenderContext<'self>  {
    pub fn get_draw_target(&self) -> &'self DrawTarget {
        &self.canvas.draw_target
    }

    pub fn draw_solid_color(&self, bounds: &Rect<Au>, color: Color) {
        self.canvas.draw_target.make_current();
        self.canvas.draw_target.fill_rect(&bounds.to_azure_rect(), &ColorPattern(color));
    }

    pub fn draw_border(&self,
                       bounds: &Rect<Au>,
                       border: SideOffsets2D<Au>,
                       color: SideOffsets2D<Color>) {
        let draw_opts = DrawOptions(1 as AzFloat, 0 as uint16_t);
        let stroke_fields = 2; // CAP_SQUARE
        let mut stroke_opts = StrokeOptions(0 as AzFloat, 10 as AzFloat, stroke_fields);

        let rect = bounds.to_azure_rect();
        let border = border.to_float_px();

        self.canvas.draw_target.make_current();

        // draw top border
        stroke_opts.line_width = border.top;
        let y = rect.origin.y + border.top * 0.5;
        let start = Point2D(rect.origin.x, y);
        let end = Point2D(rect.origin.x + rect.size.width, y);
        self.canvas.draw_target.stroke_line(start, end, &ColorPattern(color.top), &stroke_opts, &draw_opts);

        // draw bottom border
        stroke_opts.line_width = border.bottom;
        let y = rect.origin.y + rect.size.height - border.bottom * 0.5;
        let start = Point2D(rect.origin.x, y);
        let end = Point2D(rect.origin.x + rect.size.width, y);
        self.canvas.draw_target.stroke_line(start, end, &ColorPattern(color.bottom), &stroke_opts, &draw_opts);

        // draw left border
        stroke_opts.line_width = border.left;
        let x = rect.origin.x + border.left * 0.5;
        let start = Point2D(x, rect.origin.y);
        let end = Point2D(x, rect.origin.y + rect.size.height);
        self.canvas.draw_target.stroke_line(start, end, &ColorPattern(color.left), &stroke_opts, &draw_opts);

        // draw right border
        stroke_opts.line_width = border.right;
        let x = rect.origin.x + rect.size.width - border.right * 0.5;
        let start = Point2D(x, rect.origin.y);
        let end = Point2D(x, rect.origin.y + rect.size.height);
        self.canvas.draw_target.stroke_line(start, end, &ColorPattern(color.right), &stroke_opts, &draw_opts);
    }

    pub fn draw_image(&self, bounds: Rect<Au>, image: Arc<~Image>) {
        let image = image.get();
        let size = Size2D(image.width as i32, image.height as i32);
        let stride = image.width * 4;

        self.canvas.draw_target.make_current();
        let draw_target_ref = &self.canvas.draw_target;
        let azure_surface = draw_target_ref.create_source_surface_from_data(image.data, size,
                                                                            stride as i32, B8G8R8A8);
        let source_rect = Rect(Point2D(0 as AzFloat, 0 as AzFloat),
                               Size2D(image.width as AzFloat, image.height as AzFloat));
        let dest_rect = bounds.to_azure_rect();
        let draw_surface_options = DrawSurfaceOptions(Linear, true);
        let draw_options = DrawOptions(1.0f as AzFloat, 0);
        draw_target_ref.draw_surface(azure_surface,
                                     dest_rect,
                                     source_rect,
                                     draw_surface_options,
                                     draw_options);
    }

    pub fn clear(&self) {
        let pattern = ColorPattern(Color(1.0, 1.0, 1.0, 1.0));
        let rect = Rect(Point2D(self.canvas.rect.origin.x as AzFloat,
                                self.canvas.rect.origin.y as AzFloat),
                        Size2D(self.canvas.screen_pos.size.width as AzFloat,
                               self.canvas.screen_pos.size.height as AzFloat));
        self.canvas.draw_target.make_current();
        self.canvas.draw_target.fill_rect(&rect, &pattern);
    }
}

trait to_float {
    fn to_float(&self) -> float;
}

impl to_float for u8 {
    fn to_float(&self) -> float {
        (*self as float) / 255f
    }
}

trait ToAzureRect {
    fn to_azure_rect(&self) -> Rect<AzFloat>;
}

impl ToAzureRect for Rect<Au> {
    fn to_azure_rect(&self) -> Rect<AzFloat> {
        Rect(Point2D(self.origin.x.to_px() as AzFloat, self.origin.y.to_px() as AzFloat),
             Size2D(self.size.width.to_px() as AzFloat, self.size.height.to_px() as AzFloat))
    }
}

trait ToSideOffsetsPx {
    fn to_float_px(&self) -> SideOffsets2D<AzFloat>;
}

impl ToSideOffsetsPx for SideOffsets2D<Au> {
    fn to_float_px(&self) -> SideOffsets2D<AzFloat> {
        SideOffsets2D::new(self.top.to_px() as AzFloat,
                           self.right.to_px() as AzFloat,
                           self.bottom.to_px() as AzFloat,
                           self.left.to_px() as AzFloat)
    }
}
<commit_msg>auto merge of #766 : sammykim/servo/border-order, r=metajack<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use servo_msg::compositor_msg::LayerBuffer;
use font_context::FontContext;
use geometry::Au;
use opts::Opts;

use azure::azure_hl::{B8G8R8A8, Color, ColorPattern, DrawOptions};
use azure::azure_hl::{DrawSurfaceOptions, DrawTarget, Linear, StrokeOptions};
use azure::AzFloat;
use std::libc::types::common::c99::uint16_t;
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use geom::side_offsets::SideOffsets2D;
use servo_net::image::base::Image;
use extra::arc::Arc;

pub struct RenderContext<'self> {
    canvas: &'self ~LayerBuffer,
    font_ctx: @mut FontContext,
    opts: &'self Opts
}

impl<'self> RenderContext<'self>  {
    pub fn get_draw_target(&self) -> &'self DrawTarget {
        &self.canvas.draw_target
    }

    pub fn draw_solid_color(&self, bounds: &Rect<Au>, color: Color) {
        self.canvas.draw_target.make_current();
        self.canvas.draw_target.fill_rect(&bounds.to_azure_rect(), &ColorPattern(color));
    }

    pub fn draw_border(&self,
                       bounds: &Rect<Au>,
                       border: SideOffsets2D<Au>,
                       color: SideOffsets2D<Color>) {
        let draw_opts = DrawOptions(1 as AzFloat, 0 as uint16_t);
        let stroke_fields = 2; // CAP_SQUARE
        let mut stroke_opts = StrokeOptions(0 as AzFloat, 10 as AzFloat, stroke_fields);

        let rect = bounds.to_azure_rect();
        let border = border.to_float_px();

        self.canvas.draw_target.make_current();

        // draw top border
        stroke_opts.line_width = border.top;
        let y = rect.origin.y + border.top * 0.5;
        let start = Point2D(rect.origin.x, y);
        let end = Point2D(rect.origin.x + rect.size.width, y);
        self.canvas.draw_target.stroke_line(start, end, &ColorPattern(color.top), &stroke_opts, &draw_opts);

        // draw right border
        stroke_opts.line_width = border.right;
        let x = rect.origin.x + rect.size.width - border.right * 0.5;
        let start = Point2D(x, rect.origin.y);
        let end = Point2D(x, rect.origin.y + rect.size.height);
        self.canvas.draw_target.stroke_line(start, end, &ColorPattern(color.right), &stroke_opts, &draw_opts);

        // draw bottom border
        stroke_opts.line_width = border.bottom;
        let y = rect.origin.y + rect.size.height - border.bottom * 0.5;
        let start = Point2D(rect.origin.x, y);
        let end = Point2D(rect.origin.x + rect.size.width, y);
        self.canvas.draw_target.stroke_line(start, end, &ColorPattern(color.bottom), &stroke_opts, &draw_opts);

        // draw left border
        stroke_opts.line_width = border.left;
        let x = rect.origin.x + border.left * 0.5;
        let start = Point2D(x, rect.origin.y);
        let end = Point2D(x, rect.origin.y + rect.size.height);
        self.canvas.draw_target.stroke_line(start, end, &ColorPattern(color.left), &stroke_opts, &draw_opts);
    }

    pub fn draw_image(&self, bounds: Rect<Au>, image: Arc<~Image>) {
        let image = image.get();
        let size = Size2D(image.width as i32, image.height as i32);
        let stride = image.width * 4;

        self.canvas.draw_target.make_current();
        let draw_target_ref = &self.canvas.draw_target;
        let azure_surface = draw_target_ref.create_source_surface_from_data(image.data, size,
                                                                            stride as i32, B8G8R8A8);
        let source_rect = Rect(Point2D(0 as AzFloat, 0 as AzFloat),
                               Size2D(image.width as AzFloat, image.height as AzFloat));
        let dest_rect = bounds.to_azure_rect();
        let draw_surface_options = DrawSurfaceOptions(Linear, true);
        let draw_options = DrawOptions(1.0f as AzFloat, 0);
        draw_target_ref.draw_surface(azure_surface,
                                     dest_rect,
                                     source_rect,
                                     draw_surface_options,
                                     draw_options);
    }

    pub fn clear(&self) {
        let pattern = ColorPattern(Color(1.0, 1.0, 1.0, 1.0));
        let rect = Rect(Point2D(self.canvas.rect.origin.x as AzFloat,
                                self.canvas.rect.origin.y as AzFloat),
                        Size2D(self.canvas.screen_pos.size.width as AzFloat,
                               self.canvas.screen_pos.size.height as AzFloat));
        self.canvas.draw_target.make_current();
        self.canvas.draw_target.fill_rect(&rect, &pattern);
    }
}

trait to_float {
    fn to_float(&self) -> float;
}

impl to_float for u8 {
    fn to_float(&self) -> float {
        (*self as float) / 255f
    }
}

trait ToAzureRect {
    fn to_azure_rect(&self) -> Rect<AzFloat>;
}

impl ToAzureRect for Rect<Au> {
    fn to_azure_rect(&self) -> Rect<AzFloat> {
        Rect(Point2D(self.origin.x.to_px() as AzFloat, self.origin.y.to_px() as AzFloat),
             Size2D(self.size.width.to_px() as AzFloat, self.size.height.to_px() as AzFloat))
    }
}

trait ToSideOffsetsPx {
    fn to_float_px(&self) -> SideOffsets2D<AzFloat>;
}

impl ToSideOffsetsPx for SideOffsets2D<Au> {
    fn to_float_px(&self) -> SideOffsets2D<AzFloat> {
        SideOffsets2D::new(self.top.to_px() as AzFloat,
                           self.right.to_px() as AzFloat,
                           self.bottom.to_px() as AzFloat,
                           self.left.to_px() as AzFloat)
    }
}
<|endoftext|>


<commit_before>//! A parser for lambda expressions with
//! [De Bruijn indices](https://en.wikipedia.org/wiki/De_Bruijn_index)

use term::*;
use term::Term::*;
use self::Token::*;
use self::Error::*;
use self::Expression::*;

/// A type to represent a parsing error.
#[derive(Debug, PartialEq)]
pub enum Error {
    InvalidCharacter((usize, char)),
    InvalidExpression,
    EmptyExpression
}

#[derive(Debug, PartialEq)]
enum Token {
    Lambda,
    Lparen,
    Rparen,
    Number(usize)
}

fn tokenize(input: &str) -> Result<Vec<Token>, Error> {
    let mut chars = input.chars();
    let mut tokens = Vec::new();
    let mut position = 0;

    while let Some(c) = chars.next() {
        match c {
     '\\' | 'λ' => { tokens.push(Lambda) },
            '(' => { tokens.push(Lparen) },
            ')' => { tokens.push(Rparen) },
             x  => {
                if let Some(n) = x.to_digit(16) {
                    tokens.push(Number(n as usize))
                } else if x.is_whitespace() {
                    ()
                } else {
                    return Err(InvalidCharacter((position, x)))
                }
            }
        }
        position += if c == 'λ' { 2 } else { 1 };
    }

    Ok(tokens)
}

#[derive(Debug, PartialEq)]
enum Expression {
    Abstraction,
    Sequence(Vec<Expression>),
    Variable(usize)
}

fn _get_ast(tokens: &[Token], pos: &mut usize) -> Result<Expression, Error> {
    let mut expr = Vec::new();

    if tokens.is_empty() { return Err(EmptyExpression) }

    while *pos < tokens.len() {
        match tokens[*pos] {
            Lambda => {
                expr.push(Abstraction)
            },
            Number(i) => {
                expr.push(Variable(i))
            },
            Lparen => {
                *pos += 1;
                let subtree = try!(_get_ast(&tokens, pos));
                expr.push(subtree);
            },
            Rparen => {
                return Ok(Sequence(expr))
            }
        }
        *pos += 1;
    }

    Ok(Sequence(expr))
}

fn get_ast(tokens: &[Token]) -> Result<Expression, Error> {
    let mut pos = 0;

    _get_ast(tokens, &mut pos)
}

/// Parses the input `&str` as a lambda `Term`. The lambdas can be represented either with the
/// greek letter (λ) or a backslash (\\ - less aesthetic, but only one byte in size), the De Bruijn
/// indices start with 1 and are hexadecimal digits, and whitespaces are ignored.
///
/// # Example
/// ```
/// use lambda_calculus::parser::parse;
/// use lambda_calculus::arithmetic::{succ, pred};
///
/// assert_eq!(parse(&"λ λ λ 2 (3 2 1)"), Ok(succ()));
/// assert_eq!(parse(&r#"\ \ \ 2 (3 2 1)"#), Ok(succ()));
/// assert_eq!(parse(&"λλλ3(λλ1(24))(λ2)(λ1)"), Ok(pred()));
/// ```
pub fn parse(input: &str) -> Result<Term, Error> {
    let tokens = try!(tokenize(input));
    let ast = try!(get_ast(&tokens));

    let exprs = try!(if let Sequence(exprs) = ast { Ok(exprs) } else { Err(InvalidExpression) });

    let mut stack = Vec::new();
    let mut output = Vec::new();
    let term = fold_exprs(&exprs, &mut stack, &mut output);

    term
}

fn fold_exprs(exprs: &[Expression], stack: &mut Vec<Expression>, output: &mut Vec<Term>)
    -> Result<Term, Error>
{
    let mut iter = exprs.into_iter();

    while let Some(ref expr) = iter.next() {
        match **expr {
            Variable(i) => output.push(Var(i)),
            Abstraction => stack.push(Abstraction),
            Sequence(ref exprs) => {
                let mut stack2 = Vec::new();
                let mut output2 = Vec::new();
                let subexpr = try!(fold_exprs(&exprs, &mut stack2, &mut output2));
                output.push(subexpr)
            }
        }
    }

    let mut ret = try!(fold_terms(output.drain(..).collect()));

    while let Some(Abstraction) = stack.pop() {
        ret = abs(ret);
    }

    Ok(ret)
}

fn fold_terms(mut terms: Vec<Term>) -> Result<Term, Error> {
    if terms.len() > 1 {
        let fst = terms.remove(0);
        Ok( terms.into_iter().fold(fst, |acc, t| app(acc, t)) )
    } else if terms.len() == 1 {
        Ok( terms.pop().unwrap() )
    } else {
        Err(EmptyExpression)
    }
}

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

    #[test]
    fn tokenization_error() {
        assert_eq!(tokenize(&"λλx2"), Err(InvalidCharacter((4, 'x'))))
    }

    #[test]
    fn tokenization_success() {
        let quine = "λ 1 ( (λ 1 1) (λ λ λ λ λ 1 4 (3 (5 5) 2) ) ) 1";
        let tokens = tokenize(&quine);

        assert!(tokens.is_ok());
        assert_eq!(tokens.unwrap(), vec![Lambda, Number(1), Lparen, Lparen, Lambda, Number(1),
            Number(1), Rparen, Lparen, Lambda, Lambda, Lambda, Lambda, Lambda, Number(1),
            Number(4), Lparen, Number(3), Lparen, Number(5), Number(5), Rparen, Number(2),
            Rparen, Rparen, Rparen, Number(1)]);
    }

    #[test]
    fn alternative_lambda_parsing() {
        assert_eq!(parse(&"\\\\\\2(321)"), parse(&"λλλ2(321)"))
    }

    #[test]
    fn succ_ast() {
        let tokens = tokenize(&"λλλ2(321)").unwrap();
        let ast = get_ast(&tokens);

        assert_eq!(ast,
            Ok(Sequence(vec![
                Abstraction,
                Abstraction,
                Abstraction,
                Variable(2),
                Sequence(vec![
                    Variable(3),
                    Variable(2),
                    Variable(1)
                ])
            ])
        ));
    }

    #[test]
    fn parse_y() {
        let y = "λ(λ2(11))(λ2(11))";
        assert_eq!(parse(&y).expect("parsing Y failed!"),
            abs(
                app(
                    abs(
                        app(
                            Var(2),
                            app(Var(1), Var(1))
                        )
                    ),
                    abs(
                        app(
                            Var(2),
                            app(Var(1), Var(1))
                        )
                    )
                )
            )
        );
    }

    #[test]
    fn parse_quine() {
        let quine = "λ1((λ11)(λλλλλ14(3(55)2)))1";
        assert_eq!(parse(&quine).expect("parsing QUINE failed!"),
            abs(app(app(Var(1), app(abs(app(Var(1), Var(1))), abs(abs(abs(abs(abs(app(app(Var(1),
            Var(4)), app(app(Var(3), app(Var(5), Var(5))), Var(2)))))))))), Var(1)))
        );
    }

    #[test]
    fn parse_blc() {
        let blc = "(λ11)(λλλ1(λλλλ3(λ5(3(λ2(3(λλ3(λ123)))(4(λ4(λ31(21))))))(1(2(λ12))\
                   (λ4(λ4(λ2(14)))5))))(33)2)(λ1((λ11)(λ11)))";
        assert_eq!(parse(&blc).expect("parsing BLC failed!"),
            app(app(abs(app(Var(1), Var(1))), abs(abs(abs(app(app(app(Var(1),
            abs(abs(abs(abs(app(Var(3), abs(app(app(Var(5), app(Var(3), abs(app(app(Var(2),
            app(Var(3), abs(abs(app(Var(3), abs(app(app(Var(1), Var(2)), Var(3)))))))), app(Var(4),
            abs(app(Var(4), abs(app(app(Var(3), Var(1)), app(Var(2), Var(1))))))))))),
            app(app(Var(1), app(Var(2), abs(app(Var(1), Var(2))))), abs(app(app(Var(4),
            abs(app(Var(4), abs(app(Var(2), app(Var(1), Var(4))))))), Var(5)))))))))))),
            app(Var(3), Var(3))), Var(2)))))), abs(app(Var(1), app(abs(app(Var(1), Var(1))),
            abs(app(Var(1), Var(1)))))))
        );
    }
}
<commit_msg>begin work on a classic notation parser<commit_after>//! A parser for lambda expressions with
//! [De Bruijn indices](https://en.wikipedia.org/wiki/De_Bruijn_index)

use term::*;
use term::Term::*;
use self::Token::*;
use self::CToken::*;
use self::Error::*;
use self::Expression::*;

/// A type to represent a parsing error.
#[derive(Debug, PartialEq)]
pub enum Error {
    InvalidCharacter((usize, char)),
    InvalidExpression,
    EmptyExpression
}

#[derive(Debug, PartialEq)]
enum Token {
    Lambda,
    Lparen,
    Rparen,
    Number(usize)
}

#[derive(Debug, PartialEq)]
enum CToken {
    CLambda(String),
    CLparen,
    CRparen,
    CName(String)
}

fn tokenize(input: &str) -> Result<Vec<Token>, Error> {
    let mut chars = input.chars();
    let mut tokens = Vec::new();
    let mut position = 0;

    while let Some(c) = chars.next() {
        match c {
     '\\' | 'λ' => { tokens.push(Lambda) },
            '(' => { tokens.push(Lparen) },
            ')' => { tokens.push(Rparen) },
             x  => {
                if let Some(n) = x.to_digit(16) {
                    tokens.push(Number(n as usize))
                } else if x.is_whitespace() {
                    ()
                } else {
                    return Err(InvalidCharacter((position, x)))
                }
            }
        }
        position += if c == 'λ' { 2 } else { 1 };
    }

    Ok(tokens)
}

fn tokenize_classic(input: &str) -> Result<Vec<CToken>, Error> {
    let mut chars = input.chars();
    let mut tokens = Vec::new();
    let mut position = 0;

    while let Some(c) = chars.next() {
        match c {
            '\\' | 'λ' => {
                let mut name = String::new();
                while let Some(c) = chars.next() {
                    if c == '.' { break } else { name.push(c) }
                }
                tokens.push(CLambda(name))
            },
            '(' => { tokens.push(CLparen) },
            ')' => { tokens.push(CRparen) },
             x  => {
                if x.is_alphabetic() {
                    let mut name = x.to_string();
                    while let Some(c) = chars.next() {
                        if c.is_whitespace() {
                            break
                        } else if c == '(' {
                            tokens.push(CLparen);
                            break
                        } else if c == ')' {
                            tokens.push(CRparen);
                            break
                        } else {
                            name.push(c)
                        }
                        position += 1;
                    }
                    tokens.push(CName(name))
                } else if x.is_whitespace() {
                    ()
                } else {
                    return Err(InvalidCharacter((position, x)))
                }
            }
        }
        position += if c == 'λ' { 2 } else { 1 };
    }

    Ok(tokens)
}

fn convert_classic_tokens(tokens: &[CToken]) -> Vec<Token> {
    let mut stack = Vec::new();
    let mut pos = 0;

    _convert_classic_tokens(tokens, &mut stack, &mut pos)
}

fn _convert_classic_tokens(tokens: &[CToken], stack: &mut Vec<String>, pos: &mut usize) -> Vec<Token>
{
    let mut output = Vec::new();
    let mut inner_stack_count = 0;

    while *pos < tokens.len() {
        match tokens[*pos] {
            CLambda(ref name) => {
                output.push(Lambda);
                stack.push(name.clone());
                inner_stack_count += 1;
            },
            CLparen => {
                output.push(Lparen);
                *pos += 1;
                output.append(&mut _convert_classic_tokens(&tokens[*pos..], stack, pos));
            },
            CRparen => {
                output.push(Rparen);
                for _ in 0..inner_stack_count { stack.pop(); }
                return output
            },
            CName(ref name) => {
                let number = if stack.contains(name) {
                    stack.iter().rev().position(|t| t == name).unwrap() + 1
                } else {
                    stack.len() + 1
                };
                output.push(Number(number));
            }
        }
        *pos += 1;
    }

    output
}

#[derive(Debug, PartialEq)]
enum Expression {
    Abstraction,
    Sequence(Vec<Expression>),
    Variable(usize)
}

fn _get_ast(tokens: &[Token], pos: &mut usize) -> Result<Expression, Error> {
    let mut expr = Vec::new();

    if tokens.is_empty() { return Err(EmptyExpression) }

    while *pos < tokens.len() {
        match tokens[*pos] {
            Lambda => {
                expr.push(Abstraction)
            },
            Number(i) => {
                expr.push(Variable(i))
            },
            Lparen => {
                *pos += 1;
                let subtree = try!(_get_ast(&tokens, pos));
                expr.push(subtree);
            },
            Rparen => {
                return Ok(Sequence(expr))
            }
        }
        *pos += 1;
    }

    Ok(Sequence(expr))
}

fn get_ast(tokens: &[Token]) -> Result<Expression, Error> {
    let mut pos = 0;

    _get_ast(tokens, &mut pos)
}

/// Parses the input `&str` as a lambda `Term`. The lambdas can be represented either with the
/// greek letter (λ) or a backslash (\\ - less aesthetic, but only one byte in size), the De Bruijn
/// indices start with 1 and are hexadecimal digits, and whitespaces are ignored.
///
/// # Example
/// ```
/// use lambda_calculus::parser::parse;
/// use lambda_calculus::arithmetic::{succ, pred};
///
/// assert_eq!(parse(&"λ λ λ 2 (3 2 1)"), Ok(succ()));
/// assert_eq!(parse(&r#"\ \ \ 2 (3 2 1)"#), Ok(succ()));
/// assert_eq!(parse(&"λλλ3(λλ1(24))(λ2)(λ1)"), Ok(pred()));
/// ```
pub fn parse(input: &str) -> Result<Term, Error> {
    let tokens = try!(tokenize(input));
    let ast = try!(get_ast(&tokens));

    let exprs = try!(if let Sequence(exprs) = ast { Ok(exprs) } else { Err(InvalidExpression) });

    let mut stack = Vec::new();
    let mut output = Vec::new();
    let term = fold_exprs(&exprs, &mut stack, &mut output);

    term
}

fn fold_exprs(exprs: &[Expression], stack: &mut Vec<Expression>, output: &mut Vec<Term>)
    -> Result<Term, Error>
{
    let mut iter = exprs.into_iter();

    while let Some(ref expr) = iter.next() {
        match **expr {
            Variable(i) => output.push(Var(i)),
            Abstraction => stack.push(Abstraction),
            Sequence(ref exprs) => {
                let mut stack2 = Vec::new();
                let mut output2 = Vec::new();
                let subexpr = try!(fold_exprs(&exprs, &mut stack2, &mut output2));
                output.push(subexpr)
            }
        }
    }

    let mut ret = try!(fold_terms(output.drain(..).collect()));

    while let Some(Abstraction) = stack.pop() {
        ret = abs(ret);
    }

    Ok(ret)
}

fn fold_terms(mut terms: Vec<Term>) -> Result<Term, Error> {
    if terms.len() > 1 {
        let fst = terms.remove(0);
        Ok( terms.into_iter().fold(fst, |acc, t| app(acc, t)) )
    } else if terms.len() == 1 {
        Ok( terms.pop().unwrap() )
    } else {
        Err(EmptyExpression)
    }
}

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

    #[test]
    fn tokenization_error() {
        assert_eq!(tokenize(&"λλx2"), Err(InvalidCharacter((4, 'x'))))
    }

    #[test]
    fn tokenization_success() {
        let quine = "λ 1 ( (λ 1 1) (λ λ λ λ λ 1 4 (3 (5 5) 2) ) ) 1";
        let tokens = tokenize(&quine);

        assert!(tokens.is_ok());
        assert_eq!(tokens.unwrap(), vec![Lambda, Number(1), Lparen, Lparen, Lambda, Number(1),
            Number(1), Rparen, Lparen, Lambda, Lambda, Lambda, Lambda, Lambda, Number(1),
            Number(4), Lparen, Number(3), Lparen, Number(5), Number(5), Rparen, Number(2),
            Rparen, Rparen, Rparen, Number(1)]);
    }

    #[test]
    fn tokenization_success_classic() {
        let pred_1_cla = "λaa.λbe.λcee.aa (λde.λe.e (de be)) (λd.cee) (λd.d)";
        let pred_1_dbr = "λλλ3(λλ1(24))(λ2)(λ1)";
        let tokens_cla = tokenize_classic(&pred_1_cla);
        let tokens_dbr = tokenize(&pred_1_dbr);

        println!("{:?}\n", tokens_cla);

        assert!(tokens_cla.is_ok());
        assert!(tokens_dbr.is_ok());

        assert_eq!(convert_classic_tokens(&tokens_cla.unwrap()), tokens_dbr.unwrap());
    }

    #[test]
    fn alternative_lambda_parsing() {
        assert_eq!(parse(&"\\\\\\2(321)"), parse(&"λλλ2(321)"))
    }

    #[test]
    fn succ_ast() {
        let tokens = tokenize(&"λλλ2(321)").unwrap();
        let ast = get_ast(&tokens);

        assert_eq!(ast,
            Ok(Sequence(vec![
                Abstraction,
                Abstraction,
                Abstraction,
                Variable(2),
                Sequence(vec![
                    Variable(3),
                    Variable(2),
                    Variable(1)
                ])
            ])
        ));
    }

    #[test]
    fn parse_y() {
        let y = "λ(λ2(11))(λ2(11))";
        assert_eq!(parse(&y).expect("parsing Y failed!"),
            abs(
                app(
                    abs(
                        app(
                            Var(2),
                            app(Var(1), Var(1))
                        )
                    ),
                    abs(
                        app(
                            Var(2),
                            app(Var(1), Var(1))
                        )
                    )
                )
            )
        );
    }

    #[test]
    fn parse_quine() {
        let quine = "λ1((λ11)(λλλλλ14(3(55)2)))1";
        assert_eq!(parse(&quine).expect("parsing QUINE failed!"),
            abs(app(app(Var(1), app(abs(app(Var(1), Var(1))), abs(abs(abs(abs(abs(app(app(Var(1),
            Var(4)), app(app(Var(3), app(Var(5), Var(5))), Var(2)))))))))), Var(1)))
        );
    }

    #[test]
    fn parse_blc() {
        let blc = "(λ11)(λλλ1(λλλλ3(λ5(3(λ2(3(λλ3(λ123)))(4(λ4(λ31(21))))))(1(2(λ12))\
                   (λ4(λ4(λ2(14)))5))))(33)2)(λ1((λ11)(λ11)))";
        assert_eq!(parse(&blc).expect("parsing BLC failed!"),
            app(app(abs(app(Var(1), Var(1))), abs(abs(abs(app(app(app(Var(1),
            abs(abs(abs(abs(app(Var(3), abs(app(app(Var(5), app(Var(3), abs(app(app(Var(2),
            app(Var(3), abs(abs(app(Var(3), abs(app(app(Var(1), Var(2)), Var(3)))))))), app(Var(4),
            abs(app(Var(4), abs(app(app(Var(3), Var(1)), app(Var(2), Var(1))))))))))),
            app(app(Var(1), app(Var(2), abs(app(Var(1), Var(2))))), abs(app(app(Var(4),
            abs(app(Var(4), abs(app(Var(2), app(Var(1), Var(4))))))), Var(5)))))))))))),
            app(Var(3), Var(3))), Var(2)))))), abs(app(Var(1), app(abs(app(Var(1), Var(1))),
            abs(app(Var(1), Var(1)))))))
        );
    }
}
<|endoftext|>


<commit_before>//! A parser for lambda expressions

use term::*;
use term::Term::*;
use term::Notation::*;
use self::Token::*;
use self::CToken::*;
use self::Error::*;
use self::Expression::*;

/// A type to represent a parsing error.
#[derive(Debug, PartialEq)]
pub enum Error {
    InvalidCharacter((usize, char)),
    InvalidExpression,
    EmptyExpression
}

#[derive(Debug, PartialEq)]
enum Token {
    Lambda,
    Lparen,
    Rparen,
    Number(usize)
}

#[derive(Debug, PartialEq)]
enum CToken {
    CLambda(String),
    CLparen,
    CRparen,
    CName(String)
}

fn tokenize_dbr(input: &str) -> Result<Vec<Token>, Error> {
    let mut chars = input.chars();
    let mut tokens = Vec::new();
    let mut position = 1;

    while let Some(c) = chars.next() {
        match c {
     '\\' | 'λ' => { tokens.push(Lambda) },
            '(' => { tokens.push(Lparen) },
            ')' => { tokens.push(Rparen) },
             x  => {
                if let Some(n) = x.to_digit(16) {
                    tokens.push(Number(n as usize))
                } else if x.is_whitespace() {
                    ()
                } else {
                    return Err(InvalidCharacter((position, x)))
                }
            }
        }
        position += 1;
    }

    Ok(tokens)
}

fn tokenize_cla(input: &str) -> Result<Vec<CToken>, Error> {
    let mut chars = input.chars().peekable();
    let mut tokens = Vec::new();
    let mut position = 1;

    while let Some(c) = chars.next() {
        match c {
            '\\' | 'λ' => {
                let mut name = String::new();
                while let Some(c) = chars.next() {
                    position += 1;
                    if c == '.' {
                        break
                    } else if "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".contains(c) {
                        name.push(c)
                    } else {
                        return Err(InvalidCharacter((position, c)))
                    }
                }
                tokens.push(CLambda(name))
            },
            '(' => { tokens.push(CLparen) },
            ')' => { tokens.push(CRparen) },
             x  => {
                if x.is_whitespace() {
                    ()
                } else if "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".contains(x) {
                    let mut name = x.to_string();
                    while let Some(&c) = chars.peek() {
                        if c.is_whitespace() || c == '(' || c == ')' {
                            break
                        } else {
                            name.push(c);
                            chars.next();
                            position += 1;
                        }
                    }
                    tokens.push(CName(name))
                } else {
                    return Err(InvalidCharacter((position, x)))
                }
            }
        }
        position += 1;
    }

    Ok(tokens)
}

fn convert_classic_tokens(tokens: &[CToken]) -> Vec<Token> {
    let mut stack = Vec::new();
    let mut pos = 0;

    _convert_classic_tokens(tokens, &mut stack, &mut pos)
}

fn _convert_classic_tokens(tokens: &[CToken], stack: &mut Vec<String>, pos: &mut usize) -> Vec<Token>
{
    let mut output = Vec::new();
    let mut inner_stack_count = 0;

    while *pos < tokens.len() {
        match tokens[*pos] {
            CLambda(ref name) => {
                output.push(Lambda);
                stack.push(name.clone());
                inner_stack_count += 1;
            },
            CLparen => {
                output.push(Lparen);
                *pos += 1;
                output.append(&mut _convert_classic_tokens(tokens, stack, pos));
            },
            CRparen => {
                output.push(Rparen);
                for _ in 0..inner_stack_count { stack.pop(); }
                return output
            },
            CName(ref name) => {
                let number = if stack.contains(name) {
                    stack.iter().rev().position(|t| t == name).unwrap() + 1
                } else {
                    stack.len() + 1
                };
                output.push(Number(number));
            }
        }
        *pos += 1;
    }

    output
}

#[derive(Debug, PartialEq)]
enum Expression {
    Abstraction,
    Sequence(Vec<Expression>),
    Variable(usize)
}

fn _get_ast(tokens: &[Token], pos: &mut usize) -> Result<Expression, Error> {
    let mut expr = Vec::new();

    if tokens.is_empty() { return Err(EmptyExpression) }

    while *pos < tokens.len() {
        match tokens[*pos] {
            Lambda => {
                expr.push(Abstraction)
            },
            Number(i) => {
                expr.push(Variable(i))
            },
            Lparen => {
                *pos += 1;
                let subtree = try!(_get_ast(&tokens, pos));
                expr.push(subtree);
            },
            Rparen => {
                return Ok(Sequence(expr))
            }
        }
        *pos += 1;
    }

    Ok(Sequence(expr))
}

fn get_ast(tokens: &[Token]) -> Result<Expression, Error> {
    let mut pos = 0;

    _get_ast(tokens, &mut pos)
}

/// Parses the input `&str` as a lambda `Term`.
///
/// - lambdas can be represented either with the greek letter (λ) or a backslash (\\ -
/// less aesthetic, but only one byte in size)
/// - the identifiers in `Classic` mode are `String`s of ASCII alphabetic characters
/// - `Classic` mode ignores whitespaces where unambiguous
/// - `DeBruijn` mode ignores all whitespaces (since indices > 15 are very unlikely)
/// - the indices in the `DeBruijn` notation mode start with 1 and are hexadecimal digits
///
/// # Example
/// ```
/// use lambda_calculus::parser::parse;
/// use lambda_calculus::term::Notation::*;
/// use lambda_calculus::arithmetic::{succ, pred};
///
/// assert_eq!(parse(&"λn. λf. λx. n (λg. λh. h (g f)) (λu. x) (λu. u)", Classic), Ok(pred()));
/// assert_eq!(parse(&"λn.λf.λx.n(λg.λh.h(g f))(λu.x)(λu.u)", Classic), Ok(pred()));
///
/// assert_eq!(parse(  &"λλλ2(321)",  DeBruijn), Ok(succ()));
/// assert_eq!(parse(&r#"\\\2(321)"#, DeBruijn), Ok(succ()));
/// ```
pub fn parse(input: &str, notation: Notation) -> Result<Term, Error> {
    let tokens = if notation == DeBruijn {
        try!(tokenize_dbr(input))
    } else {
        convert_classic_tokens(&try!(tokenize_cla(input)))
    };
    let ast = try!(get_ast(&tokens));

    let exprs = try!(if let Sequence(exprs) = ast { Ok(exprs) } else { Err(InvalidExpression) });

    let mut stack = Vec::new();
    let mut output = Vec::new();
    let term = fold_exprs(&exprs, &mut stack, &mut output);

    term
}

fn fold_exprs(exprs: &[Expression], stack: &mut Vec<Expression>, output: &mut Vec<Term>)
    -> Result<Term, Error>
{
    let mut iter = exprs.into_iter();

    while let Some(ref expr) = iter.next() {
        match **expr {
            Variable(i) => output.push(Var(i)),
            Abstraction => stack.push(Abstraction),
            Sequence(ref exprs) => {
                let mut stack2 = Vec::new();
                let mut output2 = Vec::new();
                let subexpr = try!(fold_exprs(&exprs, &mut stack2, &mut output2));
                output.push(subexpr)
            }
        }
    }

    let mut ret = try!(fold_terms(output.drain(..).collect()));

    while let Some(Abstraction) = stack.pop() {
        ret = abs(ret);
    }

    Ok(ret)
}

fn fold_terms(mut terms: Vec<Term>) -> Result<Term, Error> {
    if terms.len() > 1 {
        let fst = terms.remove(0);
        Ok( terms.into_iter().fold(fst, |acc, t| app(acc, t)) )
    } else if terms.len() == 1 {
        Ok( terms.pop().unwrap() )
    } else {
        Err(EmptyExpression)
    }
}

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

    #[test]
    fn tokenization_error() {
        assert_eq!(tokenize_dbr(&"λλx2"),    Err(InvalidCharacter((3, 'x'))));
        assert_eq!(tokenize_cla(&"λa.λb a"), Err(InvalidCharacter((6, ' '))));
    }

    #[test]
    fn tokenization_success() {
        let quine = "λ 1 ( (λ 1 1) (λ λ λ λ λ 1 4 (3 (5 5) 2) ) ) 1";
        let tokens = tokenize_dbr(&quine);

        assert!(tokens.is_ok());
        assert_eq!(tokens.unwrap(), vec![Lambda, Number(1), Lparen, Lparen, Lambda, Number(1),
            Number(1), Rparen, Lparen, Lambda, Lambda, Lambda, Lambda, Lambda, Number(1),
            Number(4), Lparen, Number(3), Lparen, Number(5), Number(5), Rparen, Number(2),
            Rparen, Rparen, Rparen, Number(1)]);
    }

    #[test]
    fn tokenization_success_classic() {
        let blc_dbr = "(λ11)(λλλ1(λλλλ3(λ5(3(λ2(3(λλ3(λ123)))(4(λ4(λ31(21))))))(1(2(λ12))\
            (λ4(λ4(λ2(14)))5))))(33)2)(λ1((λ11)(λ11)))";
        let blc_cla = format!("{}", parse(&blc_dbr, DeBruijn).unwrap());

        let tokens_cla = tokenize_cla(&blc_cla);
        let tokens_dbr = tokenize_dbr(&blc_dbr);

        assert!(tokens_cla.is_ok());
        assert!(tokens_dbr.is_ok());

        assert_eq!(convert_classic_tokens(&tokens_cla.unwrap()), tokens_dbr.unwrap());
    }

    #[test]
    fn alternative_lambda_parsing() {
        assert_eq!(parse(&"\\\\\\2(321)", DeBruijn), parse(&"λλλ2(321)", DeBruijn))
    }

    #[test]
    fn succ_ast() {
        let tokens = tokenize_dbr(&"λλλ2(321)").unwrap();
        let ast = get_ast(&tokens);

        assert_eq!(ast,
            Ok(Sequence(vec![
                Abstraction,
                Abstraction,
                Abstraction,
                Variable(2),
                Sequence(vec![
                    Variable(3),
                    Variable(2),
                    Variable(1)
                ])
            ])
        ));
    }

    #[test]
    fn parse_y() {
        let y = "λ(λ2(11))(λ2(11))";
        assert_eq!(parse(&y, DeBruijn).expect("parsing Y failed!"),
            abs(
                app(
                    abs(
                        app(
                            Var(2),
                            app(Var(1), Var(1))
                        )
                    ),
                    abs(
                        app(
                            Var(2),
                            app(Var(1), Var(1))
                        )
                    )
                )
            )
        );
    }

    #[test]
    fn parse_quine() {
        let quine = "λ1((λ11)(λλλλλ14(3(55)2)))1";
        assert_eq!(parse(&quine, DeBruijn).expect("parsing QUINE failed!"),
            abs(app(app(Var(1), app(abs(app(Var(1), Var(1))), abs(abs(abs(abs(abs(app(app(Var(1),
            Var(4)), app(app(Var(3), app(Var(5), Var(5))), Var(2)))))))))), Var(1)))
        );
    }

    #[test]
    fn parse_blc() {
        let blc = "(λ11)(λλλ1(λλλλ3(λ5(3(λ2(3(λλ3(λ123)))(4(λ4(λ31(21))))))(1(2(λ12))\
                   (λ4(λ4(λ2(14)))5))))(33)2)(λ1((λ11)(λ11)))";
        assert_eq!(parse(&blc, DeBruijn).expect("parsing BLC failed!"),
            app(app(abs(app(Var(1), Var(1))), abs(abs(abs(app(app(app(Var(1),
            abs(abs(abs(abs(app(Var(3), abs(app(app(Var(5), app(Var(3), abs(app(app(Var(2),
            app(Var(3), abs(abs(app(Var(3), abs(app(app(Var(1), Var(2)), Var(3)))))))), app(Var(4),
            abs(app(Var(4), abs(app(app(Var(3), Var(1)), app(Var(2), Var(1))))))))))),
            app(app(Var(1), app(Var(2), abs(app(Var(1), Var(2))))), abs(app(app(Var(4),
            abs(app(Var(4), abs(app(Var(2), app(Var(1), Var(4))))))), Var(5)))))))))))),
            app(Var(3), Var(3))), Var(2)))))), abs(app(Var(1), app(abs(app(Var(1), Var(1))),
            abs(app(Var(1), Var(1)))))))
        );
    }
}
<commit_msg>track iterators with enumerate()<commit_after>//! A parser for lambda expressions

use term::*;
use term::Term::*;
use term::Notation::*;
use self::Token::*;
use self::CToken::*;
use self::Error::*;
use self::Expression::*;

/// A type to represent a parsing error.
#[derive(Debug, PartialEq)]
pub enum Error {
    InvalidCharacter((usize, char)),
    InvalidExpression,
    EmptyExpression
}

#[derive(Debug, PartialEq)]
enum Token {
    Lambda,
    Lparen,
    Rparen,
    Number(usize)
}

#[derive(Debug, PartialEq)]
enum CToken {
    CLambda(String),
    CLparen,
    CRparen,
    CName(String)
}

fn tokenize_dbr(input: &str) -> Result<Vec<Token>, Error> {
    let mut chars = input.chars().enumerate();
    let mut tokens = Vec::new();

    while let Some((i, c)) = chars.next() {
        match c {
     '\\' | 'λ' => { tokens.push(Lambda) },
            '(' => { tokens.push(Lparen) },
            ')' => { tokens.push(Rparen) },
             x  => {
                if let Some(n) = x.to_digit(16) {
                    tokens.push(Number(n as usize))
                } else if x.is_whitespace() {
                    ()
                } else {
                    return Err(InvalidCharacter((i + 1, x)))
                }
            }
        }
    }

    Ok(tokens)
}

fn tokenize_cla(input: &str) -> Result<Vec<CToken>, Error> {
    let mut chars = input.chars().enumerate().peekable();
    let mut tokens = Vec::new();

    while let Some((i, c)) = chars.next() {
        match c {
            '\\' | 'λ' => {
                let mut name = String::new();
                while let Some((i, c)) = chars.next() {
                    if c == '.' {
                        break
                    } else if "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".contains(c) {
                        name.push(c)
                    } else {
                        return Err(InvalidCharacter((i + 1, c)))
                    }
                }
                tokens.push(CLambda(name))
            },
            '(' => { tokens.push(CLparen) },
            ')' => { tokens.push(CRparen) },
             x  => {
                if x.is_whitespace() {
                    ()
                } else if "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".contains(x) {
                    let mut name = x.to_string();
                    while let Some(&(_, c)) = chars.peek() {
                        if c.is_whitespace() || c == '(' || c == ')' {
                            break
                        } else {
                            name.push(c);
                            chars.next();
                        }
                    }
                    tokens.push(CName(name))
                } else {
                    return Err(InvalidCharacter((i + 1, x)))
                }
            }
        }
    }

    Ok(tokens)
}

fn convert_classic_tokens(tokens: &[CToken]) -> Vec<Token> {
    let mut stack = Vec::new();
    let mut pos = 0;

    _convert_classic_tokens(tokens, &mut stack, &mut pos)
}

fn _convert_classic_tokens(tokens: &[CToken], stack: &mut Vec<String>, pos: &mut usize) -> Vec<Token>
{
    let mut output = Vec::new();
    let mut inner_stack_count = 0;

    while *pos < tokens.len() {
        match tokens[*pos] {
            CLambda(ref name) => {
                output.push(Lambda);
                stack.push(name.clone());
                inner_stack_count += 1;
            },
            CLparen => {
                output.push(Lparen);
                *pos += 1;
                output.append(&mut _convert_classic_tokens(tokens, stack, pos));
            },
            CRparen => {
                output.push(Rparen);
                for _ in 0..inner_stack_count { stack.pop(); }
                return output
            },
            CName(ref name) => {
                let number = if stack.contains(name) {
                    stack.iter().rev().position(|t| t == name).unwrap() + 1
                } else {
                    stack.len() + 1
                };
                output.push(Number(number));
            }
        }
        *pos += 1;
    }

    output
}

#[derive(Debug, PartialEq)]
enum Expression {
    Abstraction,
    Sequence(Vec<Expression>),
    Variable(usize)
}

fn _get_ast(tokens: &[Token], pos: &mut usize) -> Result<Expression, Error> {
    let mut expr = Vec::new();

    if tokens.is_empty() { return Err(EmptyExpression) }

    while *pos < tokens.len() {
        match tokens[*pos] {
            Lambda => {
                expr.push(Abstraction)
            },
            Number(i) => {
                expr.push(Variable(i))
            },
            Lparen => {
                *pos += 1;
                let subtree = try!(_get_ast(&tokens, pos));
                expr.push(subtree);
            },
            Rparen => {
                return Ok(Sequence(expr))
            }
        }
        *pos += 1;
    }

    Ok(Sequence(expr))
}

fn get_ast(tokens: &[Token]) -> Result<Expression, Error> {
    let mut pos = 0;

    _get_ast(tokens, &mut pos)
}

/// Parses the input `&str` as a lambda `Term`.
///
/// - lambdas can be represented either with the greek letter (λ) or a backslash (\\ -
/// less aesthetic, but only one byte in size)
/// - the identifiers in `Classic` mode are `String`s of ASCII alphabetic characters
/// - `Classic` mode ignores whitespaces where unambiguous
/// - `DeBruijn` mode ignores all whitespaces (since indices > 15 are very unlikely)
/// - the indices in the `DeBruijn` notation mode start with 1 and are hexadecimal digits
///
/// # Example
/// ```
/// use lambda_calculus::parser::parse;
/// use lambda_calculus::term::Notation::*;
/// use lambda_calculus::arithmetic::{succ, pred};
///
/// assert_eq!(parse(&"λn. λf. λx. n (λg. λh. h (g f)) (λu. x) (λu. u)", Classic), Ok(pred()));
/// assert_eq!(parse(&"λn.λf.λx.n(λg.λh.h(g f))(λu.x)(λu.u)", Classic), Ok(pred()));
///
/// assert_eq!(parse(  &"λλλ2(321)",  DeBruijn), Ok(succ()));
/// assert_eq!(parse(&r#"\\\2(321)"#, DeBruijn), Ok(succ()));
/// ```
pub fn parse(input: &str, notation: Notation) -> Result<Term, Error> {
    let tokens = if notation == DeBruijn {
        try!(tokenize_dbr(input))
    } else {
        convert_classic_tokens(&try!(tokenize_cla(input)))
    };
    let ast = try!(get_ast(&tokens));

    let exprs = try!(if let Sequence(exprs) = ast { Ok(exprs) } else { Err(InvalidExpression) });

    let mut stack = Vec::new();
    let mut output = Vec::new();
    let term = fold_exprs(&exprs, &mut stack, &mut output);

    term
}

fn fold_exprs(exprs: &[Expression], stack: &mut Vec<Expression>, output: &mut Vec<Term>)
    -> Result<Term, Error>
{
    let mut iter = exprs.into_iter();

    while let Some(ref expr) = iter.next() {
        match **expr {
            Variable(i) => output.push(Var(i)),
            Abstraction => stack.push(Abstraction),
            Sequence(ref exprs) => {
                let mut stack2 = Vec::new();
                let mut output2 = Vec::new();
                let subexpr = try!(fold_exprs(&exprs, &mut stack2, &mut output2));
                output.push(subexpr)
            }
        }
    }

    let mut ret = try!(fold_terms(output.drain(..).collect()));

    while let Some(Abstraction) = stack.pop() {
        ret = abs(ret);
    }

    Ok(ret)
}

fn fold_terms(mut terms: Vec<Term>) -> Result<Term, Error> {
    if terms.len() > 1 {
        let fst = terms.remove(0);
        Ok( terms.into_iter().fold(fst, |acc, t| app(acc, t)) )
    } else if terms.len() == 1 {
        Ok( terms.pop().unwrap() )
    } else {
        Err(EmptyExpression)
    }
}

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

    #[test]
    fn tokenization_error() {
        assert_eq!(tokenize_dbr(&"λλx2"),    Err(InvalidCharacter((3, 'x'))));
        assert_eq!(tokenize_cla(&"λa.λb a"), Err(InvalidCharacter((6, ' '))));
    }

    #[test]
    fn tokenization_success() {
        let quine = "λ 1 ( (λ 1 1) (λ λ λ λ λ 1 4 (3 (5 5) 2) ) ) 1";
        let tokens = tokenize_dbr(&quine);

        assert!(tokens.is_ok());
        assert_eq!(tokens.unwrap(), vec![Lambda, Number(1), Lparen, Lparen, Lambda, Number(1),
            Number(1), Rparen, Lparen, Lambda, Lambda, Lambda, Lambda, Lambda, Number(1),
            Number(4), Lparen, Number(3), Lparen, Number(5), Number(5), Rparen, Number(2),
            Rparen, Rparen, Rparen, Number(1)]);
    }

    #[test]
    fn tokenization_success_classic() {
        let blc_dbr = "(λ11)(λλλ1(λλλλ3(λ5(3(λ2(3(λλ3(λ123)))(4(λ4(λ31(21))))))(1(2(λ12))\
            (λ4(λ4(λ2(14)))5))))(33)2)(λ1((λ11)(λ11)))";
        let blc_cla = format!("{}", parse(&blc_dbr, DeBruijn).unwrap());

        let tokens_cla = tokenize_cla(&blc_cla);
        let tokens_dbr = tokenize_dbr(&blc_dbr);

        assert!(tokens_cla.is_ok());
        assert!(tokens_dbr.is_ok());

        assert_eq!(convert_classic_tokens(&tokens_cla.unwrap()), tokens_dbr.unwrap());
    }

    #[test]
    fn alternative_lambda_parsing() {
        assert_eq!(parse(&"\\\\\\2(321)", DeBruijn), parse(&"λλλ2(321)", DeBruijn))
    }

    #[test]
    fn succ_ast() {
        let tokens = tokenize_dbr(&"λλλ2(321)").unwrap();
        let ast = get_ast(&tokens);

        assert_eq!(ast,
            Ok(Sequence(vec![
                Abstraction,
                Abstraction,
                Abstraction,
                Variable(2),
                Sequence(vec![
                    Variable(3),
                    Variable(2),
                    Variable(1)
                ])
            ])
        ));
    }

    #[test]
    fn parse_y() {
        let y = "λ(λ2(11))(λ2(11))";
        assert_eq!(parse(&y, DeBruijn).expect("parsing Y failed!"),
            abs(
                app(
                    abs(
                        app(
                            Var(2),
                            app(Var(1), Var(1))
                        )
                    ),
                    abs(
                        app(
                            Var(2),
                            app(Var(1), Var(1))
                        )
                    )
                )
            )
        );
    }

    #[test]
    fn parse_quine() {
        let quine = "λ1((λ11)(λλλλλ14(3(55)2)))1";
        assert_eq!(parse(&quine, DeBruijn).expect("parsing QUINE failed!"),
            abs(app(app(Var(1), app(abs(app(Var(1), Var(1))), abs(abs(abs(abs(abs(app(app(Var(1),
            Var(4)), app(app(Var(3), app(Var(5), Var(5))), Var(2)))))))))), Var(1)))
        );
    }

    #[test]
    fn parse_blc() {
        let blc = "(λ11)(λλλ1(λλλλ3(λ5(3(λ2(3(λλ3(λ123)))(4(λ4(λ31(21))))))(1(2(λ12))\
                   (λ4(λ4(λ2(14)))5))))(33)2)(λ1((λ11)(λ11)))";
        assert_eq!(parse(&blc, DeBruijn).expect("parsing BLC failed!"),
            app(app(abs(app(Var(1), Var(1))), abs(abs(abs(app(app(app(Var(1),
            abs(abs(abs(abs(app(Var(3), abs(app(app(Var(5), app(Var(3), abs(app(app(Var(2),
            app(Var(3), abs(abs(app(Var(3), abs(app(app(Var(1), Var(2)), Var(3)))))))), app(Var(4),
            abs(app(Var(4), abs(app(app(Var(3), Var(1)), app(Var(2), Var(1))))))))))),
            app(app(Var(1), app(Var(2), abs(app(Var(1), Var(2))))), abs(app(app(Var(4),
            abs(app(Var(4), abs(app(Var(2), app(Var(1), Var(4))))))), Var(5)))))))))))),
            app(Var(3), Var(3))), Var(2)))))), abs(app(Var(1), app(abs(app(Var(1), Var(1))),
            abs(app(Var(1), Var(1)))))))
        );
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{
    BufReader,
    BufRead,
};

use regex::{
    Regex,
    RegexBuilder,
};

use super::Error;
use super::Result;

use types::*;

pub enum State {
    Init,
    FeatureAndTags,
    Feature,
    FeatureWithBackground,
    FeatureWithDescription,
    FeatureWithLanguage,
    FeatureWithTags,
}

pub fn parse(filename: &str) -> Result<Feature> {
    let file = try!(File::open(filename));

    let mut feature = Feature {
        filename: filename.to_owned(),
        name: None,
        description: None,
        background: None,
        items: Vec::new(),
    };
    let mut state = State::Init;

    for line in BufReader::new(file).lines() {
        let line = try!(line);

        match state {
            State::Init => {
                lazy_static! {
                    static ref RE: Regex = prepare_regex(&[FEATURE_RE, LANGUAGE_RE, TAGS_RE], true);
                }

                match try!(parse_line(&line, &RE)) {
                    _ =>
                        unimplemented!()
                }
            }

            _ => {
                return Err(Error::from_str("unhandled state"));
            }
        }
    }

    Ok(feature)
}

// nay be used only once and we ignore it
static LANGUAGE_RE: &'static str = r"(Language:\s*(?P<language>\S+))";

static TAGS_RE: &'static str = r"(?P<tags>@\w+(\s+@\w+)*)";

static FEATURE_RE: &'static str = r"(Feature:\s*(?P<feature>.*))";
static BACKGROUND_RE: &'static str = r"(Background:\s*(?P<background>.*))";
static SCENARIO_RE: &'static str = r"(Scenario:\s*(?P<scenario>.*))";
static SCENARIO_OUTLINE_RE: &'static str = r"(Scenario Outline:\s*(?P<outline>.*))";
static GIVEN_STEP_RE: &'static str = r"(Given\s+(?P<given>.*))";
static WHEN_STEP_RE: &'static str = r"(When\s+(?P<when>.*))";
static THEN_STEP_RE: &'static str = r"(Then\s+(?P<then>.*))";
static AND_STEP_RE: &'static str = r"(And\s+(?P<and>.*))";
static BUT_STEP_RE: &'static str = r"(But\s+(?P<but>.*))";
static EXAMPLES_RE: &'static str = r"(Examples:\s*(?P<examples>.*))";

static TABLE_RE: &'static str = r"(?P<table>\|.*\|)";
static DOCSTRING_RE: &'static str = "(?P<docstring>\"\"\"|''')";

static OTHER_RE: &'static str = "(?P<other>[^#]*)";

static INDENT_RE: &'static str = r"(?P<indent>\s*)";
static COMMENT_RE: &'static str = r"\s*(#\s*(?P<comment>.*))?";

fn prepare_regex(bits: &[&str], detect_comment: bool) -> Regex {
    let actual_bits = &bits.join("|");
    let mut pattern: Vec<&str> = vec!("^",
                                      INDENT_RE,
                                      "(",
                                      &actual_bits,
                                      ")");
    if detect_comment {
        pattern.push(COMMENT_RE);
    }

    pattern.push("$");

    RegexBuilder::new(&pattern.join(r""))
                 .case_insensitive(true)
                 .ignore_whitespace(true)
                 .compile()
                 .unwrap()
}

enum LineKind {
    EmptyLine,
    Tags,
    Feature,
    Background,
    Scenario,
    ScenarioOutline,
    GivenStep,
    WhenStep,
    ThenStep,
    AndStep,
    ButStep,
    Examples,
    Table,
    DocString,
    Other,
}

struct Line {
    pub kind: LineKind,
    pub value: Option<String>,
    pub indent: usize,
    pub comment: Option<String>,
}

fn parse_line(line: &str, regex: &Regex) -> Result<Line> {
    let mut kind: Option<String> = None;
    let mut value: Option<String> = None;
    let mut indent: usize = 0;
    let mut comment: Option<String> = None;

    let captures = try!(regex.captures(line)
                             .ok_or_else(|| Error::from_str(&format!("Can't parse: {}", line))));

    for (name, actual_value) in captures.iter_named() {
        match name {
            "indent" => {
                indent = actual_value.map_or(0, |value| value.len());
            }

            "comment" => {
                comment = actual_value.map(|value| value.to_owned());
            }

            _ => {
                match actual_value {
                    None => {
                        kind = Some(name.to_owned());
                        value = actual_value.map(|value| value.to_owned());
                    }

                    Some(other) => {
                        return Err(Error::from_str(&format!("Double match: {} and {}", other, name)));
                    }
                }
            }
        }
    }

    let kind = match try!(kind.ok_or_else(|| Error::from_str(&format!("Could not determine line kind for: {}", line)))).as_str() {
        "tags" =>
            LineKind::Tags,

        "feature" =>
            LineKind::Feature,

        "background" =>
            LineKind::Background,

        "scenario" =>
            LineKind::Scenario,

        "outline" =>
            LineKind::ScenarioOutline,

        "given" =>
            LineKind::GivenStep,

        "when" =>
            LineKind::WhenStep,

        "then" =>
            LineKind::ThenStep,

        "and" =>
            LineKind::AndStep,

        "but" =>
            LineKind::ButStep,

        "examples" =>
            LineKind::Examples,

        "table" =>
            LineKind::Table,

        "docstring" =>
            LineKind::DocString,

        "other" =>
            LineKind::Other,

        kind @ _ => {
            return Err(Error::from_str(&format!("Unknown kind: {}", kind)));
        }
    };

    Ok(Line{
        kind: kind,
        value: value,
        indent: indent,
        comment: comment
    })
}
<commit_msg>make sure "some" parsing works<commit_after>use std::fs::File;
use std::io::{
    BufReader,
    BufRead,
};

use regex::{
    Regex,
    RegexBuilder,
};

use super::Error;
use super::Result;

use types::*;

pub enum State {
    Init,
    FeatureAndTags,
    Feature,
    FeatureWithBackground,
    FeatureWithDescription,
    FeatureWithLanguage,
    FeatureWithTags,
}

pub fn parse(filename: &str) -> Result<Feature> {
    let file = try!(File::open(filename));

    let mut feature = Feature {
        filename: filename.to_owned(),
        name: None,
        description: None,
        background: None,
        items: Vec::new(),
    };
    let mut state = State::Init;

    for line in BufReader::new(file).lines() {
        let line = try!(line);

        match state {
            State::Init => {
                lazy_static! {
                    static ref RE: Regex = prepare_regex(&[FEATURE_RE, LANGUAGE_RE, TAGS_RE], true);
                }

                match try!(parse_line(&line, &RE)) {
                    _ =>
                        unimplemented!()
                }
            }

            _ => {
                return Err(Error::from_str("unhandled state"));
            }
        }
    }

    Ok(feature)
}

// nay be used only once and we ignore it
static LANGUAGE_RE: &'static str = r"(Language:\s*(?P<language>\S+))";

static TAGS_RE: &'static str = r"(?P<tags>@\w+(\s+@\w+)*)";

static FEATURE_RE: &'static str = r"(Feature:\s*(?P<feature>.*))";
static BACKGROUND_RE: &'static str = r"(Background:\s*(?P<background>.*))";
static SCENARIO_RE: &'static str = r"(Scenario:\s*(?P<scenario>.*))";
static SCENARIO_OUTLINE_RE: &'static str = r"(Scenario Outline:\s*(?P<outline>.*))";
static GIVEN_STEP_RE: &'static str = r"(Given\s+(?P<given>.*))";
static WHEN_STEP_RE: &'static str = r"(When\s+(?P<when>.*))";
static THEN_STEP_RE: &'static str = r"(Then\s+(?P<then>.*))";
static AND_STEP_RE: &'static str = r"(And\s+(?P<and>.*))";
static BUT_STEP_RE: &'static str = r"(But\s+(?P<but>.*))";
static EXAMPLES_RE: &'static str = r"(Examples:\s*(?P<examples>.*))";

static TABLE_RE: &'static str = r"(?P<table>\|.*\|)";
static DOCSTRING_RE: &'static str = "(?P<docstring>\"\"\"|''')";

static OTHER_RE: &'static str = "(?P<other>[^#]*)";

static INDENT_RE: &'static str = r"(?P<indent>\s*)";
// '#' requires escaping because of the way we compile regex
static COMMENT_RE: &'static str = r"\s*(\#\s*(?P<comment>.*))?";

fn prepare_regex(bits: &[&str], detect_comment: bool) -> Regex {
    let actual_bits = &bits.join("|");
    let mut pattern: Vec<&str> = vec!("^",
                                      INDENT_RE,
                                      "(",
                                      &actual_bits,
                                      ")");
    if detect_comment {
        pattern.push(COMMENT_RE);
    }

    pattern.push("$");

    RegexBuilder::new(&pattern.join(r""))
                 .case_insensitive(true)
                 .ignore_whitespace(true)
                 .compile()
                 .unwrap()
}

enum LineKind {
    EmptyLine,
    Tags,
    Feature,
    Background,
    Scenario,
    ScenarioOutline,
    GivenStep,
    WhenStep,
    ThenStep,
    AndStep,
    ButStep,
    Examples,
    Table,
    DocString,
    Other,
}

struct Line {
    pub kind: LineKind,
    pub value: Option<String>,
    pub indent: usize,
    pub comment: Option<String>,
}

fn parse_line(line: &str, regex: &Regex) -> Result<Line> {
    let mut kind: Option<String> = None;
    let mut value: Option<String> = None;
    let mut indent: usize = 0;
    let mut comment: Option<String> = None;

    let captures = try!(regex.captures(line)
                             .ok_or_else(|| Error::from_str(&format!("Can't parse: {}", line))));

    for (name, actual_value) in captures.iter_named() {
        match name {
            "indent" => {
                indent = actual_value.map_or(0, |value| value.len());
            }

            "comment" => {
                comment = actual_value.map(|value| value.to_owned());
            }

            _ => {
                // ignore None results
                if let Some(actual_value) = actual_value {
                    if let Some(other) = kind {
                        return Err(Error::from_str(&format!("Double match: {} and {}", other, name)));
                    }

                    kind = Some(name.to_owned());
                    value = Some(actual_value.to_owned());
                }
            }
        }
    }

    let kind = match kind.unwrap_or(String::new()).as_str() {
        "" =>
            LineKind::EmptyLine,

        "tags" =>
            LineKind::Tags,

        "feature" =>
            LineKind::Feature,

        "background" =>
            LineKind::Background,

        "scenario" =>
            LineKind::Scenario,

        "outline" =>
            LineKind::ScenarioOutline,

        "given" =>
            LineKind::GivenStep,

        "when" =>
            LineKind::WhenStep,

        "then" =>
            LineKind::ThenStep,

        "and" =>
            LineKind::AndStep,

        "but" =>
            LineKind::ButStep,

        "examples" =>
            LineKind::Examples,

        "table" =>
            LineKind::Table,

        "docstring" =>
            LineKind::DocString,

        "other" =>
            LineKind::Other,

        kind @ _ => {
            return Err(Error::from_str(&format!("Unknown kind: {}", kind)));
        }
    };

    Ok(Line{
        kind: kind,
        value: value,
        indent: indent,
        comment: comment
    })
}
<|endoftext|>


<commit_before>use std::{io, process};
use std::str::FromStr;
use argparse::{ArgumentParser, List, Store, StoreOption, StoreTrue};

use pprint::{self, Config as PpConfig, Mode as PpMode};

#[derive(Copy, Clone, Debug)]
enum CommandType {
    Solve,
    Test,
    Bench,
}

impl CommandType {
    fn setup_parser<'parser>(&'parser mut self,
                             ap: &mut ArgumentParser<'parser>,
                             args: &'parser mut Vec<String>) {
        ap.set_description("Slither link solver - Command line interface");
        let _ = ap.refer(self)
                  .required()
                  .add_argument("command", Store, "command to run (solve, test)");
        let _ = ap.refer(args)
                  .add_argument("arguments", List, "arguments for command");
        ap.stop_on_first_argument(true);
    }
}

impl Default for CommandType {
    fn default() -> CommandType {
        CommandType::Solve
    }
}

impl FromStr for CommandType {
    type Err = ();

    fn from_str(src: &str) -> Result<CommandType, ()> {
        match src {
            "solve" => Ok(CommandType::Solve),
            "test" => Ok(CommandType::Test),
            "bench" => Ok(CommandType::Bench),
            _ => Err(()),
        }
    }
}

#[derive(Clone, Debug)]
struct SolveArgs {
    derive_all: bool,
    output_mode: OutputModeArg,
    width: Size,
    height: Size,
    input_files: Vec<String>,
}

impl SolveArgs {
    fn setup_parser<'parser>(&'parser mut self, ap: &mut ArgumentParser<'parser>) {
        ap.set_description("Solve the given problem(s)");
        let _ = ap.refer(&mut self.derive_all)
                  .add_option(&["--all"], StoreTrue, "derive all solutions (if any).");
        let _ = ap.refer(&mut self.output_mode)
                  .add_option(&["--output-mode"],
                              Store,
                              "specify output mode (auto, pretty-color, pretty-ascii, raw, none) \
                               [default: auto]");
        let _ = ap.refer(&mut self.width)
                  .add_option(&["--width"], Store, "specify cell width [default: 2]");
        let _ = ap.refer(&mut self.height)
                  .add_option(&["--height"], Store, "specify cell width [default: 1]");
        let _ = ap.refer(&mut self.input_files)
                  .add_argument("input_files", List, "puzzle files to solve.");
    }

    fn output_mode(&self) -> OutputMode {
        let ppmode = match self.output_mode {
            OutputModeArg::Auto => {
                if pprint::is_pprintable() {
                    PpMode::Color
                } else {
                    PpMode::Ascii
                }
            }
            OutputModeArg::PrettyColor => PpMode::Color,
            OutputModeArg::PrettyAscii => PpMode::Ascii,
            OutputModeArg::Raw => return OutputMode::Raw,
            OutputModeArg::None => return OutputMode::None,
        };
        OutputMode::Pretty(PpConfig {
            mode: ppmode,
            cell_width: self.width.0,
            cell_height: self.height.0,
        })
    }
}

impl Default for SolveArgs {
    fn default() -> SolveArgs {
        SolveArgs {
            derive_all: false,
            output_mode: OutputModeArg::Auto,
            width: Size(2),
            height: Size(1),
            input_files: vec![],
        }
    }
}

impl Into<SolveConfig> for SolveArgs {
    fn into(self) -> SolveConfig {
        SolveConfig {
            derive_all: self.derive_all,
            output_mode: self.output_mode(),
            input_files: self.input_files,
        }
    }
}

#[derive(Copy, Clone, Debug)]
struct Size(usize);
impl FromStr for Size {
    type Err = ();

    fn from_str(src: &str) -> Result<Size, ()> {
        let val = usize::from_str(src);
        if let Ok(v) = val {
            if v != 0 {
                return Ok(Size(v));
            }
        }
        Err(())

    }
}

#[derive(Copy, Clone, Debug)]
enum OutputModeArg {
    Auto,
    PrettyColor,
    PrettyAscii,
    Raw,
    None,
}

impl FromStr for OutputModeArg {
    type Err = ();

    fn from_str(src: &str) -> Result<OutputModeArg, ()> {
        match src {
            "auto" => Ok(OutputModeArg::Auto),
            "pretty-color" => Ok(OutputModeArg::PrettyColor),
            "pretty-ascii" => Ok(OutputModeArg::PrettyAscii),
            "raw" => Ok(OutputModeArg::Raw),
            "none" => Ok(OutputModeArg::None),
            _ => Err(()),
        }
    }
}

#[derive(Clone, Debug)]
struct TestArgs {
    derive_all: bool,
    input_files: Vec<String>,
}

impl TestArgs {
    fn setup_parser<'parser>(&'parser mut self, ap: &mut ArgumentParser<'parser>) {
        ap.set_description("Test the given problem(s)");
        let _ = ap.refer(&mut self.derive_all)
                  .add_option(&["--all"], StoreTrue, "derive all solutions (if any).");
        let _ = ap.refer(&mut self.input_files)
                  .add_argument("input_files", List, "puzzle files to solve.");
    }
}

impl Default for TestArgs {
    fn default() -> TestArgs {
        TestArgs {
            derive_all: false,
            input_files: vec![],
        }
    }
}

impl Into<TestConfig> for TestArgs {
    fn into(self) -> TestConfig {
        TestConfig {
            derive_all: self.derive_all,
            input_files: self.input_files,
        }
    }
}

#[derive(Clone, Debug)]
struct BenchArgs {
    derive_all: bool,
    only_hardest: Option<usize>,
    input_files: Vec<String>,
}

impl BenchArgs {
    fn setup_parser<'parser>(&'parser mut self, ap: &mut ArgumentParser<'parser>) {
        ap.set_description("Bench the given problem(s)");
        let _ = ap.refer(&mut self.derive_all)
                  .add_option(&["--all"], StoreTrue, "derive all solutions (if any).");
        let _ = ap.refer(&mut self.only_hardest)
                  .add_option(&["--only-hardest"],
                              StoreOption,
                              "measure only hardest n problems.")
                  .metavar("n");
        let _ = ap.refer(&mut self.input_files)
                  .add_argument("input_files", List, "puzzle files to solve.");
    }
}

impl Default for BenchArgs {
    fn default() -> BenchArgs {
        BenchArgs {
            derive_all: false,
            only_hardest: None,
            input_files: vec![],
        }
    }
}

impl Into<BenchConfig> for BenchArgs {
    fn into(self) -> BenchConfig {
        BenchConfig {
            derive_all: self.derive_all,
            only_hardest: self.only_hardest,
            input_files: self.input_files,
        }
    }
}

#[derive(Clone, Debug)]
pub enum Config {
    Solve(SolveConfig),
    Test(TestConfig),
    Bench(BenchConfig),
}

#[derive(Clone, Debug)]
pub struct SolveConfig {
    pub derive_all: bool,
    pub output_mode: OutputMode,
    pub input_files: Vec<String>,
}

#[derive(Clone, Debug)]
pub struct TestConfig {
    pub derive_all: bool,
    pub input_files: Vec<String>,
}

#[derive(Clone, Debug)]
pub struct BenchConfig {
    pub derive_all: bool,
    pub only_hardest: Option<usize>,
    pub input_files: Vec<String>,
}

#[derive(Copy, Clone, Debug)]
pub enum OutputMode {
    Pretty(PpConfig),
    Raw,
    None,
}

impl Config {
    pub fn parse() -> Config {
        let mut command = CommandType::default();
        let mut args = vec![];
        {
            let mut ap = ArgumentParser::new();
            command.setup_parser(&mut ap, &mut args);
            ap.parse_args_or_exit();
        }

        args.insert(0, format!("{:?}", command));

        match command {
            CommandType::Solve => {
                let mut sub_args = SolveArgs::default();
                {
                    let mut ap = ArgumentParser::new();
                    sub_args.setup_parser(&mut ap);
                    if let Err(x) = ap.parse(args, &mut io::stdout(), &mut io::stderr()) {
                        process::exit(x);
                    }
                }
                Config::Solve(sub_args.into())
            }
            CommandType::Test => {
                let mut sub_args = TestArgs::default();
                {
                    let mut ap = ArgumentParser::new();
                    sub_args.setup_parser(&mut ap);
                    if let Err(x) = ap.parse(args, &mut io::stdout(), &mut io::stderr()) {
                        process::exit(x);
                    }
                }
                Config::Test(sub_args.into())
            }
            CommandType::Bench => {
                let mut sub_args = BenchArgs::default();
                {
                    let mut ap = ArgumentParser::new();
                    sub_args.setup_parser(&mut ap);
                    if let Err(x) = ap.parse(args, &mut io::stdout(), &mut io::stderr()) {
                        process::exit(x);
                    }
                }
                Config::Bench(sub_args.into())
            }
        }
    }
}
<commit_msg>refactor parse arguments<commit_after>use std::{io, process};
use std::str::FromStr;
use argparse::{ArgumentParser, List, Store, StoreOption, StoreTrue};

use pprint::{self, Config as PpConfig, Mode as PpMode};

#[derive(Copy, Clone, Debug)]
enum CommandType {
    Solve,
    Test,
    Bench,
}

impl CommandType {
    fn setup_parser<'parser>(&'parser mut self,
                             ap: &mut ArgumentParser<'parser>,
                             args: &'parser mut Vec<String>) {
        ap.set_description("Slither link solver - Command line interface");
        let _ = ap.refer(self)
                  .required()
                  .add_argument("command", Store, "command to run (solve, test)");
        let _ = ap.refer(args)
                  .add_argument("arguments", List, "arguments for command");
        ap.stop_on_first_argument(true);
    }
}

impl Default for CommandType {
    fn default() -> CommandType {
        CommandType::Solve
    }
}

impl FromStr for CommandType {
    type Err = ();

    fn from_str(src: &str) -> Result<CommandType, ()> {
        match src {
            "solve" => Ok(CommandType::Solve),
            "test" => Ok(CommandType::Test),
            "bench" => Ok(CommandType::Bench),
            _ => Err(()),
        }
    }
}

trait SetupParser {
    fn setup_parser<'parser>(&'parser mut self, ap: &mut ArgumentParser<'parser>);
}

#[derive(Clone, Debug)]
struct SolveArgs {
    derive_all: bool,
    output_mode: OutputModeArg,
    width: Size,
    height: Size,
    input_files: Vec<String>,
}

impl SetupParser for SolveArgs {
    fn setup_parser<'parser>(&'parser mut self, ap: &mut ArgumentParser<'parser>) {
        ap.set_description("Solve the given problem(s)");
        let _ = ap.refer(&mut self.derive_all)
                  .add_option(&["--all"], StoreTrue, "derive all solutions (if any).");
        let _ = ap.refer(&mut self.output_mode)
                  .add_option(&["--output-mode"],
                              Store,
                              "specify output mode (auto, pretty-color, pretty-ascii, raw, none) \
                               [default: auto]");
        let _ = ap.refer(&mut self.width)
                  .add_option(&["--width"], Store, "specify cell width [default: 2]");
        let _ = ap.refer(&mut self.height)
                  .add_option(&["--height"], Store, "specify cell width [default: 1]");
        let _ = ap.refer(&mut self.input_files)
                  .add_argument("input_files", List, "puzzle files to solve.");
    }
}

impl SolveArgs {
    fn output_mode(&self) -> OutputMode {
        let ppmode = match self.output_mode {
            OutputModeArg::Auto => {
                if pprint::is_pprintable() {
                    PpMode::Color
                } else {
                    PpMode::Ascii
                }
            }
            OutputModeArg::PrettyColor => PpMode::Color,
            OutputModeArg::PrettyAscii => PpMode::Ascii,
            OutputModeArg::Raw => return OutputMode::Raw,
            OutputModeArg::None => return OutputMode::None,
        };
        OutputMode::Pretty(PpConfig {
            mode: ppmode,
            cell_width: self.width.0,
            cell_height: self.height.0,
        })
    }
}

impl Default for SolveArgs {
    fn default() -> SolveArgs {
        SolveArgs {
            derive_all: false,
            output_mode: OutputModeArg::Auto,
            width: Size(2),
            height: Size(1),
            input_files: vec![],
        }
    }
}

impl Into<Config> for SolveArgs {
    fn into(self) -> Config {
        Config::Solve(SolveConfig {
            derive_all: self.derive_all,
            output_mode: self.output_mode(),
            input_files: self.input_files,
        })
    }
}

#[derive(Copy, Clone, Debug)]
struct Size(usize);
impl FromStr for Size {
    type Err = ();

    fn from_str(src: &str) -> Result<Size, ()> {
        let val = usize::from_str(src);
        if let Ok(v) = val {
            if v != 0 {
                return Ok(Size(v));
            }
        }
        Err(())

    }
}

#[derive(Copy, Clone, Debug)]
enum OutputModeArg {
    Auto,
    PrettyColor,
    PrettyAscii,
    Raw,
    None,
}

impl FromStr for OutputModeArg {
    type Err = ();

    fn from_str(src: &str) -> Result<OutputModeArg, ()> {
        match src {
            "auto" => Ok(OutputModeArg::Auto),
            "pretty-color" => Ok(OutputModeArg::PrettyColor),
            "pretty-ascii" => Ok(OutputModeArg::PrettyAscii),
            "raw" => Ok(OutputModeArg::Raw),
            "none" => Ok(OutputModeArg::None),
            _ => Err(()),
        }
    }
}

#[derive(Clone, Debug)]
struct TestArgs {
    derive_all: bool,
    input_files: Vec<String>,
}

impl SetupParser for TestArgs {
    fn setup_parser<'parser>(&'parser mut self, ap: &mut ArgumentParser<'parser>) {
        ap.set_description("Test the given problem(s)");
        let _ = ap.refer(&mut self.derive_all)
                  .add_option(&["--all"], StoreTrue, "derive all solutions (if any).");
        let _ = ap.refer(&mut self.input_files)
                  .add_argument("input_files", List, "puzzle files to solve.");
    }
}

impl Default for TestArgs {
    fn default() -> TestArgs {
        TestArgs {
            derive_all: false,
            input_files: vec![],
        }
    }
}

impl Into<Config> for TestArgs {
    fn into(self) -> Config {
        Config::Test(TestConfig {
            derive_all: self.derive_all,
            input_files: self.input_files,
        })
    }
}

#[derive(Clone, Debug)]
struct BenchArgs {
    derive_all: bool,
    only_hardest: Option<usize>,
    input_files: Vec<String>,
}

impl SetupParser for BenchArgs {
    fn setup_parser<'parser>(&'parser mut self, ap: &mut ArgumentParser<'parser>) {
        ap.set_description("Bench the given problem(s)");
        let _ = ap.refer(&mut self.derive_all)
                  .add_option(&["--all"], StoreTrue, "derive all solutions (if any).");
        let _ = ap.refer(&mut self.only_hardest)
                  .add_option(&["--only-hardest"],
                              StoreOption,
                              "measure only hardest n problems.")
                  .metavar("n");
        let _ = ap.refer(&mut self.input_files)
                  .add_argument("input_files", List, "puzzle files to solve.");
    }
}

impl Default for BenchArgs {
    fn default() -> BenchArgs {
        BenchArgs {
            derive_all: false,
            only_hardest: None,
            input_files: vec![],
        }
    }
}

impl Into<Config> for BenchArgs {
    fn into(self) -> Config {
        Config::Bench(BenchConfig {
            derive_all: self.derive_all,
            only_hardest: self.only_hardest,
            input_files: self.input_files,
        })
    }
}

#[derive(Clone, Debug)]
pub enum Config {
    Solve(SolveConfig),
    Test(TestConfig),
    Bench(BenchConfig),
}

#[derive(Clone, Debug)]
pub struct SolveConfig {
    pub derive_all: bool,
    pub output_mode: OutputMode,
    pub input_files: Vec<String>,
}

#[derive(Clone, Debug)]
pub struct TestConfig {
    pub derive_all: bool,
    pub input_files: Vec<String>,
}

#[derive(Clone, Debug)]
pub struct BenchConfig {
    pub derive_all: bool,
    pub only_hardest: Option<usize>,
    pub input_files: Vec<String>,
}

#[derive(Copy, Clone, Debug)]
pub enum OutputMode {
    Pretty(PpConfig),
    Raw,
    None,
}

impl Config {
    pub fn parse() -> Config {
        let mut command = CommandType::default();
        let mut args = vec![];
        {
            let mut ap = ArgumentParser::new();
            command.setup_parser(&mut ap, &mut args);
            ap.parse_args_or_exit();
        }

        args.insert(0, format!("{:?}", command));

        match command {
            CommandType::Solve => Self::parse_subcommand::<SolveArgs>(args),
            CommandType::Test => Self::parse_subcommand::<TestArgs>(args),
            CommandType::Bench => Self::parse_subcommand::<BenchArgs>(args),
        }
    }

    fn parse_subcommand<T>(args: Vec<String>) -> Config
        where T: SetupParser + Default + Into<Config>
    {
        let mut sub_args = T::default();
        {
            let mut ap = ArgumentParser::new();
            sub_args.setup_parser(&mut ap);
            if let Err(x) = ap.parse(args, &mut io::stdout(), &mut io::stderr()) {
                process::exit(x);
            }
        }
        sub_args.into()
    }
}
<|endoftext|>