<commit_before>extern crate sdl2;

use memory::Memory;
use self::sdl2::keyboard::Keycode;

use std::collections::HashMap;

pub enum Button {
    Up,
    Down,
    Left,
    Right,
    A,
    B,
    Start,
    Select,
}

pub struct Controller {
    controls: HashMap<Keycode, Button>,
    buttons: u8,
    shift: u8,
    strobe: bool,
}

impl Memory for Controller {
    fn read(&mut self, address: u16) -> u8 {
        assert!(address == 0x4016 || address == 0x4017);

        if self.strobe || self.shift == 8 {
            self.shift = 0;
        } else {
            self.shift += 1;
        }
        0
    }

    fn write(&mut self, address: u16, value: u8) {
        assert!(address == 0x4016);
        self.strobe = (value & 0x01) == 0x01;
    }
}

impl Controller {
    fn new(optional_controls: Option<HashMap<Keycode, Button>>) -> Controller {
        let controls = match optional_controls {
            Some(x) => x,
            None => {
                let mut defaults = HashMap::new();
                defaults.insert(Keycode::Up, Button::Up);
                defaults.insert(Keycode::Down, Button::Down);
                defaults.insert(Keycode::Left, Button::Left);
                defaults.insert(Keycode::Right, Button::Right);
                defaults.insert(Keycode::Tab, Button::Select);
                defaults.insert(Keycode::Return, Button::Start);
                defaults.insert(Keycode::LCtrl, Button::A);
                defaults.insert(Keycode::LShift, Button::B);

                defaults
            }
        };

        Controller {
            controls: controls,
            shift: 0,
            strobe: false,
            buttons: 0,
        }
    }

    fn key_down(&mut self, code: Keycode) {
        self.buttons = self.buttons | match self.controls[&code] {
            Button::A => 0x80, // set bit 7
            Button::B => 0x40, // set bit 6
            Button::Select => 0x20, // set bit 5
            Button::Start => 0x10, // set bit 4
            Button::Up => 0x08, // set bit 3
            Button::Down => 0x04, // set bit 2
            Button::Left => 0x02,
            Button::Right => 0x01,
        }
    }

    fn key_up(&mut self, code: Keycode) {
        self.buttons = self.buttons & match self.controls[&code] {
            Button::A => 0x7F, // clear bit 7
            Button::B => 0xBF,  // clear bit 6
            Button::Select => 0xDF, // clear bit 5
            Button::Start => 0xEF, // clear bit 4
            Button::Up => 0xF7, // clear bit 3
            Button::Down => 0xFB,
            Button::Left => 0xFD,
            Button::Right => 0xFE,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use memory::Memory;
    use controller::sdl2::keyboard::Keycode;
    use std::collections::HashMap;

    fn create_test_controller() -> Controller {
        // independent from defaults so that changes to defaults do not invalidate tests
        let mut test_controls = HashMap::new();
        test_controls.insert(Keycode::Up, Button::Up);
        test_controls.insert(Keycode::Down, Button::Down);
        test_controls.insert(Keycode::Left, Button::Left);
        test_controls.insert(Keycode::Right, Button::Right);
        test_controls.insert(Keycode::Tab, Button::Select);
        test_controls.insert(Keycode::Return, Button::Start);
        test_controls.insert(Keycode::LCtrl, Button::A);
        test_controls.insert(Keycode::LShift, Button::B);

        Controller::new(Some(test_controls))
    }

    #[test]
    #[should_panic]
    fn controller_panics_if_write_is_not_to_0x4016() {
        let mut controller = create_test_controller();
        controller.write(0x4000, 51);
    }

    #[test]
    fn write_to_0x4016_sets_strobe_if_bit_0_is_set() {
        let mut controller = create_test_controller();
        controller.write(0x4016, 0x01);
        assert_eq!(true, controller.strobe)
    }

    #[test]
    fn write_to_0x4016_clears_strobe_if_bit_0_is_clear() {
        let mut controller = create_test_controller();
        controller.strobe = true;
        controller.write(0x4016, 0x00);
        assert_eq!(false, controller.strobe)
    }

    #[test]
    fn read_from_0x4016_keeps_shift_at_0_if_strobe_is_high() {
        let mut controller = create_test_controller();
        controller.strobe = true;
        controller.read(0x4016);
        assert_eq!(0, controller.shift);
    }

    #[test]
    fn read_from_0x4017_keeps_shift_at_0_if_strobe_is_high() {
        let mut controller = create_test_controller();
        controller.strobe = true;
        controller.read(0x4017);
        assert_eq!(0, controller.shift);
    }

    #[test]
    fn read_from_0x4016_increases_shift_if_strobe_is_low() {
        let mut controller = create_test_controller();
        controller.strobe = false;
        controller.read(0x4016);
        assert_eq!(1, controller.shift);
    }

    #[test]
    fn read_from_0x4017_increases_shift_if_strobe_is_low() {
        let mut controller = create_test_controller();
        controller.strobe = false;
        controller.read(0x4017);
        assert_eq!(1, controller.shift);
    }

    #[test]
    fn shift_wraps_around_after_8() {
        let mut controller = create_test_controller();
        controller.strobe = false;
        controller.shift = 8;
        controller.read(0x4017);
        assert_eq!(0, controller.shift);
    }

    #[test]
    fn button_a_bit_is_set_if_key_down_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.key_down(Keycode::LCtrl);
        assert_eq!(0x80, controller.buttons & 0x80);
    }

    #[test]
    fn button_a_bit_is_cleared_if_key_up_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.buttons = 0x80;
        controller.key_up(Keycode::LCtrl);
        assert_eq!(0x00, controller.buttons & 0x80);
    }

    #[test]
    fn button_b_bit_is_set_if_key_down_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.key_down(Keycode::LShift);
        assert_eq!(0x40, controller.buttons & 0x40);
    }

    #[test]
    fn button_b_bit_is_cleared_if_key_up_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.buttons = 0x40;
        controller.key_up(Keycode::LShift);
        assert_eq!(0x00, controller.buttons & 0x40);
    }

    #[test]
    fn button_select_bit_is_set_if_key_down_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.key_down(Keycode::Tab);
        assert_eq!(0x20, controller.buttons & 0x20);
    }

    #[test]
    fn button_select_bit_is_cleared_if_key_up_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.buttons = 0x20;
        controller.key_up(Keycode::Tab);
        assert_eq!(0x00, controller.buttons & 0x20);
    }

    #[test]
    fn button_start_bit_is_set_if_key_down_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.key_down(Keycode::Return);
        assert_eq!(0x10, controller.buttons & 0x10);
    }

    #[test]
    fn button_start_bit_is_cleared_if_key_up_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.buttons = 0x10;
        controller.key_up(Keycode::Return);
        assert_eq!(0x00, controller.buttons & 0x10);
    }

    #[test]
    fn button_up_bit_is_set_if_key_down_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.key_down(Keycode::Up);
        assert_eq!(0x08, controller.buttons & 0x08);
    }

    #[test]
    fn button_up_bit_is_cleared_if_key_up_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.buttons = 0x08;
        controller.key_up(Keycode::Up);
        assert_eq!(0x00, controller.buttons & 0x08);
    }

    #[test]
    fn button_down_bit_is_set_if_key_down_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.key_down(Keycode::Down);
        assert_eq!(0x04, controller.buttons & 0x04);
    }

    #[test]
    fn button_down_bit_is_cleared_if_key_up_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.buttons = 0x04;
        controller.key_up(Keycode::Down);
        assert_eq!(0x00, controller.buttons & 0x04);
    }

    #[test]
    fn button_left_bit_is_set_if_key_down_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.key_down(Keycode::Left);
        assert_eq!(0x02, controller.buttons & 0x02);
    }

    #[test]
    fn button_left_bit_is_cleared_if_key_up_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.buttons = 0x02;
        controller.key_up(Keycode::Left);
        assert_eq!(0x00, controller.buttons & 0x02);
    }

    #[test]
    fn button_right_bit_is_set_if_key_down_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.key_down(Keycode::Right);
        assert_eq!(0x01, controller.buttons & 0x01);
    }

    #[test]
    fn button_right_bit_is_cleared_if_key_up_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.buttons = 0x01;
        controller.key_up(Keycode::Right);
        assert_eq!(0x00, controller.buttons & 0x01);
    }
}
<commit_msg>Controller now returns button status when reading from 0x4016 or 0x4017<commit_after>extern crate sdl2;

use memory::Memory;
use self::sdl2::keyboard::Keycode;

use std::collections::HashMap;

pub enum Button {
    Up,
    Down,
    Left,
    Right,
    A,
    B,
    Start,
    Select,
}

pub struct Controller {
    controls: HashMap<Keycode, Button>,
    buttons: u8,
    shift: u8,
    strobe: bool,
}

impl Memory for Controller {
    // TODO: Upper 3 bits should maintain the value that the bus had previously;
    // this is currently not implemented. At least one game uses this (paperboy)
    fn read(&mut self, address: u16) -> u8 {
        assert!(address == 0x4016 || address == 0x4017);

        let return_value = ((self.buttons << self.shift) & 0x80) >> 7;
        if self.strobe || self.shift == 7 {
            self.shift = 0;
        } else {
            self.shift += 1;
        }
        return_value
    }

    fn write(&mut self, address: u16, value: u8) {
        assert!(address == 0x4016);
        self.strobe = (value & 0x01) == 0x01;
    }
}

impl Controller {
    fn new(optional_controls: Option<HashMap<Keycode, Button>>) -> Controller {
        let controls = match optional_controls {
            Some(x) => x,
            None => {
                let mut defaults = HashMap::new();
                defaults.insert(Keycode::Up, Button::Up);
                defaults.insert(Keycode::Down, Button::Down);
                defaults.insert(Keycode::Left, Button::Left);
                defaults.insert(Keycode::Right, Button::Right);
                defaults.insert(Keycode::Tab, Button::Select);
                defaults.insert(Keycode::Return, Button::Start);
                defaults.insert(Keycode::LCtrl, Button::A);
                defaults.insert(Keycode::LShift, Button::B);

                defaults
            }
        };

        Controller {
            controls: controls,
            shift: 0,
            strobe: false,
            buttons: 0,
        }
    }

    fn key_down(&mut self, code: Keycode) {
        self.buttons = self.buttons | match self.controls[&code] {
            Button::A => 0x80, // set bit 7
            Button::B => 0x40, // set bit 6
            Button::Select => 0x20, // set bit 5
            Button::Start => 0x10, // set bit 4
            Button::Up => 0x08, // set bit 3
            Button::Down => 0x04, // set bit 2
            Button::Left => 0x02,
            Button::Right => 0x01,
        }
    }

    fn key_up(&mut self, code: Keycode) {
        self.buttons = self.buttons & match self.controls[&code] {
            Button::A => 0x7F, // clear bit 7
            Button::B => 0xBF,  // clear bit 6
            Button::Select => 0xDF, // clear bit 5
            Button::Start => 0xEF, // clear bit 4
            Button::Up => 0xF7, // clear bit 3
            Button::Down => 0xFB,
            Button::Left => 0xFD,
            Button::Right => 0xFE,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use memory::Memory;
    use controller::sdl2::keyboard::Keycode;
    use std::collections::HashMap;

    fn create_test_controller() -> Controller {
        // independent from defaults so that changes to defaults do not invalidate tests
        let mut test_controls = HashMap::new();
        test_controls.insert(Keycode::Up, Button::Up);
        test_controls.insert(Keycode::Down, Button::Down);
        test_controls.insert(Keycode::Left, Button::Left);
        test_controls.insert(Keycode::Right, Button::Right);
        test_controls.insert(Keycode::Tab, Button::Select);
        test_controls.insert(Keycode::Return, Button::Start);
        test_controls.insert(Keycode::LCtrl, Button::A);
        test_controls.insert(Keycode::LShift, Button::B);

        Controller::new(Some(test_controls))
    }

    #[test]
    #[should_panic]
    fn controller_panics_if_write_is_not_to_0x4016() {
        let mut controller = create_test_controller();
        controller.write(0x4000, 51);
    }

    #[test]
    fn write_to_0x4016_sets_strobe_if_bit_0_is_set() {
        let mut controller = create_test_controller();
        controller.write(0x4016, 0x01);
        assert_eq!(true, controller.strobe)
    }

    #[test]
    fn write_to_0x4016_clears_strobe_if_bit_0_is_clear() {
        let mut controller = create_test_controller();
        controller.strobe = true;
        controller.write(0x4016, 0x00);
        assert_eq!(false, controller.strobe)
    }

    #[test]
    fn read_from_0x4016_keeps_shift_at_0_if_strobe_is_high() {
        let mut controller = create_test_controller();
        controller.strobe = true;
        controller.read(0x4016);
        assert_eq!(0, controller.shift);
    }

    #[test]
    fn read_from_0x4017_keeps_shift_at_0_if_strobe_is_high() {
        let mut controller = create_test_controller();
        controller.strobe = true;
        controller.read(0x4017);
        assert_eq!(0, controller.shift);
    }

    #[test]
    fn read_from_0x4016_increases_shift_if_strobe_is_low() {
        let mut controller = create_test_controller();
        controller.strobe = false;
        controller.read(0x4016);
        assert_eq!(1, controller.shift);
    }

    #[test]
    fn read_from_0x4017_increases_shift_if_strobe_is_low() {
        let mut controller = create_test_controller();
        controller.strobe = false;
        controller.read(0x4017);
        assert_eq!(1, controller.shift);
    }

    #[test]
    fn shift_wraps_around_after_7() {
        let mut controller = create_test_controller();
        controller.strobe = false;
        controller.shift = 7;
        controller.read(0x4017);
        assert_eq!(0, controller.shift);
    }

    #[test]
    fn button_a_bit_is_set_if_key_down_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.key_down(Keycode::LCtrl);
        assert_eq!(0x80, controller.buttons & 0x80);
    }

    #[test]
    fn button_a_bit_is_cleared_if_key_up_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.buttons = 0x80;
        controller.key_up(Keycode::LCtrl);
        assert_eq!(0x00, controller.buttons & 0x80);
    }

    #[test]
    fn button_b_bit_is_set_if_key_down_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.key_down(Keycode::LShift);
        assert_eq!(0x40, controller.buttons & 0x40);
    }

    #[test]
    fn button_b_bit_is_cleared_if_key_up_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.buttons = 0x40;
        controller.key_up(Keycode::LShift);
        assert_eq!(0x00, controller.buttons & 0x40);
    }

    #[test]
    fn button_select_bit_is_set_if_key_down_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.key_down(Keycode::Tab);
        assert_eq!(0x20, controller.buttons & 0x20);
    }

    #[test]
    fn button_select_bit_is_cleared_if_key_up_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.buttons = 0x20;
        controller.key_up(Keycode::Tab);
        assert_eq!(0x00, controller.buttons & 0x20);
    }

    #[test]
    fn button_start_bit_is_set_if_key_down_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.key_down(Keycode::Return);
        assert_eq!(0x10, controller.buttons & 0x10);
    }

    #[test]
    fn button_start_bit_is_cleared_if_key_up_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.buttons = 0x10;
        controller.key_up(Keycode::Return);
        assert_eq!(0x00, controller.buttons & 0x10);
    }

    #[test]
    fn button_up_bit_is_set_if_key_down_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.key_down(Keycode::Up);
        assert_eq!(0x08, controller.buttons & 0x08);
    }

    #[test]
    fn button_up_bit_is_cleared_if_key_up_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.buttons = 0x08;
        controller.key_up(Keycode::Up);
        assert_eq!(0x00, controller.buttons & 0x08);
    }

    #[test]
    fn button_down_bit_is_set_if_key_down_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.key_down(Keycode::Down);
        assert_eq!(0x04, controller.buttons & 0x04);
    }

    #[test]
    fn button_down_bit_is_cleared_if_key_up_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.buttons = 0x04;
        controller.key_up(Keycode::Down);
        assert_eq!(0x00, controller.buttons & 0x04);
    }

    #[test]
    fn button_left_bit_is_set_if_key_down_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.key_down(Keycode::Left);
        assert_eq!(0x02, controller.buttons & 0x02);
    }

    #[test]
    fn button_left_bit_is_cleared_if_key_up_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.buttons = 0x02;
        controller.key_up(Keycode::Left);
        assert_eq!(0x00, controller.buttons & 0x02);
    }

    #[test]
    fn button_right_bit_is_set_if_key_down_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.key_down(Keycode::Right);
        assert_eq!(0x01, controller.buttons & 0x01);
    }

    #[test]
    fn button_right_bit_is_cleared_if_key_up_is_called_with_correct_keycode() {
        let mut controller = create_test_controller();
        controller.buttons = 0x01;
        controller.key_up(Keycode::Right);
        assert_eq!(0x00, controller.buttons & 0x01);
    }

    #[test]
    fn a_button_status_is_correctly_returned_when_reading_from_0x4016() {
        let mut controller = create_test_controller();
        controller.key_down(Keycode::LCtrl);
        assert_eq!(0x01, controller.read(0x4016));
    }

    #[test]
    fn b_button_status_is_correctly_returned_when_reading_from_0x4016() {
        let mut controller = create_test_controller();
        controller.key_down(Keycode::LShift);
        for _ in 0..1 {
            controller.read(0x4016);
        }
        assert_eq!(0x01, controller.read(0x4016));
    }

    #[test]
    fn select_button_status_is_correctly_returned_when_reading_from_0x4016() {
        let mut controller = create_test_controller();
        controller.key_down(Keycode::Tab);
        for _ in 0..2 {
            controller.read(0x4016);
        }
        assert_eq!(0x01, controller.read(0x4016));
    }

    #[test]
    fn start_button_status_is_correctly_returned_when_reading_from_0x4016() {
        let mut controller = create_test_controller();
        controller.key_down(Keycode::Return);
        for _ in 0..3 {
            controller.read(0x4016);
        }
        assert_eq!(0x01, controller.read(0x4016));
    }

    #[test]
    fn up_button_status_is_correctly_returned_when_reading_from_0x4016() {
        let mut controller = create_test_controller();
        controller.key_down(Keycode::Up);
        for _ in 0..4 {
            controller.read(0x4016);
        }
        assert_eq!(0x01, controller.read(0x4016));
    }

    #[test]
    fn down_button_status_is_correctly_returned_when_reading_from_0x4016() {
        let mut controller = create_test_controller();
        controller.key_down(Keycode::Down);
        for _ in 0..5 {
            controller.read(0x4016);
        }
        assert_eq!(0x01, controller.read(0x4016));
    }

    #[test]
    fn left_button_status_is_correctly_returned_when_reading_from_0x4016() {
        let mut controller = create_test_controller();
        controller.key_down(Keycode::Left);
        for _ in 0..6 {
            controller.read(0x4016);
        }
        assert_eq!(0x01, controller.read(0x4016));
    }

    #[test]
    fn right_button_status_is_correctly_returned_when_reading_from_0x4016() {
        let mut controller = create_test_controller();
        controller.key_down(Keycode::Right);
        for _ in 0..7 {
            controller.read(0x4016);
        }
        assert_eq!(0x01, controller.read(0x4016));
    }
}
<|endoftext|>


<commit_before>use base::ast::{
    Alternative, Argument, AstType, Expr, ExprField, Literal, Pattern, PatternField, SpannedExpr,
    TypeBinding, TypedIdent, ValueBinding,
};
use base::metadata::Attribute;
use base::pos::{self, BytePos, Span};
use base::symbol::{Symbol, Symbols};
use base::types::{arg_iter, row_iter, Type};

use macros::Error;

pub fn generate(
    symbols: &mut Symbols,
    derive: &Attribute,
    bind: &TypeBinding<Symbol>,
) -> Result<Vec<ValueBinding<Symbol>>, Error> {
    match derive.arguments {
        Some(ref args) => args
            .split(',')
            .map(|s| s.trim())
            .map(|arg| match arg {
                "Eq" => generate_eq(symbols, bind),
                "Show" => generate_show(symbols, bind),
                _ => panic!(),
            })
            .collect(),
        _ => Err("Invalid `derive` attribute".into()),
    }
}

fn ident(span: Span<BytePos>, s: Symbol) -> SpannedExpr<Symbol> {
    pos::spanned(span, Expr::Ident(TypedIdent::new(s)))
}

fn literal(span: Span<BytePos>, s: &str) -> SpannedExpr<Symbol> {
    pos::spanned(span, Expr::Literal(Literal::String(s.to_string())))
}

fn app(span: Span<BytePos>, func: Symbol, args: Vec<SpannedExpr<Symbol>>) -> SpannedExpr<Symbol> {
    pos::spanned(
        Default::default(),
        Expr::App {
            func: Box::new(pos::spanned(span, Expr::Ident(TypedIdent::new(func)))),
            implicit_args: Vec::new(),
            args,
        },
    )
}

fn infix(
    span: Span<BytePos>,
    lhs: SpannedExpr<Symbol>,
    op: Symbol,
    rhs: SpannedExpr<Symbol>,
) -> SpannedExpr<Symbol> {
    pos::spanned(
        Default::default(),
        Expr::Infix {
            lhs: lhs.into(),
            op: pos::spanned(span, TypedIdent::new(op)),
            rhs: rhs.into(),
            implicit_args: Vec::new(),
        },
    )
}

fn is_self_type(self_: &Symbol, typ: &AstType<Symbol>) -> bool {
    match **typ {
        Type::App(ref f, _) => is_self_type(self_, f),
        Type::Alias(ref alias) => alias.name == *self_,
        Type::Ident(ref id) => id == self_,
        _ => false,
    }
}

fn generate_show(
    symbols: &mut Symbols,
    bind: &TypeBinding<Symbol>,
) -> Result<ValueBinding<Symbol>, Error> {
    let span = bind.name.span;

    let x = Symbol::from("x");
    let show_fn = TypedIdent::new(symbols.symbol("show_"));

    let show_expr = match **bind.alias.value.unresolved_type() {
        Type::Variant(ref variants) => {
            let alts = row_iter(variants)
                .map(|variant| {
                    let pattern_args: Vec<_> = arg_iter(&variant.typ)
                        .enumerate()
                        .map(|(i, typ)| {
                            (
                                is_self_type(&bind.alias.value.name, typ),
                                TypedIdent::new(Symbol::from(format!("arg_{}", i))),
                            )
                        })
                        .collect();

                    let expr = {
                        let open_brace = literal(span, variant.name.declared_name());

                        pattern_args
                            .iter()
                            .fold(open_brace, |acc, &(self_type, ref x)| {
                                let show_function = if self_type {
                                    show_fn.name.clone()
                                } else {
                                    symbols.symbol("show")
                                };
                                let show = infix(
                                    span,
                                    literal(span, "("),
                                    symbols.symbol("++"),
                                    infix(
                                        span,
                                        app(span, show_function, vec![ident(span, x.name.clone())]),
                                        symbols.symbol("++"),
                                        literal(span, ")"),
                                    ),
                                );
                                infix(
                                    span,
                                    acc,
                                    symbols.symbol("++"),
                                    infix(span, literal(span, " "), symbols.symbol("++"), show),
                                )
                            })
                    };

                    let ctor_pattern = |pattern_args: Vec<_>| {
                        pos::spanned(
                            span,
                            Pattern::Constructor(
                                TypedIdent::new(variant.name.clone()),
                                pattern_args
                                    .into_iter()
                                    .map(|arg| pos::spanned(span, Pattern::Ident(arg)))
                                    .collect(),
                            ),
                        )
                    };
                    Alternative {
                        pattern: ctor_pattern(pattern_args.into_iter().map(|t| t.1).collect()),
                        expr,
                    }
                })
                .collect();
            Expr::Match(Box::new(ident(span, x.clone())), alts)
        }
        Type::Record(ref row) => {
            let field_symbols: Vec<_> = row_iter(row)
                .map(|field| {
                    TypedIdent::new(Symbol::from(format!("{}", field.name.declared_name())))
                })
                .collect();

            let expr = {
                let open_brace = literal(span, "{ ");

                let show_expr = field_symbols
                    .iter()
                    .enumerate()
                    .fold(open_brace, |acc, (i, x)| {
                        let show = app(
                            span,
                            symbols.symbol("show"),
                            vec![ident(span, x.name.clone())],
                        );

                        let show_field = infix(
                            span,
                            acc,
                            symbols.symbol("++"),
                            infix(
                                span,
                                literal(span, &format!("{} = ", x.name.declared_name())),
                                symbols.symbol("++"),
                                show,
                            ),
                        );

                        let last = i == field_symbols.len() - 1;
                        let suffix = if last { " " } else { ", " };
                        infix(
                            span,
                            show_field,
                            symbols.symbol("++"),
                            literal(span, suffix),
                        )
                    });

                infix(span, show_expr, symbols.symbol("++"), literal(span, "}"))
            };
            let generate_record_pattern = |symbols| {
                pos::spanned(
                    span,
                    Pattern::Record {
                        implicit_import: None,
                        typ: Type::hole(),
                        types: Vec::new(),
                        fields: row_iter(row)
                            .zip(symbols)
                            .map(|(field, bind)| PatternField {
                                name: pos::spanned(span, field.name.clone()),
                                value: Some(pos::spanned(span, Pattern::Ident(bind))),
                            })
                            .collect(),
                    },
                )
            };
            Expr::Match(
                Box::new(ident(span, x.clone())),
                vec![Alternative {
                    pattern: generate_record_pattern(field_symbols),
                    expr,
                }],
            )
        }
        _ => return Err("Unable to derive Show for this type".into()),
    };

    let show_record_expr = Expr::LetBindings(
        vec![ValueBinding {
            name: pos::spanned(span, Pattern::Ident(show_fn.clone())),
            args: vec![Argument::explicit(pos::spanned(
                span,
                TypedIdent::new(x.clone()),
            ))],
            expr: pos::spanned(span, show_expr),
            metadata: Default::default(),
            typ: Some(Type::function(
                vec![Type::ident(bind.alias.value.name.clone())],
                Type::string(),
            )),
            resolved_type: Type::hole(),
        }],
        Box::new(pos::spanned(
            span,
            Expr::Record {
                typ: Type::hole(),
                types: Vec::new(),
                exprs: vec![ExprField {
                    metadata: Default::default(),
                    name: pos::spanned(span, symbols.symbol("show")),
                    value: Some(ident(span, show_fn.name.clone())),
                }],
                base: None,
            },
        )),
    );
    Ok(ValueBinding {
        name: pos::spanned(span, Pattern::Ident(TypedIdent::new(Symbol::from("show")))),
        args: Vec::new(),
        expr: pos::spanned(span, show_record_expr),
        metadata: Default::default(),
        typ: Some(Type::app(
            Type::ident(symbols.symbol("Show")),
            collect![Type::ident(bind.alias.value.name.clone())],
        )),
        resolved_type: Type::hole(),
    })
}

fn generate_eq(
    symbols: &mut Symbols,
    bind: &TypeBinding<Symbol>,
) -> Result<ValueBinding<Symbol>, Error> {
    let span = bind.name.span;

    let eq = TypedIdent::new(symbols.symbol("eq"));
    let l = Symbol::from("l");
    let r = Symbol::from("r");

    let matcher = Box::new(pos::spanned(
        span,
        Expr::Tuple {
            typ: Type::hole(),
            elems: vec![ident(span, l.clone()), ident(span, r.clone())],
        },
    ));

    let generate_and_chain =
        |symbols: &mut Symbols,
         iter: &mut Iterator<Item = (&(bool, TypedIdent<Symbol>), &TypedIdent<Symbol>)>| {
            iter.fold(None, |acc, (&(self_type, ref l), r)| {
                let equal_symbol = if self_type {
                    eq.name.clone()
                } else {
                    symbols.symbol("==")
                };

                let eq_check = app(
                    span,
                    equal_symbol,
                    vec![
                        ident(span, l.name.clone()).into(),
                        ident(span, r.name.clone()),
                    ],
                );

                Some(match acc {
                    Some(acc) => infix(span, acc, symbols.symbol("&&"), eq_check),
                    None => eq_check,
                })
            }).unwrap_or_else(|| ident(span, symbols.symbol("True")))
        };

    let comparison_expr = match **bind.alias.value.unresolved_type() {
        Type::Variant(ref variants) => {
            let catch_all_alternative = Alternative {
                pattern: pos::spanned(span, Pattern::Ident(TypedIdent::new(symbols.symbol("_")))),
                expr: ident(span, symbols.symbol("False")),
            };

            let alts = row_iter(variants)
                .map(|variant| {
                    let l_pattern_args: Vec<_> = arg_iter(&variant.typ)
                        .map(|typ| {
                            (
                                is_self_type(&bind.alias.value.name, typ),
                                TypedIdent::new(Symbol::from("arg_l")),
                            )
                        })
                        .collect();
                    let r_pattern_args: Vec<_> = arg_iter(&variant.typ)
                        .map(|_| TypedIdent::new(Symbol::from("arg_r")))
                        .collect();

                    let expr = generate_and_chain(
                        symbols,
                        &mut l_pattern_args.iter().zip(&r_pattern_args),
                    );

                    let ctor_pattern = |pattern_args: Vec<_>| {
                        pos::spanned(
                            span,
                            Pattern::Constructor(
                                TypedIdent::new(variant.name.clone()),
                                pattern_args
                                    .into_iter()
                                    .map(|arg| pos::spanned(span, Pattern::Ident(arg)))
                                    .collect(),
                            ),
                        )
                    };
                    Alternative {
                        pattern: pos::spanned(
                            span,
                            Pattern::Tuple {
                                typ: Type::hole(),
                                elems: vec![
                                    ctor_pattern(l_pattern_args.into_iter().map(|t| t.1).collect()),
                                    ctor_pattern(r_pattern_args),
                                ],
                            },
                        ),
                        expr,
                    }
                })
                .chain(Some(catch_all_alternative))
                .collect();
            Expr::Match(matcher, alts)
        }
        Type::Record(ref row) => {
            let l_symbols: Vec<_> = row_iter(row)
                .map(|field| {
                    (
                        is_self_type(&bind.alias.value.name, &field.typ),
                        TypedIdent::new(Symbol::from(format!("{}_l", field.name.declared_name()))),
                    )
                })
                .collect();
            let r_symbols: Vec<_> = row_iter(row)
                .map(|field| {
                    TypedIdent::new(Symbol::from(format!("{}_r", field.name.declared_name())))
                })
                .collect();

            let expr = generate_and_chain(symbols, &mut l_symbols.iter().zip(&r_symbols));
            let generate_record_pattern = |symbols| {
                pos::spanned(
                    span,
                    Pattern::Record {
                        implicit_import: None,
                        typ: Type::hole(),
                        types: Vec::new(),
                        fields: row_iter(row)
                            .zip(symbols)
                            .map(|(field, bind)| PatternField {
                                name: pos::spanned(span, field.name.clone()),
                                value: Some(pos::spanned(span, Pattern::Ident(bind))),
                            })
                            .collect(),
                    },
                )
            };
            Expr::Match(
                matcher,
                vec![Alternative {
                    pattern: pos::spanned(
                        span,
                        Pattern::Tuple {
                            elems: vec![
                                generate_record_pattern(
                                    l_symbols.into_iter().map(|t| t.1).collect(),
                                ),
                                generate_record_pattern(r_symbols),
                            ],
                            typ: Type::hole(),
                        },
                    ),
                    expr,
                }],
            )
        }
        _ => return Err("Unable to derive eq for this type".into()),
    };
    let eq_record_expr = Expr::LetBindings(
        vec![ValueBinding {
            name: pos::spanned(span, Pattern::Ident(eq.clone())),
            args: [l, r]
                .iter()
                .map(|arg| Argument::explicit(pos::spanned(span, TypedIdent::new(arg.clone()))))
                .collect(),
            expr: pos::spanned(span, comparison_expr),
            metadata: Default::default(),
            typ: Some(Type::function(
                vec![
                    Type::ident(bind.alias.value.name.clone()),
                    Type::ident(bind.alias.value.name.clone()),
                ],
                Type::hole(),
            )),
            resolved_type: Type::hole(),
        }],
        Box::new(pos::spanned(
            span,
            Expr::Record {
                typ: Type::hole(),
                types: Vec::new(),
                exprs: vec![ExprField {
                    metadata: Default::default(),
                    name: pos::spanned(span, symbols.symbol("==")),
                    value: Some(ident(span, eq.name.clone())),
                }],
                base: None,
            },
        )),
    );
    Ok(ValueBinding {
        name: pos::spanned(span, Pattern::Ident(TypedIdent::new(Symbol::from("eq")))),
        args: Vec::new(),
        expr: pos::spanned(span, eq_record_expr),
        metadata: Default::default(),
        typ: Some(Type::app(
            Type::ident(symbols.symbol("Eq")),
            collect![Type::ident(bind.alias.value.name.clone())],
        )),
        resolved_type: Type::hole(),
    })
}
<commit_msg>Don't use default spans as they will cause panics during error construction<commit_after>use base::ast::{
    Alternative, Argument, AstType, Expr, ExprField, Literal, Pattern, PatternField, SpannedExpr,
    TypeBinding, TypedIdent, ValueBinding,
};
use base::metadata::Attribute;
use base::pos::{self, BytePos, Span};
use base::symbol::{Symbol, Symbols};
use base::types::{arg_iter, row_iter, Type};

use macros::Error;

pub fn generate(
    symbols: &mut Symbols,
    derive: &Attribute,
    bind: &TypeBinding<Symbol>,
) -> Result<Vec<ValueBinding<Symbol>>, Error> {
    match derive.arguments {
        Some(ref args) => args
            .split(',')
            .map(|s| s.trim())
            .map(|arg| match arg {
                "Eq" => generate_eq(symbols, bind),
                "Show" => generate_show(symbols, bind),
                _ => panic!(),
            })
            .collect(),
        _ => Err("Invalid `derive` attribute".into()),
    }
}

fn ident(span: Span<BytePos>, s: Symbol) -> SpannedExpr<Symbol> {
    pos::spanned(span, Expr::Ident(TypedIdent::new(s)))
}

fn literal(span: Span<BytePos>, s: &str) -> SpannedExpr<Symbol> {
    pos::spanned(span, Expr::Literal(Literal::String(s.to_string())))
}

fn app(span: Span<BytePos>, func: Symbol, args: Vec<SpannedExpr<Symbol>>) -> SpannedExpr<Symbol> {
    pos::spanned(
        span,
        Expr::App {
            func: Box::new(pos::spanned(span, Expr::Ident(TypedIdent::new(func)))),
            implicit_args: Vec::new(),
            args,
        },
    )
}

fn infix(
    span: Span<BytePos>,
    lhs: SpannedExpr<Symbol>,
    op: Symbol,
    rhs: SpannedExpr<Symbol>,
) -> SpannedExpr<Symbol> {
    pos::spanned(
        span,
        Expr::Infix {
            lhs: lhs.into(),
            op: pos::spanned(span, TypedIdent::new(op)),
            rhs: rhs.into(),
            implicit_args: Vec::new(),
        },
    )
}

fn is_self_type(self_: &Symbol, typ: &AstType<Symbol>) -> bool {
    match **typ {
        Type::App(ref f, _) => is_self_type(self_, f),
        Type::Alias(ref alias) => alias.name == *self_,
        Type::Ident(ref id) => id == self_,
        _ => false,
    }
}

fn generate_show(
    symbols: &mut Symbols,
    bind: &TypeBinding<Symbol>,
) -> Result<ValueBinding<Symbol>, Error> {
    let span = bind.name.span;

    let x = Symbol::from("x");
    let show_fn = TypedIdent::new(symbols.symbol("show_"));

    let show_expr = match **bind.alias.value.unresolved_type() {
        Type::Variant(ref variants) => {
            let alts = row_iter(variants)
                .map(|variant| {
                    let pattern_args: Vec<_> = arg_iter(&variant.typ)
                        .enumerate()
                        .map(|(i, typ)| {
                            (
                                is_self_type(&bind.alias.value.name, typ),
                                TypedIdent::new(Symbol::from(format!("arg_{}", i))),
                            )
                        })
                        .collect();

                    let expr = {
                        let open_brace = literal(span, variant.name.declared_name());

                        pattern_args
                            .iter()
                            .fold(open_brace, |acc, &(self_type, ref x)| {
                                let show_function = if self_type {
                                    show_fn.name.clone()
                                } else {
                                    symbols.symbol("show")
                                };
                                let show = infix(
                                    span,
                                    literal(span, "("),
                                    symbols.symbol("++"),
                                    infix(
                                        span,
                                        app(span, show_function, vec![ident(span, x.name.clone())]),
                                        symbols.symbol("++"),
                                        literal(span, ")"),
                                    ),
                                );
                                infix(
                                    span,
                                    acc,
                                    symbols.symbol("++"),
                                    infix(span, literal(span, " "), symbols.symbol("++"), show),
                                )
                            })
                    };

                    let ctor_pattern = |pattern_args: Vec<_>| {
                        pos::spanned(
                            span,
                            Pattern::Constructor(
                                TypedIdent::new(variant.name.clone()),
                                pattern_args
                                    .into_iter()
                                    .map(|arg| pos::spanned(span, Pattern::Ident(arg)))
                                    .collect(),
                            ),
                        )
                    };
                    Alternative {
                        pattern: ctor_pattern(pattern_args.into_iter().map(|t| t.1).collect()),
                        expr,
                    }
                })
                .collect();
            Expr::Match(Box::new(ident(span, x.clone())), alts)
        }
        Type::Record(ref row) => {
            let field_symbols: Vec<_> = row_iter(row)
                .map(|field| {
                    TypedIdent::new(Symbol::from(format!("{}", field.name.declared_name())))
                })
                .collect();

            let expr = {
                let open_brace = literal(span, "{ ");

                let show_expr = field_symbols
                    .iter()
                    .enumerate()
                    .fold(open_brace, |acc, (i, x)| {
                        let show = app(
                            span,
                            symbols.symbol("show"),
                            vec![ident(span, x.name.clone())],
                        );

                        let show_field = infix(
                            span,
                            acc,
                            symbols.symbol("++"),
                            infix(
                                span,
                                literal(span, &format!("{} = ", x.name.declared_name())),
                                symbols.symbol("++"),
                                show,
                            ),
                        );

                        let last = i == field_symbols.len() - 1;
                        let suffix = if last { " " } else { ", " };
                        infix(
                            span,
                            show_field,
                            symbols.symbol("++"),
                            literal(span, suffix),
                        )
                    });

                infix(span, show_expr, symbols.symbol("++"), literal(span, "}"))
            };
            let generate_record_pattern = |symbols| {
                pos::spanned(
                    span,
                    Pattern::Record {
                        implicit_import: None,
                        typ: Type::hole(),
                        types: Vec::new(),
                        fields: row_iter(row)
                            .zip(symbols)
                            .map(|(field, bind)| PatternField {
                                name: pos::spanned(span, field.name.clone()),
                                value: Some(pos::spanned(span, Pattern::Ident(bind))),
                            })
                            .collect(),
                    },
                )
            };
            Expr::Match(
                Box::new(ident(span, x.clone())),
                vec![Alternative {
                    pattern: generate_record_pattern(field_symbols),
                    expr,
                }],
            )
        }
        _ => return Err("Unable to derive Show for this type".into()),
    };

    let show_record_expr = Expr::LetBindings(
        vec![ValueBinding {
            name: pos::spanned(span, Pattern::Ident(show_fn.clone())),
            args: vec![Argument::explicit(pos::spanned(
                span,
                TypedIdent::new(x.clone()),
            ))],
            expr: pos::spanned(span, show_expr),
            metadata: Default::default(),
            typ: Some(Type::function(
                vec![Type::ident(bind.alias.value.name.clone())],
                Type::string(),
            )),
            resolved_type: Type::hole(),
        }],
        Box::new(pos::spanned(
            span,
            Expr::Record {
                typ: Type::hole(),
                types: Vec::new(),
                exprs: vec![ExprField {
                    metadata: Default::default(),
                    name: pos::spanned(span, symbols.symbol("show")),
                    value: Some(ident(span, show_fn.name.clone())),
                }],
                base: None,
            },
        )),
    );
    Ok(ValueBinding {
        name: pos::spanned(span, Pattern::Ident(TypedIdent::new(Symbol::from("show")))),
        args: Vec::new(),
        expr: pos::spanned(span, show_record_expr),
        metadata: Default::default(),
        typ: Some(Type::app(
            Type::ident(symbols.symbol("Show")),
            collect![Type::ident(bind.alias.value.name.clone())],
        )),
        resolved_type: Type::hole(),
    })
}

fn generate_eq(
    symbols: &mut Symbols,
    bind: &TypeBinding<Symbol>,
) -> Result<ValueBinding<Symbol>, Error> {
    let span = bind.name.span;

    let eq = TypedIdent::new(symbols.symbol("eq"));
    let l = Symbol::from("l");
    let r = Symbol::from("r");

    let matcher = Box::new(pos::spanned(
        span,
        Expr::Tuple {
            typ: Type::hole(),
            elems: vec![ident(span, l.clone()), ident(span, r.clone())],
        },
    ));

    let generate_and_chain =
        |symbols: &mut Symbols,
         iter: &mut Iterator<Item = (&(bool, TypedIdent<Symbol>), &TypedIdent<Symbol>)>| {
            iter.fold(None, |acc, (&(self_type, ref l), r)| {
                let equal_symbol = if self_type {
                    eq.name.clone()
                } else {
                    symbols.symbol("==")
                };

                let eq_check = app(
                    span,
                    equal_symbol,
                    vec![
                        ident(span, l.name.clone()).into(),
                        ident(span, r.name.clone()),
                    ],
                );

                Some(match acc {
                    Some(acc) => infix(span, acc, symbols.symbol("&&"), eq_check),
                    None => eq_check,
                })
            }).unwrap_or_else(|| ident(span, symbols.symbol("True")))
        };

    let comparison_expr = match **bind.alias.value.unresolved_type() {
        Type::Variant(ref variants) => {
            let catch_all_alternative = Alternative {
                pattern: pos::spanned(span, Pattern::Ident(TypedIdent::new(symbols.symbol("_")))),
                expr: ident(span, symbols.symbol("False")),
            };

            let alts = row_iter(variants)
                .map(|variant| {
                    let l_pattern_args: Vec<_> = arg_iter(&variant.typ)
                        .map(|typ| {
                            (
                                is_self_type(&bind.alias.value.name, typ),
                                TypedIdent::new(Symbol::from("arg_l")),
                            )
                        })
                        .collect();
                    let r_pattern_args: Vec<_> = arg_iter(&variant.typ)
                        .map(|_| TypedIdent::new(Symbol::from("arg_r")))
                        .collect();

                    let expr = generate_and_chain(
                        symbols,
                        &mut l_pattern_args.iter().zip(&r_pattern_args),
                    );

                    let ctor_pattern = |pattern_args: Vec<_>| {
                        pos::spanned(
                            span,
                            Pattern::Constructor(
                                TypedIdent::new(variant.name.clone()),
                                pattern_args
                                    .into_iter()
                                    .map(|arg| pos::spanned(span, Pattern::Ident(arg)))
                                    .collect(),
                            ),
                        )
                    };
                    Alternative {
                        pattern: pos::spanned(
                            span,
                            Pattern::Tuple {
                                typ: Type::hole(),
                                elems: vec![
                                    ctor_pattern(l_pattern_args.into_iter().map(|t| t.1).collect()),
                                    ctor_pattern(r_pattern_args),
                                ],
                            },
                        ),
                        expr,
                    }
                })
                .chain(Some(catch_all_alternative))
                .collect();
            Expr::Match(matcher, alts)
        }
        Type::Record(ref row) => {
            let l_symbols: Vec<_> = row_iter(row)
                .map(|field| {
                    (
                        is_self_type(&bind.alias.value.name, &field.typ),
                        TypedIdent::new(Symbol::from(format!("{}_l", field.name.declared_name()))),
                    )
                })
                .collect();
            let r_symbols: Vec<_> = row_iter(row)
                .map(|field| {
                    TypedIdent::new(Symbol::from(format!("{}_r", field.name.declared_name())))
                })
                .collect();

            let expr = generate_and_chain(symbols, &mut l_symbols.iter().zip(&r_symbols));
            let generate_record_pattern = |symbols| {
                pos::spanned(
                    span,
                    Pattern::Record {
                        implicit_import: None,
                        typ: Type::hole(),
                        types: Vec::new(),
                        fields: row_iter(row)
                            .zip(symbols)
                            .map(|(field, bind)| PatternField {
                                name: pos::spanned(span, field.name.clone()),
                                value: Some(pos::spanned(span, Pattern::Ident(bind))),
                            })
                            .collect(),
                    },
                )
            };
            Expr::Match(
                matcher,
                vec![Alternative {
                    pattern: pos::spanned(
                        span,
                        Pattern::Tuple {
                            elems: vec![
                                generate_record_pattern(
                                    l_symbols.into_iter().map(|t| t.1).collect(),
                                ),
                                generate_record_pattern(r_symbols),
                            ],
                            typ: Type::hole(),
                        },
                    ),
                    expr,
                }],
            )
        }
        _ => return Err("Unable to derive eq for this type".into()),
    };
    let eq_record_expr = Expr::LetBindings(
        vec![ValueBinding {
            name: pos::spanned(span, Pattern::Ident(eq.clone())),
            args: [l, r]
                .iter()
                .map(|arg| Argument::explicit(pos::spanned(span, TypedIdent::new(arg.clone()))))
                .collect(),
            expr: pos::spanned(span, comparison_expr),
            metadata: Default::default(),
            typ: Some(Type::function(
                vec![
                    Type::ident(bind.alias.value.name.clone()),
                    Type::ident(bind.alias.value.name.clone()),
                ],
                Type::hole(),
            )),
            resolved_type: Type::hole(),
        }],
        Box::new(pos::spanned(
            span,
            Expr::Record {
                typ: Type::hole(),
                types: Vec::new(),
                exprs: vec![ExprField {
                    metadata: Default::default(),
                    name: pos::spanned(span, symbols.symbol("==")),
                    value: Some(ident(span, eq.name.clone())),
                }],
                base: None,
            },
        )),
    );
    Ok(ValueBinding {
        name: pos::spanned(span, Pattern::Ident(TypedIdent::new(Symbol::from("eq")))),
        args: Vec::new(),
        expr: pos::spanned(span, eq_record_expr),
        metadata: Default::default(),
        typ: Some(Type::app(
            Type::ident(symbols.symbol("Eq")),
            collect![Type::ident(bind.alias.value.name.clone())],
        )),
        resolved_type: Type::hole(),
    })
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate clap;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate commercetools;
extern crate rustc_serialize;

use std::str::FromStr;
use clap::{App, Arg};
use commercetools::region::Region;
use commercetools::client::CtpClient;

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable)]
pub struct LocalizedString {
    pub en: String,
}

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable)]
pub struct ProductData {
    pub name: LocalizedString,
}

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable)]
pub struct ProductCatalogData {
    pub published: bool,
    pub hasStagedChanges: bool,
    pub current: ProductData,
    pub staged: ProductData,
}

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable)]
pub struct Product {
    pub id: String,
    pub version: u64,
    pub createdAt: String,
    pub lastModifiedAt: String,
    pub masterData: ProductCatalogData,
}

fn main() {
    env_logger::init().unwrap();
    let matches = App::new("sphere")
        .version("1.0")
        .author("Yann Simon <yann.simon@commercetools.com>")
        .args_from_usage(
            "<PROJECT_KEY> 'project key'
             <CLIENT_ID> 'client ID'
             <CLIENT_SECRET> 'client secret'
             --region=[Europe|NorthAmerica] 'region to use (default to Europe)'")
        .arg(Arg::with_name("permissions")
            .short("p")
            .long("permission")
            .help("permissions (default to manage_project)")
            .multiple(true)
            .takes_value(true)
        )
        .get_matches();

    let project_key = matches.value_of("PROJECT_KEY").unwrap();
    let client_id = matches.value_of("CLIENT_ID").unwrap();
    let client_secret = matches.value_of("CLIENT_SECRET").unwrap();
    let region = matches.value_of("region").map(|s| Region::from_str(s).unwrap()).unwrap_or(Region::Europe);
    let permissions: Vec<&str> = if matches.is_present("permissions") {
        matches.values_of("permissions").unwrap().collect()
    } else {
        vec!("manage_project")
    };

    let ctp_client = CtpClient::new(&region, project_key, client_id, client_secret)
        .with_permissions(permissions);

    let products = ctp_client.get("/products?limit=1").unwrap();
    println!("\nProducts: {}", products.body_as_string().unwrap());

    let products2 = ctp_client.list::<Product>("products").unwrap();
    println!("\nList of products: {:?}", products2);

    let reviews = ctp_client.get("/reviews?limit=1").unwrap();
    println!("\nReviews: {}", reviews.body_as_string().unwrap());

    let create = false;
    if create {
        let create_review = r#"
        {
          "text": "my review"
        }
        "#;
        let review = ctp_client.post("/reviews", create_review).unwrap();
        println!("\n[{}] New Review: {}", review.status(), review.body_as_string().unwrap());
    }
}
<commit_msg>more domain<commit_after>extern crate hyper;
extern crate clap;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate commercetools;
extern crate rustc_serialize;

use std::str::FromStr;
use clap::{App, Arg};
use commercetools::region::Region;
use commercetools::client::CtpClient;
use std::collections::HashMap;

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable)]
pub struct Reference {
    pub typeId: String,
    pub id: String,
}

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable)]
pub struct ProductVariant {
    pub id: u64,
    pub sku: Option<String>,
}

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable)]
pub struct ProductData {
    pub name: HashMap<String, String>,
    pub categories: Vec<Reference>,
    pub description: Option<HashMap<String, String>>,
    pub slug: HashMap<String, String>,
    pub metaTitle: Option<HashMap<String, String>>,
    pub metaDescription: Option<HashMap<String, String>>,
    pub metaKeywords: Option<HashMap<String, String>>,
    pub masterVariant: ProductVariant,
}

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable)]
pub struct ProductCatalogData {
    pub published: bool,
    pub hasStagedChanges: bool,
    pub current: ProductData,
    pub staged: ProductData,
}

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable)]
pub struct Product {
    pub id: String,
    pub version: u64,
    pub createdAt: String,
    pub lastModifiedAt: String,
    pub masterData: ProductCatalogData,
}

fn main() {
    env_logger::init().unwrap();
    let matches = App::new("sphere")
        .version("1.0")
        .author("Yann Simon <yann.simon@commercetools.com>")
        .args_from_usage(
            "<PROJECT_KEY> 'project key'
             <CLIENT_ID> 'client ID'
             <CLIENT_SECRET> 'client secret'
             --region=[Europe|NorthAmerica] 'region to use (default to Europe)'")
        .arg(Arg::with_name("permissions")
            .short("p")
            .long("permission")
            .help("permissions (default to manage_project)")
            .multiple(true)
            .takes_value(true)
        )
        .get_matches();

    let project_key = matches.value_of("PROJECT_KEY").unwrap();
    let client_id = matches.value_of("CLIENT_ID").unwrap();
    let client_secret = matches.value_of("CLIENT_SECRET").unwrap();
    let region = matches.value_of("region").map(|s| Region::from_str(s).unwrap()).unwrap_or(Region::Europe);
    let permissions: Vec<&str> = if matches.is_present("permissions") {
        matches.values_of("permissions").unwrap().collect()
    } else {
        vec!("manage_project")
    };

    let ctp_client = CtpClient::new(&region, project_key, client_id, client_secret)
        .with_permissions(permissions);

    let products = ctp_client.get("/products?limit=1").unwrap();
    println!("\nProducts: {}", products.body_as_string().unwrap());

    let products2 = ctp_client.list::<Product>("products").unwrap();
    println!("\nList of product ids: {:?}", products2.results.iter().map(|p| &p.id).collect::<Vec<&String>>());

    println!("\nFirst product: {:?}", &products2.results.first());

    let reviews = ctp_client.get("/reviews?limit=1").unwrap();
    println!("\nReviews: {}", reviews.body_as_string().unwrap());

    let create = false;
    if create {
        let create_review = r#"
        {
          "text": "my review"
        }
        "#;
        let review = ctp_client.post("/reviews", create_review).unwrap();
        println!("\n[{}] New Review: {}", review.status(), review.body_as_string().unwrap());
    }
}
<|endoftext|>


<commit_before>#![cfg(feature = "reqwest-backend")]

use std::env::{remove_var, set_var};
use std::error::Error;
use std::net::TcpListener;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Mutex;
use std::thread;
use std::time::Duration;

use env_proxy::for_url;
use lazy_static::lazy_static;
use reqwest::{blocking::Client, Proxy};
use url::Url;

lazy_static! {
    static ref SERIALISE_TESTS: Mutex<()> = Mutex::new(());
}

fn scrub_env() {
    remove_var("http_proxy");
    remove_var("https_proxy");
    remove_var("HTTPS_PROXY");
    remove_var("ftp_proxy");
    remove_var("FTP_PROXY");
    remove_var("all_proxy");
    remove_var("ALL_PROXY");
    remove_var("no_proxy");
    remove_var("NO_PROXY");
}

// Tests for correctly retrieving the proxy (host, port) tuple from $https_proxy
#[test]
fn read_basic_proxy_params() {
    let _guard = SERIALISE_TESTS
        .lock()
        .expect("Unable to lock the test guard");
    scrub_env();
    set_var("https_proxy", "http://proxy.example.com:8080");
    let u = Url::parse("https://www.example.org").ok().unwrap();
    assert_eq!(
        for_url(&u).host_port(),
        Some(("proxy.example.com".to_string(), 8080))
    );
}

// Tests to verify if socks feature is available and being used
#[test]
fn socks_proxy_request() {
    static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
    let _guard = SERIALISE_TESTS
        .lock()
        .expect("Unable to lock the test guard");

    scrub_env();
    set_var("all_proxy", "socks5://127.0.0.1:1080");

    thread::spawn(move || {
        let listener = TcpListener::bind("127.0.0.1:1080").unwrap();
        let incoming = listener.incoming();
        for _ in incoming {
            CALL_COUNT.fetch_add(1, Ordering::SeqCst);
        }
    });

    let env_proxy = |url: &Url| for_url(&url).to_url();
    let url = Url::parse("http://example.org").unwrap();

    let client = Client::builder()
        .proxy(Proxy::custom(env_proxy))
        .timeout(Duration::from_secs(1))
        .build()
        .unwrap();
    let res = client.get(url.as_str()).send();

    if let Err(e) = res {
        let s = e.source().unwrap();
        assert_eq!(CALL_COUNT.load(Ordering::SeqCst), 1);
        assert!(s.to_string().contains("socks connect error"));
    } else {
        panic!("Socks proxy was ignored")
    }
}
<commit_msg>download: Use an IP address when testing socks support<commit_after>#![cfg(feature = "reqwest-backend")]

use std::env::{remove_var, set_var};
use std::error::Error;
use std::net::TcpListener;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Mutex;
use std::thread;
use std::time::Duration;

use env_proxy::for_url;
use lazy_static::lazy_static;
use reqwest::{blocking::Client, Proxy};
use url::Url;

lazy_static! {
    static ref SERIALISE_TESTS: Mutex<()> = Mutex::new(());
}

fn scrub_env() {
    remove_var("http_proxy");
    remove_var("https_proxy");
    remove_var("HTTPS_PROXY");
    remove_var("ftp_proxy");
    remove_var("FTP_PROXY");
    remove_var("all_proxy");
    remove_var("ALL_PROXY");
    remove_var("no_proxy");
    remove_var("NO_PROXY");
}

// Tests for correctly retrieving the proxy (host, port) tuple from $https_proxy
#[test]
fn read_basic_proxy_params() {
    let _guard = SERIALISE_TESTS
        .lock()
        .expect("Unable to lock the test guard");
    scrub_env();
    set_var("https_proxy", "http://proxy.example.com:8080");
    let u = Url::parse("https://www.example.org").ok().unwrap();
    assert_eq!(
        for_url(&u).host_port(),
        Some(("proxy.example.com".to_string(), 8080))
    );
}

// Tests to verify if socks feature is available and being used
#[test]
fn socks_proxy_request() {
    static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
    let _guard = SERIALISE_TESTS
        .lock()
        .expect("Unable to lock the test guard");

    scrub_env();
    set_var("all_proxy", "socks5://127.0.0.1:1080");

    thread::spawn(move || {
        let listener = TcpListener::bind("127.0.0.1:1080").unwrap();
        let incoming = listener.incoming();
        for _ in incoming {
            CALL_COUNT.fetch_add(1, Ordering::SeqCst);
        }
    });

    let env_proxy = |url: &Url| for_url(&url).to_url();
    let url = Url::parse("http://192.168.0.1/").unwrap();

    let client = Client::builder()
        .proxy(Proxy::custom(env_proxy))
        .timeout(Duration::from_secs(1))
        .build()
        .unwrap();
    let res = client.get(url.as_str()).send();

    if let Err(e) = res {
        let s = e.source().unwrap();
        assert_eq!(CALL_COUNT.load(Ordering::SeqCst), 1);
        assert!(s.to_string().contains("socks connect error"));
    } else {
        panic!("Socks proxy was ignored")
    }
}
<|endoftext|>


<commit_before>//! Askama implements a type-safe compiler for Jinja-like templates.
//! It lets you write templates in a Jinja-like syntax,
//! which are linked to a `struct` defining the template context.
//! This is done using a custom derive implementation (implemented
//! in [`askama_derive`](https://crates.io/crates/askama_derive)).
//!
//! # Example template
//!
//! ```text
//! {% extends "layout.html" %}
//! {% block body %}
//!   <ul>
//!     {% for user in users %}
//!       <li><a href="{{ user.url }}">{{ user.username }}</a></li>
//!     {% endfor %}
//!   </ul>
//! {% endblock %}
//! ```
//!
//! # Feature highlights
//!
//! * Construct templates using a familiar, easy-to-use syntax
//! * Benefit from the safety provided by Rust's type system
//! * Template code is compiled into your crate for optimal performance
//! * Templates only convert your data as needed
//! * Templates can access your Rust types directly, according to Rust's
//!   privacy rules
//! * Debugging features to assist you in template development
//! * Templates must be valid UTF-8 and produce UTF-8 when rendered
//! * Works on stable Rust
//!
//! # Creating Askama templates
//!
//! An Askama template is just a text file, in the UTF-8 encoding.
//! It can be used to generate any kind of text-based format.
//! You can use whatever extension you like.
//!
//! A template consists of **text contents**, which are passed through as-is,
//! **expressions**, which get replaced with content while being rendered, and
//! **tags**, which control the template's logic.
//! The template syntax is very similar to [Jinja](http://jinja.pocoo.org/),
//! as well as Jinja-derivatives like [Twig](http://twig.sensiolabs.org/) or
//! [Tera](https://github.com/Keats/tera).
//!
//! ## Variables
//!
//! Template variables are defined by the template context linked to the
//! template by deriving a `struct`'s implementation for `Template` from
//! a template file's contents.
//! You can use a dot (`.`) to get a variable's attributes.
//! Reading from variables is subject to the usual borrowing policies.
//! For example, `{{ name }}` will get the ``name`` field from the template
//! context,
//! while `{{ user.name }}` will get the ``name`` field of the `user`
//! ``field`` of the template context.
//!
//! ## Filters
//!
//! Values such as those obtained from variables can be post-processed
//! using **filters**.
//! Filters are applied to values using the pipe symbol (`|`) and may
//! have optional extra arguments in parentheses.
//! Filters can be chained, in which case the output from one filter
//! is passed to the next.
//!
//! For example, `{{ "{:?}"|format(name|escape) }}` will escape HTML
//! characters from the value obtained by accessing the `name` field,
//! and print the resulting string as a Rust literal.
//!
//! Consult the [filters module documentation](filters/index.html) for a list
//! of available filters. User-defined filters are currently not supported.
//!
//! ## Whitespace control
//!
//! Askama preserves all whitespace in template code by default,
//! except that final trailing newline characters are suppressed.
//! However, whitespace before and after expression and block delimiters
//! can be suppressed by writing a minus sign directly following a
//! start delimiter or leading into an end delimiter.
//! Askama considers all tabs, spaces, newlines and carriage returns to be
//! whitespace.
//!
//! ## Template inheritance
//!
//! Template inheritance allows you to build a base template with common
//! elements that can then be shared by all inheriting templates.
//! A base template defines **blocks** that child templates can then override.
//!
//! ### Base template
//!
//! ```text
//! <!DOCTYPE html>
//! <html lang="en">
//!   <head>
//!     <title>{{ block title %}{{ title }}{% endblock %} - My Site</title>
//!     {% block head %}{% endblock %}
//!   </head>
//!   <body>
//!     <div id="content">
//!       {% block content %}{% endblock %}
//!     </div>
//!   </body>
//! </html>
//! ```
//!
//! The `block` tags define three blocks that can be filled in by child
//! templates. The base template defines a default version of the block.
//!
//! ### Child template
//!
//! Here's an example child template:
//!
//! ```text
//! {% extends "base.html" %}
//!
//! {% block title %}Index{% endblock %}
//!
//! {% block head %}
//!   <style>
//!   </style>
//! {% endblock %}
//!
//! {% block content %}
//!   <h1>Index</h1>
//!   <p>Hello, world!</p>
//! {% endblock %}
//! ```
//!
//! The `extends` tag tells the code generator that this template inherits
//! from another template. It will render the top-level content from the
//! base template, and substitute blocks from the base template with those
//! from the child template. The inheriting template context `struct` must
//! have a field called `_parent` of the type used as the base template
//! context. Blocks can only refer to the context of their own template.
//!
//! ## HTML escaping
//!
//! Askama does not yet support automatic escaping. Care must be taken to
//! escape content that may contain HTML control characters. You can use
//! the `escape` filter (or its `e` alias) to escape data for use in HTML.
//!
//! ## Control structures
//!
//! ### For
//!
//! Loop over each item in an iterator. For example:
//!
//! ```text
//! <h1>Users</h1>
//! <ul>
//! {% for user in users %}
//!   <li>{{ user.name|e }}</li>
//! {% endfor %}
//! </ul>
//! ```
//!
//! Inside for-loop blocks, some useful variables are accessible:
//!
//! * *loop.index*: current loop iteration (starting from 1)
//! * *loop.index0*: current loop iteration (starting from 0)
//!
//! ### If
//!
//! The *if* statement is used as you might expect:
//!
//! ```text
//! {% if users.len() == 0 %}
//!   No users
//! {% else if users.len() == 1 %}
//!   1 user
//! {% else %}
//!   {{ users.len() }} users
//! {% endif %}
//! ```
//!
//! ## Expressions
//!
//! Askama supports string literals (`"foo"`) and integer literals (`1`).
//! It supports almost all binary operators that Rust supports,
//! including arithmetic, comparison and logic operators.
//! The same precedence order as Rust uses is applied.
//! Expressions can be grouped using parentheses.

#![allow(unused_imports)]
#[macro_use]
extern crate askama_derive;

use std::env;
use std::fs::{self, DirEntry};
use std::io;
use std::path::{Path, PathBuf};

/// Main `Template` trait; implementations are generally derived
pub trait Template {
    /// Renders the template to the given `writer` buffer
    fn render_to(&self, writer: &mut std::fmt::Write);
    /// Helper method which allocates a new `String` and renders into it
    fn render(&self) -> String {
        let mut buf = String::new();
        self.render_to(&mut buf);
        buf
    }
}

pub mod filters;
pub use askama_derive::*;

// Duplicates askama_derive::path::template_dir()
fn template_dir() -> PathBuf {
    let mut path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
    path.push("templates");
    path
}

fn visit_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<()> {
    if dir.is_dir() {
        for entry in try!(fs::read_dir(dir)) {
            let entry = try!(entry);
            let path = entry.path();
            if path.is_dir() {
                try!(visit_dirs(&path, cb));
            } else {
                cb(&entry);
            }
        }
    }
    Ok(())
}

/// Build script helper to rebuild crates if contained templates have changed
///
/// Iterates over all files in the template dir (`templates` in
/// `CARGO_MANIFEST_DIR`) and writes a `cargo:rerun-if-changed=` line for each
/// of them to stdout.
///
/// This helper method can be used in build scripts (`build.rs`) in crates
/// that have templates, to make sure the crate gets rebuilt when template
/// source code changes.
pub fn rerun_if_templates_changed() {
    visit_dirs(&template_dir(), &|e: &DirEntry| {
        println!("cargo:rerun-if-changed={}", e.path().to_str().unwrap());
    }).unwrap();
}
<commit_msg>Fix formatting in "Variables" section of docs<commit_after>//! Askama implements a type-safe compiler for Jinja-like templates.
//! It lets you write templates in a Jinja-like syntax,
//! which are linked to a `struct` defining the template context.
//! This is done using a custom derive implementation (implemented
//! in [`askama_derive`](https://crates.io/crates/askama_derive)).
//!
//! # Example template
//!
//! ```text
//! {% extends "layout.html" %}
//! {% block body %}
//!   <ul>
//!     {% for user in users %}
//!       <li><a href="{{ user.url }}">{{ user.username }}</a></li>
//!     {% endfor %}
//!   </ul>
//! {% endblock %}
//! ```
//!
//! # Feature highlights
//!
//! * Construct templates using a familiar, easy-to-use syntax
//! * Benefit from the safety provided by Rust's type system
//! * Template code is compiled into your crate for optimal performance
//! * Templates only convert your data as needed
//! * Templates can access your Rust types directly, according to Rust's
//!   privacy rules
//! * Debugging features to assist you in template development
//! * Templates must be valid UTF-8 and produce UTF-8 when rendered
//! * Works on stable Rust
//!
//! # Creating Askama templates
//!
//! An Askama template is just a text file, in the UTF-8 encoding.
//! It can be used to generate any kind of text-based format.
//! You can use whatever extension you like.
//!
//! A template consists of **text contents**, which are passed through as-is,
//! **expressions**, which get replaced with content while being rendered, and
//! **tags**, which control the template's logic.
//! The template syntax is very similar to [Jinja](http://jinja.pocoo.org/),
//! as well as Jinja-derivatives like [Twig](http://twig.sensiolabs.org/) or
//! [Tera](https://github.com/Keats/tera).
//!
//! ## Variables
//!
//! Template variables are defined by the template context linked to the
//! template by deriving a `struct`'s implementation for `Template` from
//! a template file's contents.
//! You can use a dot (`.`) to get a variable's attributes.
//! Reading from variables is subject to the usual borrowing policies.
//! For example, `{{ name }}` will get the ``name`` field from the template
//! context,
//! while `{{ user.name }}` will get the ``name`` field of the ``user``
//! field of the template context.
//!
//! ## Filters
//!
//! Values such as those obtained from variables can be post-processed
//! using **filters**.
//! Filters are applied to values using the pipe symbol (`|`) and may
//! have optional extra arguments in parentheses.
//! Filters can be chained, in which case the output from one filter
//! is passed to the next.
//!
//! For example, `{{ "{:?}"|format(name|escape) }}` will escape HTML
//! characters from the value obtained by accessing the `name` field,
//! and print the resulting string as a Rust literal.
//!
//! Consult the [filters module documentation](filters/index.html) for a list
//! of available filters. User-defined filters are currently not supported.
//!
//! ## Whitespace control
//!
//! Askama preserves all whitespace in template code by default,
//! except that final trailing newline characters are suppressed.
//! However, whitespace before and after expression and block delimiters
//! can be suppressed by writing a minus sign directly following a
//! start delimiter or leading into an end delimiter.
//! Askama considers all tabs, spaces, newlines and carriage returns to be
//! whitespace.
//!
//! ## Template inheritance
//!
//! Template inheritance allows you to build a base template with common
//! elements that can then be shared by all inheriting templates.
//! A base template defines **blocks** that child templates can then override.
//!
//! ### Base template
//!
//! ```text
//! <!DOCTYPE html>
//! <html lang="en">
//!   <head>
//!     <title>{{ block title %}{{ title }}{% endblock %} - My Site</title>
//!     {% block head %}{% endblock %}
//!   </head>
//!   <body>
//!     <div id="content">
//!       {% block content %}{% endblock %}
//!     </div>
//!   </body>
//! </html>
//! ```
//!
//! The `block` tags define three blocks that can be filled in by child
//! templates. The base template defines a default version of the block.
//!
//! ### Child template
//!
//! Here's an example child template:
//!
//! ```text
//! {% extends "base.html" %}
//!
//! {% block title %}Index{% endblock %}
//!
//! {% block head %}
//!   <style>
//!   </style>
//! {% endblock %}
//!
//! {% block content %}
//!   <h1>Index</h1>
//!   <p>Hello, world!</p>
//! {% endblock %}
//! ```
//!
//! The `extends` tag tells the code generator that this template inherits
//! from another template. It will render the top-level content from the
//! base template, and substitute blocks from the base template with those
//! from the child template. The inheriting template context `struct` must
//! have a field called `_parent` of the type used as the base template
//! context. Blocks can only refer to the context of their own template.
//!
//! ## HTML escaping
//!
//! Askama does not yet support automatic escaping. Care must be taken to
//! escape content that may contain HTML control characters. You can use
//! the `escape` filter (or its `e` alias) to escape data for use in HTML.
//!
//! ## Control structures
//!
//! ### For
//!
//! Loop over each item in an iterator. For example:
//!
//! ```text
//! <h1>Users</h1>
//! <ul>
//! {% for user in users %}
//!   <li>{{ user.name|e }}</li>
//! {% endfor %}
//! </ul>
//! ```
//!
//! Inside for-loop blocks, some useful variables are accessible:
//!
//! * *loop.index*: current loop iteration (starting from 1)
//! * *loop.index0*: current loop iteration (starting from 0)
//!
//! ### If
//!
//! The *if* statement is used as you might expect:
//!
//! ```text
//! {% if users.len() == 0 %}
//!   No users
//! {% else if users.len() == 1 %}
//!   1 user
//! {% else %}
//!   {{ users.len() }} users
//! {% endif %}
//! ```
//!
//! ## Expressions
//!
//! Askama supports string literals (`"foo"`) and integer literals (`1`).
//! It supports almost all binary operators that Rust supports,
//! including arithmetic, comparison and logic operators.
//! The same precedence order as Rust uses is applied.
//! Expressions can be grouped using parentheses.

#![allow(unused_imports)]
#[macro_use]
extern crate askama_derive;

use std::env;
use std::fs::{self, DirEntry};
use std::io;
use std::path::{Path, PathBuf};

/// Main `Template` trait; implementations are generally derived
pub trait Template {
    /// Renders the template to the given `writer` buffer
    fn render_to(&self, writer: &mut std::fmt::Write);
    /// Helper method which allocates a new `String` and renders into it
    fn render(&self) -> String {
        let mut buf = String::new();
        self.render_to(&mut buf);
        buf
    }
}

pub mod filters;
pub use askama_derive::*;

// Duplicates askama_derive::path::template_dir()
fn template_dir() -> PathBuf {
    let mut path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
    path.push("templates");
    path
}

fn visit_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<()> {
    if dir.is_dir() {
        for entry in try!(fs::read_dir(dir)) {
            let entry = try!(entry);
            let path = entry.path();
            if path.is_dir() {
                try!(visit_dirs(&path, cb));
            } else {
                cb(&entry);
            }
        }
    }
    Ok(())
}

/// Build script helper to rebuild crates if contained templates have changed
///
/// Iterates over all files in the template dir (`templates` in
/// `CARGO_MANIFEST_DIR`) and writes a `cargo:rerun-if-changed=` line for each
/// of them to stdout.
///
/// This helper method can be used in build scripts (`build.rs`) in crates
/// that have templates, to make sure the crate gets rebuilt when template
/// source code changes.
pub fn rerun_if_templates_changed() {
    visit_dirs(&template_dir(), &|e: &DirEntry| {
        println!("cargo:rerun-if-changed={}", e.path().to_str().unwrap());
    }).unwrap();
}
<|endoftext|>


<commit_before>//!

use collections::{Map, Set};
use ena::unify::UnificationTable;
use grammar::repr::*;
use lr1::build;
use lr1::core::*;
use lr1::first::FirstSets;
use lr1::lookahead::{Lookahead, TokenSet};
use lr1::lane_table::lane::LaneTracer;
use lr1::lane_table::table::{ConflictIndex, LaneTable};
use lr1::lane_table::table::context_set::OverlappingLookahead;
use lr1::state_graph::StateGraph;
use std::rc::Rc;

mod merge;
use self::merge::Merge;

mod state_set;
use self::state_set::StateSet;

pub struct LaneTableConstruct<'grammar> {
    grammar: &'grammar Grammar,
    first_sets: FirstSets,
    start_nt: NonterminalString,
}

impl<'grammar> LaneTableConstruct<'grammar> {
    pub fn new(grammar: &'grammar Grammar, start_nt: NonterminalString) -> Self {
        let first_sets = FirstSets::new(grammar);
        LaneTableConstruct {
            grammar: grammar,
            start_nt: start_nt,
            first_sets: first_sets,
        }
    }

    pub fn construct(self) -> Result<Vec<LR1State<'grammar>>, LR1TableConstructionError<'grammar>> {
        let TableConstructionError { states, conflicts: _ } = {
            match build::build_lr0_states(self.grammar, self.start_nt) {
                // This is the easy (and very rare...) case.
                Ok(lr0) => return Ok(self.promote_lr0_states(lr0)),
                Err(err) => err,
            }
        };

        // Convert the LR(0) states into LR(0-1) states.
        let mut states = self.promote_lr0_states(states);

        // For each inconsistent state, apply the lane-table algorithm to
        // resolve it.
        for i in 0.. {
            if i >= states.len() {
                break;
            }

            match self.resolve_inconsistencies(&mut states, StateIndex(i)) {
                Ok(()) => { }
                Err(_) => {
                    // We failed because of irreconcilable conflicts
                    // somewhere. Just compute the conflicts from the final set of
                    // states.
                    let conflicts: Vec<Conflict<'grammar, TokenSet>> =
                        states.iter()
                              .flat_map(|s| Lookahead::conflicts(&s))
                              .collect();
                    return Err(TableConstructionError { states: states,
                                                        conflicts: conflicts });
                }
            }
        }

        Ok(states)
    }

    /// Given a set of LR0 states, returns LR1 states where the lookahead
    /// is always `TokenSet::all()`. We refer to these states as LR(0-1)
    /// states in the README.
    fn promote_lr0_states(&self, lr0: Vec<LR0State<'grammar>>) -> Vec<LR1State<'grammar>> {
        let all = TokenSet::all();
        debug!("promote_lr0_states: all={:?}", all);
        lr0.into_iter()
            .map(|s| {
                let items = s.items
                    .vec
                    .iter()
                    .map(|item| {
                        Item {
                            production: item.production,
                            index: item.index,
                            lookahead: all.clone(),
                        }
                    })
                    .collect();
                let reductions = s.reductions
                    .into_iter()
                    .map(|(_, p)| (all.clone(), p))
                    .collect();
                State {
                    index: s.index,
                    items: Items { vec: Rc::new(items) },
                    shifts: s.shifts,
                    reductions: reductions,
                    gotos: s.gotos,
                }
            })
            .collect()
    }

    fn resolve_inconsistencies(&self,
                               states: &mut Vec<LR1State<'grammar>>,
                               inconsistent_state: StateIndex)
                               -> Result<(), StateIndex> {
        debug!("resolve_inconsistencies(inconsistent_state={:?}/{:#?}",
               inconsistent_state, states[inconsistent_state.0]);

        let actions = super::conflicting_actions(&states[inconsistent_state.0]);
        if actions.is_empty() {
            return Ok(());
        }

        debug!("resolve_inconsistencies: conflicting_actions={:?}", actions);

        let table = self.build_lane_table(states, inconsistent_state, &actions);

        // Consider first the "LALR" case, where the lookaheads for each
        // action are completely disjoint.
        if self.attempt_lalr(&mut states[inconsistent_state.0], &table, &actions) {
            return Ok(());
        }

        // Construct the initial states; each state will map to a
        // context-set derived from its row in the lane-table. This is
        // fallible, because a state may be internally inconstent.
        //
        // (To handle unification, we also map each state to a
        // `StateSet` that is its entry in the `ena` table.)
        let rows = table.rows()?;
        let mut unify = UnificationTable::<StateSet>::new();
        let mut state_sets = Map::new();
        for (&state_index, context_set) in &rows {
            let state_set = unify.new_key(context_set.clone());
            state_sets.insert(state_index, state_set);
            debug!("resolve_inconsistencies: state_index={:?}, state_set={:?}",
                   state_index, state_set);
        }

        // Now merge state-sets, cloning states where needed.
        let mut merge = Merge::new(&table, &mut unify, states, &mut state_sets, inconsistent_state);
        let beachhead_states = table.beachhead_states();
        for beachhead_state in beachhead_states {
            match merge.start(beachhead_state) {
                Ok(()) => { }
                Err((source, _)) => return Err(source),
            }
        }
        merge.patch_target_starts(&actions);

        Ok(())
    }

    fn attempt_lalr(&self,
                    state: &mut LR1State<'grammar>,
                    table: &LaneTable<'grammar>,
                    actions: &Set<Action<'grammar>>)
                    -> bool {
        match table.columns() {
            Ok(columns) => {
                debug!("attempt_lalr, columns={:#?}", columns);
                columns.apply(state, actions);
                true
            }
            Err(OverlappingLookahead) => {
                debug!("attempt_lalr, OverlappingLookahead");
                false
            }
        }
    }

    fn build_lane_table(&self,
                        states: &[LR1State<'grammar>],
                        inconsistent_state: StateIndex,
                        actions: &Set<Action<'grammar>>)
                        -> LaneTable<'grammar> {
        let state_graph = StateGraph::new(states);
        let mut tracer = LaneTracer::new(self.grammar,
                                         self.start_nt,
                                         states,
                                         &self.first_sets,
                                         &state_graph,
                                         actions.len());
        for (i, &action) in actions.iter().enumerate() {
            tracer.start_trace(inconsistent_state, ConflictIndex::new(i), action);
        }
        tracer.into_table()
    }
}
<commit_msg>in lane table mode, run algorithm even with just one reduce<commit_after>//!

use collections::{Map, Set};
use ena::unify::UnificationTable;
use grammar::repr::*;
use lr1::build;
use lr1::core::*;
use lr1::first::FirstSets;
use lr1::lookahead::{Lookahead, TokenSet};
use lr1::lane_table::lane::LaneTracer;
use lr1::lane_table::table::{ConflictIndex, LaneTable};
use lr1::lane_table::table::context_set::OverlappingLookahead;
use lr1::state_graph::StateGraph;
use std::rc::Rc;

mod merge;
use self::merge::Merge;

mod state_set;
use self::state_set::StateSet;

pub struct LaneTableConstruct<'grammar> {
    grammar: &'grammar Grammar,
    first_sets: FirstSets,
    start_nt: NonterminalString,
}

impl<'grammar> LaneTableConstruct<'grammar> {
    pub fn new(grammar: &'grammar Grammar, start_nt: NonterminalString) -> Self {
        let first_sets = FirstSets::new(grammar);
        LaneTableConstruct {
            grammar: grammar,
            start_nt: start_nt,
            first_sets: first_sets,
        }
    }

    pub fn construct(self) -> Result<Vec<LR1State<'grammar>>, LR1TableConstructionError<'grammar>> {
        let TableConstructionError { states, conflicts: _ } = {
            match build::build_lr0_states(self.grammar, self.start_nt) {
                // This is the easy (and very rare...) case.
                Ok(lr0) => return Ok(self.promote_lr0_states(lr0)),
                Err(err) => err,
            }
        };

        // Convert the LR(0) states into LR(0-1) states.
        let mut states = self.promote_lr0_states(states);

        // For each inconsistent state, apply the lane-table algorithm to
        // resolve it.
        for i in 0.. {
            if i >= states.len() {
                break;
            }

            match self.resolve_inconsistencies(&mut states, StateIndex(i)) {
                Ok(()) => { }
                Err(_) => {
                    // We failed because of irreconcilable conflicts
                    // somewhere. Just compute the conflicts from the final set of
                    // states.
                    let conflicts: Vec<Conflict<'grammar, TokenSet>> =
                        states.iter()
                              .flat_map(|s| Lookahead::conflicts(&s))
                              .collect();
                    return Err(TableConstructionError { states: states,
                                                        conflicts: conflicts });
                }
            }
        }

        Ok(states)
    }

    /// Given a set of LR0 states, returns LR1 states where the lookahead
    /// is always `TokenSet::all()`. We refer to these states as LR(0-1)
    /// states in the README.
    fn promote_lr0_states(&self, lr0: Vec<LR0State<'grammar>>) -> Vec<LR1State<'grammar>> {
        let all = TokenSet::all();
        debug!("promote_lr0_states: all={:?}", all);
        lr0.into_iter()
            .map(|s| {
                let items = s.items
                    .vec
                    .iter()
                    .map(|item| {
                        Item {
                            production: item.production,
                            index: item.index,
                            lookahead: all.clone(),
                        }
                    })
                    .collect();
                let reductions = s.reductions
                    .into_iter()
                    .map(|(_, p)| (all.clone(), p))
                    .collect();
                State {
                    index: s.index,
                    items: Items { vec: Rc::new(items) },
                    shifts: s.shifts,
                    reductions: reductions,
                    gotos: s.gotos,
                }
            })
            .collect()
    }

    fn resolve_inconsistencies(&self,
                               states: &mut Vec<LR1State<'grammar>>,
                               inconsistent_state: StateIndex)
                               -> Result<(), StateIndex> {
        debug!("resolve_inconsistencies(inconsistent_state={:?}/{:#?}",
               inconsistent_state, states[inconsistent_state.0]);

        let mut actions = super::conflicting_actions(&states[inconsistent_state.0]);
        if actions.is_empty() {
            // This can mean one of two things: only shifts, or a
            // single reduction. We have to be careful about states
            // with a single reduction: even though such a state is
            // not inconsistent (there is only one possible course of
            // action), we still want to run the lane table algorithm,
            // because otherwise we get states with "complete"
            // lookahead, which messes with error recovery.
            //
            // In particular, if there is too much lookahead, we will
            // reduce even when it is inappropriate to do so.
            actions = states[inconsistent_state.0].reductions
                                                  .iter()
                                                  .map(|&(_, prod)| Action::Reduce(prod))
                                                  .collect();
            if actions.is_empty() {
                return Ok(());
            }
        }

        debug!("resolve_inconsistencies: conflicting_actions={:?}", actions);

        let table = self.build_lane_table(states, inconsistent_state, &actions);

        // Consider first the "LALR" case, where the lookaheads for each
        // action are completely disjoint.
        if self.attempt_lalr(&mut states[inconsistent_state.0], &table, &actions) {
            return Ok(());
        }

        // Construct the initial states; each state will map to a
        // context-set derived from its row in the lane-table. This is
        // fallible, because a state may be internally inconstent.
        //
        // (To handle unification, we also map each state to a
        // `StateSet` that is its entry in the `ena` table.)
        let rows = table.rows()?;
        let mut unify = UnificationTable::<StateSet>::new();
        let mut state_sets = Map::new();
        for (&state_index, context_set) in &rows {
            let state_set = unify.new_key(context_set.clone());
            state_sets.insert(state_index, state_set);
            debug!("resolve_inconsistencies: state_index={:?}, state_set={:?}",
                   state_index, state_set);
        }

        // Now merge state-sets, cloning states where needed.
        let mut merge = Merge::new(&table, &mut unify, states, &mut state_sets, inconsistent_state);
        let beachhead_states = table.beachhead_states();
        for beachhead_state in beachhead_states {
            match merge.start(beachhead_state) {
                Ok(()) => { }
                Err((source, _)) => return Err(source),
            }
        }
        merge.patch_target_starts(&actions);

        Ok(())
    }

    fn attempt_lalr(&self,
                    state: &mut LR1State<'grammar>,
                    table: &LaneTable<'grammar>,
                    actions: &Set<Action<'grammar>>)
                    -> bool {
        match table.columns() {
            Ok(columns) => {
                debug!("attempt_lalr, columns={:#?}", columns);
                columns.apply(state, actions);
                debug!("attempt_lalr, state={:#?}", state);
                true
            }
            Err(OverlappingLookahead) => {
                debug!("attempt_lalr, OverlappingLookahead");
                false
            }
        }
    }

    fn build_lane_table(&self,
                        states: &[LR1State<'grammar>],
                        inconsistent_state: StateIndex,
                        actions: &Set<Action<'grammar>>)
                        -> LaneTable<'grammar> {
        let state_graph = StateGraph::new(states);
        let mut tracer = LaneTracer::new(self.grammar,
                                         self.start_nt,
                                         states,
                                         &self.first_sets,
                                         &state_graph,
                                         actions.len());
        for (i, &action) in actions.iter().enumerate() {
            tracer.start_trace(inconsistent_state, ConflictIndex::new(i), action);
        }
        tracer.into_table()
    }
}
<|endoftext|>