<commit_before>//  K8055.rs is a library for controlling the Vellemann K8055 USB IO card from rust.
//  Copyright (C) 2014 Falco Hirschenberger <falco.hirschenberger@gmail.com>
//
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License along
//  with this program; if not, write to the Free Software Foundation, Inc.,
//  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

//! Driver library for controlling the *Vellemann K8055(N)* USB digital and analog IO-cards.
//!
//! See the Vellemann [Homepage](http://www.velleman.eu/products/view/?id=351346) for the
//! hardware specification.

#![crate_type = "lib"]
extern crate libc;
extern crate usb;
extern crate serialize;

use std::iter::range_inclusive;
use std::fmt::{Show, Formatter, FormatError};
use std::default::Default;
use usb::libusb;

/// Analog values in the range (0-255).
#[deriving(PartialEq, PartialOrd, Show)]
pub enum AnalogChannel {
      A1(u8),
      A2(u8)
}

bitflags!(
#[doc = "
The digital channel values.

Can be combined with bitoperations.

    let dc = k8055::D1 & k8055::D2 & k8055::D3;

See the bitflags documentation for more information.
"]
  flags DigitalChannel: u8 {
#[doc = "All flags set to `off`"]
    static DZero = 0,
    static D1 = 1,
    static D2 = 2,
    static D3 = 4,
    static D4 = 8,
    static D5 = 16,
    static D6 = 32,
    static D7 = 64,
    static D8 = 128,
#[doc = "All flags set to `on`"]
    static DAll = 255
  }
)

bitflags!(
#[doc = "
Adresses of the different cards that can be controlled.

See the jumper setting on your card for the correct address.
"]
    flags CardAddress: uint {
#[doc = "Use card `0x5500` (see jumper settings)"]
        static Card1 = 0x5500,
#[doc = "Use card `0x5501` (see jumper settings)"]
        static Card2 = 0x5501,
#[doc = "Use card `0x5502` (see jumper settings)"]
        static Card3 = 0x5502,
#[doc = "Use card `0x5503` (see jumper settings)"]
        static Card4 = 0x5503,
#[doc = "Automatically selects the first card found on the system"]
        static CardAny = 0x0
    }
)

static VendorId: uint = 0x10cfu;

#[deriving(Show)]
enum Packet {
    Reset,
    SetAnalogDigital(u8, u8, u8),
    Status(u8, u8, u8, u8)
}

#[deriving(Default)]
struct State {
    dig: u8,
    ana1: u8,
    ana2: u8
}

/// Object controlling one Vellemann K8055 card.
pub struct K8055 {
    dev: usb::Device,
    hd: Option<usb::DeviceHandle>,
    state: State
}

impl K8055 {
    /// Create a new K8055 instance with the first card found on the system.
    ///
    /// May return `None` if no card was found connected to the system.
    pub fn new() -> Option<K8055> {
        K8055::new_addr(CardAny)
    }

    /// Create a new K8055 instance with a specific card address.
    ///
    /// See the hardware jumpers on the card for your card's address. May return `None` if no card
    /// with the address `addr` can be found connected to the system.
    pub fn new_addr(addr: CardAddress) -> Option<K8055> {
        let c = usb::Context::new();
        let d = if addr == CardAny {
            K8055::find_any_k8055(&c)
        } else {
            c.find_by_vid_pid(VendorId, addr.bits)
        };

        if d.is_some() {
            return Some(K8055{ dev: d.unwrap(), hd: None, state: Default::default() })
        } else {
            return None
        }
    }

    /// Open the device for starting IO operations.
    ///
    /// Returns `true` if the device was successfully opened or is already open. Returns `false`
    /// if the device can't be opened.
    pub fn open(&mut self) -> bool {
      // device already open
      if self.hd.is_some() { return true }
      match self.dev.open() {
          Ok(h) => {
              self.hd = Some(h);
              return true
          }
          Err(_) => return false
      }
    }

    /// Set all analog and digital values to zero.
    pub fn reset(&mut self) -> bool {
        self.write(&SetAnalogDigital(0u8, 0u8, 0u8))
    }

// digital

    /// Write the digital value `d` to the outports.
    ///
    /// Leaves the analog values untouched. Returns `false` on failure.
    pub fn write_digital_out(&mut self, d: DigitalChannel) -> bool {
        let p = &SetAnalogDigital(d.bits, self.state.ana1, self.state.ana2);
        self.write(p)
    }

    /// Write the masked digital value `d` to the outports.
    ///
    /// Masks `d` with `mask` to only affect bits which are `on` in the mask.
    /// Leaves the analog values untouched. Returns `false` on failure.
    pub fn write_digital_out_mask(&mut self, d: DigitalChannel, mask: DigitalChannel) -> bool {
        self.write_digital_out(d & mask)
    }

    /// Return the bits that are currently set on the digital out channel.
    pub fn get_digital_out(&mut self) -> DigitalChannel {
        DigitalChannel::from_bits(self.state.dig).unwrap()
    }

    /// Return the bits that are currently set on the digital out channel, masked with `mask`.
    pub fn get_digital_out_mask(&mut self, d: DigitalChannel) -> DigitalChannel {
        DigitalChannel::from_bits(self.state.dig).unwrap() & d
    }

    /// Read the digital in channel.
    ///
    /// Returns `None` on failure
    pub fn read_digital_in(&mut self) -> Option<DigitalChannel> {
        match self.read() {
            Some(Status(dig, _, _, _)) => Some(DigitalChannel::from_bits(dig).unwrap()),
            _ => None
        }
    }

    /// Read the digital in channel masked with `mask`.
    ///
    /// Returns `None` on failure
    pub fn read_digital_in_mask(&mut self, mask: DigitalChannel) -> Option<DigitalChannel> {
        match self.read_digital_in() {
            Some(c) => Some(c & mask),
            _ => None
        }
    }

// analog
    /// Write the analog value `a` to the given outport.
    ///
    /// Leaves the digital values untouched. Returns `false` on failure.
    pub fn write_analog_out(&mut self, a: AnalogChannel) -> bool {
      let p = match a {
          A1(v) => SetAnalogDigital(self.state.dig, v, self.state.ana2),
          A2(v) => SetAnalogDigital(self.state.dig, self.state.ana1, v)
      };
      self.write(&p)
    }

    /// Return the analog channel 1 out value
    pub fn get_analog_out1(&mut self) -> AnalogChannel {
        A1(self.state.ana1)
    }

    /// Return the analog channel 2 out value
    pub fn get_analog_out2(&mut self) -> AnalogChannel {
        A2(self.state.ana2)
    }

    /// Read the analog channel 1 input value.
    ///
    /// Returns `None` on failure.
    pub fn read_analog_in1(&mut self) -> Option<AnalogChannel> {
        match self.read() {
            Some(Status(_, _, a1, _)) => Some(A1(a1)),
            _ => None
        }
    }

    /// Read the analog channel 2 input value.
    ///
    /// Returns `None` on failure.
    pub fn read_analog_in2(&mut self) -> Option<AnalogChannel> {
        match self.read() {
            Some(Status(_, _, _, a2)) => Some(A2(a2)),
            _ => None
        }
    }

// private
    fn find_any_k8055(c: &usb::Context) -> Option<usb::Device> {
        for pid in range_inclusive(Card1.bits, Card4.bits) {
          let d = c.find_by_vid_pid(VendorId, pid);
          if d.is_some() { return d }
        }
        None
    }

    fn write(&mut self, p: &Packet) -> bool {
        match self.hd {
          Some(ref hd) => {
              K8055::detach_and_claim(hd);
              let data = match K8055::encode(p) {
                  Some(d) => d,
                  None => return false
              };

              match hd.write(0x1, libusb::LIBUSB_TRANSFER_TYPE_INTERRUPT, data) {
                  Ok(_) => {
                      // update the internal state on output changes
                      match *p {
                          SetAnalogDigital(d, a1, a2) => {
                              self.state = State{dig: d, ana1: a1, ana2: a2};
                          }
                          _ => ()
                      }
                      return true
                  }
                  Err(_) => return false
              }
          }
          None => return false
        }
    }

    fn read(&mut self) -> Option<Packet> {
        match self.hd {
          Some(ref hd) => {
            K8055::detach_and_claim(hd);
            match hd.read(0x81, libusb::LIBUSB_TRANSFER_TYPE_INTERRUPT, 8) {
              Ok(data) => K8055::decode(data.as_slice()),
              Err(_) => None
            }
          }
          None => None
        }
    }

    fn encode(p: &Packet) -> Option<[u8, ..8]> {
      match *p {
          Reset => Some([0u8, ..8]),
          SetAnalogDigital(dig, ana1, ana2) => Some([5u8, dig, ana1, ana2,
                                                     0u8, 0u8, 0u8, 0u8]),
          _ => None
      }
    }

    fn decode(d: &[u8]) -> Option<Packet> {
       match d {
          [dig, st, ana1, ana2, _, _, _, _] => Some(Status(dig, st, ana1, ana2)),
          _ => None
       }
    }

    fn detach_and_claim(hd: &usb::DeviceHandle ) {
      unsafe {
        if libusb::libusb_kernel_driver_active(hd.ptr(), 0) == 1 {
          if libusb::libusb_detach_kernel_driver(hd.ptr(), 0) != 0 {
            fail!("Can't detach usb kernel driver");
          }
        }
      }
      hd.claim_interface(0u);
    }

}

impl Show for K8055 {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> {
      write!(f, "K8055( bus: {}, address: {} )", self.dev.bus(), self.dev.address())
    }
}

#[test()]
fn find_and_open() {
  let k = K8055::new();
  assert!(k.is_some());
  let mut k = k.unwrap();
  assert!(k.open());
  assert!(K8055::new_addr(Card2).is_none());
  assert!(K8055::new_addr(Card3).is_none());
  assert!(K8055::new_addr(Card4).is_none());
}

#[test()]
fn write_and_read_digital() {
  use std::io::timer::sleep;

  let k = K8055::new();
  assert!(k.is_some());
  let mut k = k.unwrap();
  assert!(k.open());
  assert!(k.get_digital_out() == DZero);
  for i in range(0u, 8) {
    assert!(k.write_digital_out(DigitalChannel::from_bits(1u8<<i).unwrap()));
    assert!(k.get_digital_out() == DigitalChannel::from_bits(1u8<<i).unwrap());
    sleep(100);
  }
  assert!(k.reset());
  assert!(k.get_digital_out() == DZero);

  assert!(k.write_digital_out_mask(D1 | D2 | D3, D2));
  assert!(k.get_digital_out() == D2);
  assert!(k.reset());
  sleep(1000);
}

#[test()]
fn write_and_read_analog() {
  use std::io::timer::sleep;

  let k = K8055::new();
  assert!(k.is_some());
  let mut k = k.unwrap();
  assert!(k.open());
  assert!(k.get_analog_out1() == A1(0u8));
  assert!(k.get_analog_out2() == A2(0u8));
  for i in range(0u8, 255) {
    assert!(k.write_analog_out(A1(i)));
    assert!(k.write_analog_out(A2(255-i)));
    sleep(10);
  }
  assert!(k.reset());
  sleep(1000);
}

<commit_msg>Fix compiler style warnings<commit_after>//  K8055.rs is a library for controlling the Vellemann K8055 USB IO card from rust.
//  Copyright (C) 2014 Falco Hirschenberger <falco.hirschenberger@gmail.com>
//
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License along
//  with this program; if not, write to the Free Software Foundation, Inc.,
//  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

//! Driver library for controlling the *Vellemann K8055(N)* USB digital and analog IO-cards.
//!
//! See the Vellemann [Homepage](http://www.velleman.eu/products/view/?id=351346) for the
//! hardware specification.

#![crate_type = "lib"]
extern crate libc;
extern crate usb;
extern crate serialize;

use std::iter::range_inclusive;
use std::fmt::{Show, Formatter, FormatError};
use std::default::Default;
use usb::libusb;

/// Analog values in the range (0-255).
#[deriving(PartialEq, PartialOrd, Show)]
pub enum AnalogChannel {
      A1(u8),
      A2(u8)
}

bitflags!(
#[doc = "
The digital channel values.

Can be combined with bitoperations.

    let dc = k8055::D1 & k8055::D2 & k8055::D3;

See the bitflags documentation for more information.
"]
  flags DigitalChannel: u8 {
#[doc = "All flags set to `off`"]
    static DZERO = 0,
    static D1 = 1,
    static D2 = 2,
    static D3 = 4,
    static D4 = 8,
    static D5 = 16,
    static D6 = 32,
    static D7 = 64,
    static D8 = 128,
#[doc = "All flags set to `on`"]
    static DALL = 255
  }
)

bitflags!(
#[doc = "
Adresses of the different cards that can be controlled.

See the jumper setting on your card for the correct address.
"]
    flags CardAddress: uint {
#[doc = "Use card `0x5500` (see jumper settings)"]
        static CARD_1 = 0x5500,
#[doc = "Use card `0x5501` (see jumper settings)"]
        static CARD_2 = 0x5501,
#[doc = "Use card `0x5502` (see jumper settings)"]
        static CARD_3 = 0x5502,
#[doc = "Use card `0x5503` (see jumper settings)"]
        static CARD_4 = 0x5503,
#[doc = "Automatically selects the first card found on the system"]
        static CARD_ANY = 0x0
    }
)

static VENDOR_ID: uint = 0x10cfu;

#[deriving(Show)]
enum Packet {
    Reset,
    SetAnalogDigital(u8, u8, u8),
    Status(u8, u8, u8, u8)
}

#[deriving(Default)]
struct State {
    dig: u8,
    ana1: u8,
    ana2: u8
}

/// Object controlling one Vellemann K8055 card.
pub struct K8055 {
    dev: usb::Device,
    hd: Option<usb::DeviceHandle>,
    state: State
}

impl K8055 {
    /// Create a new K8055 instance with the first card found on the system.
    ///
    /// May return `None` if no card was found connected to the system.
    pub fn new() -> Option<K8055> {
        K8055::new_addr(CARD_ANY)
    }

    /// Create a new K8055 instance with a specific card address.
    ///
    /// See the hardware jumpers on the card for your card's address. May return `None` if no card
    /// with the address `addr` can be found connected to the system.
    pub fn new_addr(addr: CardAddress) -> Option<K8055> {
        let c = usb::Context::new();
        let d = if addr == CARD_ANY {
            K8055::find_any_k8055(&c)
        } else {
            c.find_by_vid_pid(VENDOR_ID, addr.bits)
        };

        if d.is_some() {
            return Some(K8055{ dev: d.unwrap(), hd: None, state: Default::default() })
        } else {
            return None
        }
    }

    /// Open the device for starting IO operations.
    ///
    /// Returns `true` if the device was successfully opened or is already open. Returns `false`
    /// if the device can't be opened.
    pub fn open(&mut self) -> bool {
      // device already open
      if self.hd.is_some() { return true }
      match self.dev.open() {
          Ok(h) => {
              self.hd = Some(h);
              return true
          }
          Err(_) => return false
      }
    }

    /// Set all analog and digital values to zero.
    pub fn reset(&mut self) -> bool {
        self.write(&SetAnalogDigital(0u8, 0u8, 0u8))
    }

// digital

    /// Write the digital value `d` to the outports.
    ///
    /// Leaves the analog values untouched. Returns `false` on failure.
    pub fn write_digital_out(&mut self, d: DigitalChannel) -> bool {
        let p = &SetAnalogDigital(d.bits, self.state.ana1, self.state.ana2);
        self.write(p)
    }

    /// Write the masked digital value `d` to the outports.
    ///
    /// Masks `d` with `mask` to only affect bits which are `on` in the mask.
    /// Leaves the analog values untouched. Returns `false` on failure.
    pub fn write_digital_out_mask(&mut self, d: DigitalChannel, mask: DigitalChannel) -> bool {
        self.write_digital_out(d & mask)
    }

    /// Return the bits that are currently set on the digital out channel.
    pub fn get_digital_out(&mut self) -> DigitalChannel {
        DigitalChannel::from_bits(self.state.dig).unwrap()
    }

    /// Return the bits that are currently set on the digital out channel, masked with `mask`.
    pub fn get_digital_out_mask(&mut self, d: DigitalChannel) -> DigitalChannel {
        DigitalChannel::from_bits(self.state.dig).unwrap() & d
    }

    /// Read the digital in channel.
    ///
    /// Returns `None` on failure
    pub fn read_digital_in(&mut self) -> Option<DigitalChannel> {
        match self.read() {
            Some(Status(dig, _, _, _)) => Some(DigitalChannel::from_bits(dig).unwrap()),
            _ => None
        }
    }

    /// Read the digital in channel masked with `mask`.
    ///
    /// Returns `None` on failure
    pub fn read_digital_in_mask(&mut self, mask: DigitalChannel) -> Option<DigitalChannel> {
        match self.read_digital_in() {
            Some(c) => Some(c & mask),
            _ => None
        }
    }

// analog
    /// Write the analog value `a` to the given outport.
    ///
    /// Leaves the digital values untouched. Returns `false` on failure.
    pub fn write_analog_out(&mut self, a: AnalogChannel) -> bool {
      let p = match a {
          A1(v) => SetAnalogDigital(self.state.dig, v, self.state.ana2),
          A2(v) => SetAnalogDigital(self.state.dig, self.state.ana1, v)
      };
      self.write(&p)
    }

    /// Return the analog channel 1 out value
    pub fn get_analog_out1(&mut self) -> AnalogChannel {
        A1(self.state.ana1)
    }

    /// Return the analog channel 2 out value
    pub fn get_analog_out2(&mut self) -> AnalogChannel {
        A2(self.state.ana2)
    }

    /// Read the analog channel 1 input value.
    ///
    /// Returns `None` on failure.
    pub fn read_analog_in1(&mut self) -> Option<AnalogChannel> {
        match self.read() {
            Some(Status(_, _, a1, _)) => Some(A1(a1)),
            _ => None
        }
    }

    /// Read the analog channel 2 input value.
    ///
    /// Returns `None` on failure.
    pub fn read_analog_in2(&mut self) -> Option<AnalogChannel> {
        match self.read() {
            Some(Status(_, _, _, a2)) => Some(A2(a2)),
            _ => None
        }
    }

// private
    fn find_any_k8055(c: &usb::Context) -> Option<usb::Device> {
        for pid in range_inclusive(CARD_1.bits, CARD_4.bits) {
          let d = c.find_by_vid_pid(VENDOR_ID, pid);
          if d.is_some() { return d }
        }
        None
    }

    fn write(&mut self, p: &Packet) -> bool {
        match self.hd {
          Some(ref hd) => {
              K8055::detach_and_claim(hd);
              let data = match K8055::encode(p) {
                  Some(d) => d,
                  None => return false
              };

              match hd.write(0x1, libusb::LIBUSB_TRANSFER_TYPE_INTERRUPT, data) {
                  Ok(_) => {
                      // update the internal state on output changes
                      match *p {
                          SetAnalogDigital(d, a1, a2) => {
                              self.state = State{dig: d, ana1: a1, ana2: a2};
                          }
                          _ => ()
                      }
                      return true
                  }
                  Err(_) => return false
              }
          }
          None => return false
        }
    }

    fn read(&mut self) -> Option<Packet> {
        match self.hd {
          Some(ref hd) => {
            K8055::detach_and_claim(hd);
            match hd.read(0x81, libusb::LIBUSB_TRANSFER_TYPE_INTERRUPT, 8) {
              Ok(data) => K8055::decode(data.as_slice()),
              Err(_) => None
            }
          }
          None => None
        }
    }

    fn encode(p: &Packet) -> Option<[u8, ..8]> {
      match *p {
          Reset => Some([0u8, ..8]),
          SetAnalogDigital(dig, ana1, ana2) => Some([5u8, dig, ana1, ana2,
                                                     0u8, 0u8, 0u8, 0u8]),
          _ => None
      }
    }

    fn decode(d: &[u8]) -> Option<Packet> {
       match d {
          [dig, st, ana1, ana2, _, _, _, _] => Some(Status(dig, st, ana1, ana2)),
          _ => None
       }
    }

    fn detach_and_claim(hd: &usb::DeviceHandle ) {
      unsafe {
        if libusb::libusb_kernel_driver_active(hd.ptr(), 0) == 1 {
          if libusb::libusb_detach_kernel_driver(hd.ptr(), 0) != 0 {
            fail!("Can't detach usb kernel driver");
          }
        }
      }
      hd.claim_interface(0u);
    }

}

impl Show for K8055 {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> {
      write!(f, "K8055( bus: {}, address: {} )", self.dev.bus(), self.dev.address())
    }
}

#[test()]
fn find_and_open() {
  let k = K8055::new();
  assert!(k.is_some());
  let mut k = k.unwrap();
  assert!(k.open());
  assert!(K8055::new_addr(CARD_2).is_none());
  assert!(K8055::new_addr(CARD_3).is_none());
  assert!(K8055::new_addr(CARD_4).is_none());
}

#[test()]
fn write_and_read_digital() {
  use std::io::timer::sleep;

  let k = K8055::new();
  assert!(k.is_some());
  let mut k = k.unwrap();
  assert!(k.open());
  assert!(k.get_digital_out() == DZERO);
  for i in range(0u, 8) {
    assert!(k.write_digital_out(DigitalChannel::from_bits(1u8<<i).unwrap()));
    assert!(k.get_digital_out() == DigitalChannel::from_bits(1u8<<i).unwrap());
    sleep(100);
  }
  assert!(k.reset());
  assert!(k.get_digital_out() == DZERO);

  assert!(k.write_digital_out_mask(D1 | D2 | D3, D2));
  assert!(k.get_digital_out() == D2);
  assert!(k.reset());
  sleep(1000);
}

#[test()]
fn write_and_read_analog() {
  use std::io::timer::sleep;

  let k = K8055::new();
  assert!(k.is_some());
  let mut k = k.unwrap();
  assert!(k.open());
  assert!(k.get_analog_out1() == A1(0u8));
  assert!(k.get_analog_out2() == A2(0u8));
  for i in range(0u8, 255) {
    assert!(k.write_analog_out(A1(i)));
    assert!(k.write_analog_out(A2(255-i)));
    sleep(10);
  }
  assert!(k.reset());
  sleep(1000);
}
<|endoftext|>


<commit_before>use std::str::CharIndices;
use tokens::Token;
use itertools;
use itertools::MultiPeek;

#[inline]
fn is_id_start(ch: char) -> bool {
    ch == '_' || ch.is_ascii_alphabetic()
}

#[inline]
fn is_id_continue(ch: char) -> bool {
    ch == '_' || ch.is_ascii_digit()
}

pub type SpanResult<'input> = Result<(usize, Token<'input>, usize), String>;

pub struct Lexer<'input> {
    source: &'input str,
    chars: MultiPeek<CharIndices<'input>>,
}

impl<'input> Lexer<'input> {
    pub fn new(source: &'input str) -> Lexer<'input> {
        Lexer {
            source,
            chars: itertools::multipeek(source.char_indices()),
        }
    }

    fn skip_to_line_end(&mut self) {
        while let Some(&(_, ch)) = self.chars.peek() {
            if ch != '\n' {
                self.chars.next();
            } else {
                break;
            }
        }
    }

    fn read_string(&mut self, pos: usize) -> SpanResult<'input> {
        let mut end = pos;

        while let Some((i, ch)) = self.chars.next() {
            if ch == '"' {
                return Ok((pos, Token::String(&self.source[pos + 1..end + 1]), end + 1));
            } else {
                end = i;
            }
        }

        Err(format!("Unterminated string"))
    }

    fn read_number(&mut self, pos: usize) -> SpanResult<'input> {
        let mut end = pos;
        let mut consumed_dot = false;

        while let Some(&(i, ch)) = self.chars.peek() {
            match ch {
                // If we encounter a dot, we need to do an extra character of
                // lookahead to check whether it's a decimal or a field
                // access
                // TODO: This code could almost certainly be cleaner
                '.' if !consumed_dot => match self.chars.peek() {
                    Some(&(_, next_ch)) if next_ch.is_ascii_digit() => {
                        end = i;
                        consumed_dot = true;
                        self.chars.next();
                    }
                    _ => {
                        break;
                    }
                },
                ch if ch.is_ascii_digit() => {
                    end = i;
                    self.chars.next();
                }
                _ => {
                    break;
                }
            }
        }

        Ok((
            pos,
            Token::Number(
                self.source[pos..end + 1]
                    .parse()
                    .expect("unparsable number"),
            ),
            end,
        ))
    }

    fn read_identifier(&mut self, pos: usize) -> SpanResult<'input> {
        let mut end = pos;

        while let Some(&(i, ch)) = self.chars.peek() {
            if is_id_start(ch) || is_id_continue(ch) {
                end = i;
                self.chars.next();
            } else {
                break;
            }
        }

        match &self.source[pos..end + 1] {
            "and" => Ok((pos, Token::And, end)),
            "else" => Ok((pos, Token::Else, end)),
            "false" => Ok((pos, Token::False, end)),
            "fn" => Ok((pos, Token::Fn, end)),
            "for" => Ok((pos, Token::For, end)),
            "if" => Ok((pos, Token::If, end)),
            "nil" => Ok((pos, Token::Nil, end)),
            "or" => Ok((pos, Token::Or, end)),
            "print" => Ok((pos, Token::Print, end)),
            "return" => Ok((pos, Token::Return, end)),
            "this" => Ok((pos, Token::This, end)),
            "true" => Ok((pos, Token::True, end)),
            "let" => Ok((pos, Token::Let, end)),
            "while" => Ok((pos, Token::While, end)),
            id => Ok((pos, Token::Identifier(id), end)),
        }
    }
}

impl<'input> Iterator for Lexer<'input> {
    type Item = SpanResult<'input>;

    fn next(&mut self) -> Option<SpanResult<'input>> {
        while let Some((i, ch)) = self.chars.next() {
            return match ch {
                '{' => Some(Ok((i, Token::OpenBrace, i + 1))),
                '}' => Some(Ok((i, Token::CloseBrace, i + 1))),
                '(' => Some(Ok((i, Token::OpenParen, i + 1))),
                ')' => Some(Ok((i, Token::CloseParen, i + 1))),
                '[' => Some(Ok((i, Token::OpenBracket, i + 1))),
                ']' => Some(Ok((i, Token::CloseBracket, i + 1))),
                ',' => Some(Ok((i, Token::Comma, i + 1))),
                '.' => Some(Ok((i, Token::Dot, i + 1))),
                '+' => Some(Ok((i, Token::Plus, i + 1))),
                '-' => Some(Ok((i, Token::Minus, i + 1))),
                '*' => Some(Ok((i, Token::Star, i + 1))),

                '/' => {
                    if let Some(&(_, '/')) = self.chars.peek() {
                        self.skip_to_line_end();
                        continue;
                    } else {
                        Some(Ok((i, Token::Slash, i + 1)))
                    }
                }

                '!' => {
                    if let Some(&(_, '=')) = self.chars.peek() {
                        self.chars.next();
                        Some(Ok((i, Token::NotEqual, i + 2)))
                    } else {
                        Some(Ok((i, Token::Not, i + 1)))
                    }
                }

                '=' => {
                    if let Some(&(_, '=')) = self.chars.peek() {
                        self.chars.next();
                        Some(Ok((i, Token::EqualEqual, i + 2)))
                    } else {
                        Some(Ok((i, Token::Equal, i + 1)))
                    }
                }

                '>' => {
                    if let Some(&(_, '=')) = self.chars.peek() {
                        self.chars.next();
                        Some(Ok((i, Token::GreaterEqual, i + 2)))
                    } else {
                        Some(Ok((i, Token::Greater, i + 1)))
                    }
                }

                '<' => {
                    if let Some(&(_, '=')) = self.chars.peek() {
                        self.chars.next();
                        Some(Ok((i, Token::LessEqual, i + 2)))
                    } else {
                        Some(Ok((i, Token::Less, i + 1)))
                    }
                }

                '"' => Some(self.read_string(i)),
                '\n' => Some(Ok((i, Token::NewLine, i + 1))),

                ch if is_id_start(ch) => Some(self.read_identifier(i)),
                ch if ch.is_ascii_digit() => Some(self.read_number(i)),
                ch if ch.is_whitespace() => continue,

                ch => Some(Err(format!("Unexpected token: {}", ch))),
            };
        }

        None
    }
}

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

    fn lex(source: &str, expected: Vec<Token>) {
        let mut lexer = Lexer::new(source);

        let mut actual_len = 0;
        let expected_len = expected.len();

        for (expected, actual) in expected.into_iter().zip(lexer.by_ref()) {
            actual_len += 1;
            let actual = actual.unwrap();
            assert_eq!(expected, actual);
        }

        assert_eq!(expected_len, actual_len);
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn delimiters() {
        lex(
            "{} [] ()",
            vec![
                Token::OpenDelim(DelimToken::Brace),
                Token::CloseDelim(DelimToken::Brace),
                Token::OpenDelim(DelimToken::Bracket),
                Token::CloseDelim(DelimToken::Bracket),
                Token::OpenDelim(DelimToken::Paren),
                Token::CloseDelim(DelimToken::Paren),
            ],
        );
    }

    #[test]
    fn operators() {
        lex(
            ", . + - * / = == ! != > >= < <=",
            vec![
                Token::Comma,
                Token::Dot,
                Token::Plus,
                Token::Minus,
                Token::Star,
                Token::Slash,
                Token::Equal,
                Token::EqualEqual,
                Token::Not,
                Token::NotEqual,
                Token::Greater,
                Token::GreaterEqual,
                Token::Less,
                Token::LessEqual,
            ],
        );
    }

    #[test]
    fn line_comment() {
        lex(
            "123 // comment\n 123",
            vec![Token::Number(123.0), Token::NewLine, Token::Number(123.0)],
        );
    }

    #[test]
    fn string() {
        lex("\"hello, world\"", vec![Token::String("hello, world")]);
    }

    #[test]
    fn integer() {
        lex("123", vec![Token::Number(123.0)]);
    }

    #[test]
    fn decimal() {
        lex("123.45", vec![Token::Number(123.45)]);
    }

    #[test]
    fn number_field_access() {
        lex(
            "123.prop",
            vec![Token::Number(123.0), Token::Dot, Token::Identifier("prop")],
        );
    }

    #[test]
    fn identifiers() {
        lex("id", vec![Token::Identifier("id")]);
        lex("_id", vec![Token::Identifier("_id")]);
        lex("id123", vec![Token::Identifier("id123")]);
    }

    #[test]
    fn keywords() {
        lex("and", vec![Token::And]);
        lex("else", vec![Token::Else]);
        lex("false", vec![Token::False]);
        lex("fn", vec![Token::Fn]);
        lex("for", vec![Token::For]);
        lex("if", vec![Token::If]);
        lex("nil", vec![Token::Nil]);
        lex("or", vec![Token::Or]);
        lex("print", vec![Token::Print]);
        lex("return", vec![Token::Return]);
        lex("this", vec![Token::This]);
        lex("true", vec![Token::True]);
        lex("let", vec![Token::Let]);
        lex("while", vec![Token::While]);
    }
}
<commit_msg>Fix lexer tests<commit_after>use std::str::CharIndices;
use tokens::Token;
use itertools;
use itertools::MultiPeek;

#[inline]
fn is_id_start(ch: char) -> bool {
    ch == '_' || ch.is_ascii_alphabetic()
}

#[inline]
fn is_id_continue(ch: char) -> bool {
    ch == '_' || ch.is_ascii_digit()
}

pub type SpanResult<'input> = Result<(usize, Token<'input>, usize), String>;

pub struct Lexer<'input> {
    source: &'input str,
    chars: MultiPeek<CharIndices<'input>>,
}

impl<'input> Lexer<'input> {
    pub fn new(source: &'input str) -> Lexer<'input> {
        Lexer {
            source,
            chars: itertools::multipeek(source.char_indices()),
        }
    }

    fn skip_to_line_end(&mut self) {
        while let Some(&(_, ch)) = self.chars.peek() {
            if ch != '\n' {
                self.chars.next();
            } else {
                break;
            }
        }
    }

    fn read_string(&mut self, pos: usize) -> SpanResult<'input> {
        let mut end = pos;

        while let Some((i, ch)) = self.chars.next() {
            if ch == '"' {
                return Ok((pos, Token::String(&self.source[pos + 1..end + 1]), end + 1));
            } else {
                end = i;
            }
        }

        Err(format!("Unterminated string"))
    }

    fn read_number(&mut self, pos: usize) -> SpanResult<'input> {
        let mut end = pos;
        let mut consumed_dot = false;

        while let Some(&(i, ch)) = self.chars.peek() {
            match ch {
                // If we encounter a dot, we need to do an extra character of
                // lookahead to check whether it's a decimal or a field
                // access
                // TODO: This code could almost certainly be cleaner
                '.' if !consumed_dot => match self.chars.peek() {
                    Some(&(_, next_ch)) if next_ch.is_ascii_digit() => {
                        end = i;
                        consumed_dot = true;
                        self.chars.next();
                    }
                    _ => {
                        break;
                    }
                },
                ch if ch.is_ascii_digit() => {
                    end = i;
                    self.chars.next();
                }
                _ => {
                    break;
                }
            }
        }

        Ok((
            pos,
            Token::Number(
                self.source[pos..end + 1]
                    .parse()
                    .expect("unparsable number"),
            ),
            end,
        ))
    }

    fn read_identifier(&mut self, pos: usize) -> SpanResult<'input> {
        let mut end = pos;

        while let Some(&(i, ch)) = self.chars.peek() {
            if is_id_start(ch) || is_id_continue(ch) {
                end = i;
                self.chars.next();
            } else {
                break;
            }
        }

        match &self.source[pos..end + 1] {
            "and" => Ok((pos, Token::And, end)),
            "else" => Ok((pos, Token::Else, end)),
            "false" => Ok((pos, Token::False, end)),
            "fn" => Ok((pos, Token::Fn, end)),
            "for" => Ok((pos, Token::For, end)),
            "if" => Ok((pos, Token::If, end)),
            "nil" => Ok((pos, Token::Nil, end)),
            "or" => Ok((pos, Token::Or, end)),
            "print" => Ok((pos, Token::Print, end)),
            "return" => Ok((pos, Token::Return, end)),
            "this" => Ok((pos, Token::This, end)),
            "true" => Ok((pos, Token::True, end)),
            "let" => Ok((pos, Token::Let, end)),
            "while" => Ok((pos, Token::While, end)),
            id => Ok((pos, Token::Identifier(id), end)),
        }
    }
}

impl<'input> Iterator for Lexer<'input> {
    type Item = SpanResult<'input>;

    fn next(&mut self) -> Option<SpanResult<'input>> {
        while let Some((i, ch)) = self.chars.next() {
            return match ch {
                '{' => Some(Ok((i, Token::OpenBrace, i + 1))),
                '}' => Some(Ok((i, Token::CloseBrace, i + 1))),
                '(' => Some(Ok((i, Token::OpenParen, i + 1))),
                ')' => Some(Ok((i, Token::CloseParen, i + 1))),
                '[' => Some(Ok((i, Token::OpenBracket, i + 1))),
                ']' => Some(Ok((i, Token::CloseBracket, i + 1))),
                ',' => Some(Ok((i, Token::Comma, i + 1))),
                '.' => Some(Ok((i, Token::Dot, i + 1))),
                '+' => Some(Ok((i, Token::Plus, i + 1))),
                '-' => Some(Ok((i, Token::Minus, i + 1))),
                '*' => Some(Ok((i, Token::Star, i + 1))),

                '/' => {
                    if let Some(&(_, '/')) = self.chars.peek() {
                        self.skip_to_line_end();
                        continue;
                    } else {
                        Some(Ok((i, Token::Slash, i + 1)))
                    }
                }

                '!' => {
                    if let Some(&(_, '=')) = self.chars.peek() {
                        self.chars.next();
                        Some(Ok((i, Token::NotEqual, i + 2)))
                    } else {
                        Some(Ok((i, Token::Not, i + 1)))
                    }
                }

                '=' => {
                    if let Some(&(_, '=')) = self.chars.peek() {
                        self.chars.next();
                        Some(Ok((i, Token::EqualEqual, i + 2)))
                    } else {
                        Some(Ok((i, Token::Equal, i + 1)))
                    }
                }

                '>' => {
                    if let Some(&(_, '=')) = self.chars.peek() {
                        self.chars.next();
                        Some(Ok((i, Token::GreaterEqual, i + 2)))
                    } else {
                        Some(Ok((i, Token::Greater, i + 1)))
                    }
                }

                '<' => {
                    if let Some(&(_, '=')) = self.chars.peek() {
                        self.chars.next();
                        Some(Ok((i, Token::LessEqual, i + 2)))
                    } else {
                        Some(Ok((i, Token::Less, i + 1)))
                    }
                }

                '"' => Some(self.read_string(i)),
                '\n' => Some(Ok((i, Token::NewLine, i + 1))),

                ch if is_id_start(ch) => Some(self.read_identifier(i)),
                ch if ch.is_ascii_digit() => Some(self.read_number(i)),
                ch if ch.is_whitespace() => continue,

                ch => Some(Err(format!("Unexpected token: {}", ch))),
            };
        }

        None
    }
}

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

    fn lex(source: &str, expected: Vec<(usize, Token, usize)>) {
        let mut lexer = Lexer::new(source);

        let mut actual_len = 0;
        let expected_len = expected.len();

        for (expected, actual) in expected.into_iter().zip(lexer.by_ref()) {
            actual_len += 1;
            let actual = actual.unwrap();
            assert_eq!(expected, actual);
        }

        assert_eq!(expected_len, actual_len);
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn delimiters() {
        lex(
            "{} [] ()",
            vec![
                (0, Token::OpenBrace, 1),
                (1, Token::CloseBrace, 2),
                (3, Token::OpenBracket, 4),
                (4, Token::CloseBracket, 5),
                (6, Token::OpenParen, 7),
                (7, Token::CloseParen, 8),
            ],
        );
    }

    #[test]
    fn operators() {
        lex(
            ", . + - * / = == ! != > >= < <=",
            vec![
                (0, Token::Comma, 1),
                (2, Token::Dot, 3),
                (4, Token::Plus, 5),
                (6, Token::Minus, 7),
                (8, Token::Star, 9),
                (10, Token::Slash, 11),
                (12, Token::Equal, 13),
                (14, Token::EqualEqual, 16),
                (17, Token::Not, 18),
                (19, Token::NotEqual, 21),
                (22, Token::Greater, 23),
                (24, Token::GreaterEqual, 26),
                (27, Token::Less, 28),
                (29, Token::LessEqual, 31),
            ],
        );
    }

    #[test]
    fn line_comment() {
        lex(
            "123 // comment\n 123",
            vec![
                (0, Token::Number(123.0), 2),
                (14, Token::NewLine, 15),
                (16, Token::Number(123.0), 18),
            ],
        );
    }

    #[test]
    fn string() {
        lex(
            "\"hello, world\"",
            vec![(0, Token::String("hello, world"), 13)],
        );
    }

    #[test]
    fn integer() {
        lex("123", vec![(0, Token::Number(123.0), 2)]);
    }

    #[test]
    fn decimal() {
        lex("123.45", vec![(0, Token::Number(123.45), 5)]);
    }

    #[test]
    fn number_field_access() {
        lex(
            "123.prop",
            vec![
                (0, Token::Number(123.0), 2),
                (3, Token::Dot, 4),
                (4, Token::Identifier("prop"), 7),
            ],
        );
    }

    #[test]
    fn identifiers() {
        lex("id", vec![(0, Token::Identifier("id"), 1)]);
        lex("_id", vec![(0, Token::Identifier("_id"), 2)]);
        lex("id123", vec![(0, Token::Identifier("id123"), 4)]);
    }

    #[test]
    fn keywords() {
        lex("and", vec![(0, Token::And, 2)]);
        lex("else", vec![(0, Token::Else, 3)]);
        lex("false", vec![(0, Token::False, 4)]);
        lex("fn", vec![(0, Token::Fn, 1)]);
        lex("for", vec![(0, Token::For, 2)]);
        lex("if", vec![(0, Token::If, 1)]);
        lex("nil", vec![(0, Token::Nil, 2)]);
        lex("or", vec![(0, Token::Or, 1)]);
        lex("print", vec![(0, Token::Print, 4)]);
        lex("return", vec![(0, Token::Return, 5)]);
        lex("this", vec![(0, Token::This, 3)]);
        lex("true", vec![(0, Token::True, 3)]);
        lex("let", vec![(0, Token::Let, 2)]);
        lex("while", vec![(0, Token::While, 4)]);
    }
}
<|endoftext|>


<commit_before>extern crate bf;
extern crate clap;

use std::io::{self, Read, Write};
use std::fs::File;
use std::process::exit;

use clap::{Arg, App};

use bf::state;
use bf::ast;
use bf::rle_ast;
use bf::flat;
use bf::interpreter::Interpretable;

#[derive(Debug, Clone)]
struct Options {
    program_text:  Vec<u8>,
    memory_size:   Option<usize>,
    compiler_pass: Pass,
}

#[derive(Debug, Clone, Copy)]
enum Pass {
    Ast,
    Rle,
    Flat,
}

fn main() {
    // Process command-line options:
    let options = get_options();

    // Parse the program to AST:
    let program = parse(&options);

    match options.compiler_pass {
        Pass::Ast => {
            interpret(&*program, &options);
        }

        Pass::Rle => {
            let program = rle_ast::compiler::compile(&program);
            interpret(&*program, &options);
        }

        Pass::Flat => {
            let program = rle_ast::compiler::compile(&program);
            let program = flat::compiler::compile(&program);
            interpret(&*program, &options);
        }

    }
}

fn parse(options: &Options) -> ast::Program {
    ast::parser::parse_program(&options.program_text)
        .unwrap_or_else(|e| error_exit(2, format!("Syntax error: {:?}.", e)))
}

fn interpret<P: Interpretable + ?Sized>(program: &P, options: &Options) {
    let state = options.memory_size.map(state::State::with_capacity);
    program.interpret_stdin(state)
        .unwrap_or_else(|e| error_exit(3, format!("Runtime error: {:?}.", e)))
}

fn get_options() -> Options {
    let mut result = Options {
        program_text:  Vec::new(),
        memory_size:   None,
        compiler_pass: Pass::Flat,
    };

    let matches = build_clap_app().get_matches();

    if let Some(size) = matches.value_of("size") {
        let size = size.parse()
            .unwrap_or_else(|e| error_exit(1, format!("Could not parse memory size: {}", e)));
        result.memory_size = Some(size);
    }

    if matches.is_present("ast") {
        result.compiler_pass = Pass::Ast;
    } else if matches.is_present("rle") {
        result.compiler_pass = Pass::Rle;
    } else if matches.is_present("flat") {
        result.compiler_pass = Pass::Flat;
    }

    if let Some(exprs) = matches.values_of("expr") {
        for e in exprs {
            result.program_text.extend(e.as_bytes());
        }
    } else if let Some(files) = matches.values_of("INPUT") {
        for f in files {
            let mut file = File::open(f)
                .unwrap_or_else(|e| error_exit(1, format!("{}: {}", e, f)));
            file.read_to_end(&mut result.program_text)
                .unwrap_or_else(|e| error_exit(1, format!("{}: {}", e, f)));
        }
    } else {
        error_exit(1, "No program given.".to_owned());
    }

    result
}

fn build_clap_app() -> App<'static, 'static> {
    App::new("bfi")
        .author("Jesse A. Tov <jesse.tov@gmail.com>")
        .about("A Brainfuck interpreter")
        .arg(Arg::with_name("expr")
            .short("e")
            .long("expr")
            .value_name("CODE")
            .help("BF code to execute")
            .multiple(true)
            .takes_value(true)
            .conflicts_with("INPUT"))
        .arg(Arg::with_name("INPUT")
            .help("The source file(s) to interpret")
            .multiple(true)
            .conflicts_with("expr")
            .index(1))
        .arg(Arg::with_name("size")
            .short("s")
            .long("size")
            .help("Memory size in bytes")
            .takes_value(true))
        .arg(Arg::with_name("ast")
            .long("ast")
            .help("Interpret the AST directly")
            .conflicts_with_all(&["flat", "rle"]))
        .arg(Arg::with_name("rle")
            .long("rle")
            .help("Interpret the run-length encoded AST directly")
            .conflicts_with_all(&["ast", "flat"]))
        .arg(Arg::with_name("flat")
            .long("flat")
            .help("Interpret the flattened AST (default)")
            .conflicts_with_all(&["ast", "rle"]))
}

fn error_exit(code: i32, msg: String) -> ! {
    writeln!(io::stderr(), "{}", msg).unwrap();
    exit(code)
}

<commit_msg>Added version.<commit_after>extern crate bf;
extern crate clap;

use std::io::{self, Read, Write};
use std::fs::File;
use std::process::exit;

use clap::{Arg, App};

use bf::state;
use bf::ast;
use bf::rle_ast;
use bf::flat;
use bf::interpreter::Interpretable;

const VERSION: &'static str = "0.1.0";

#[derive(Debug, Clone)]
struct Options {
    program_text:  Vec<u8>,
    memory_size:   Option<usize>,
    compiler_pass: Pass,
}

#[derive(Debug, Clone, Copy)]
enum Pass {
    Ast,
    Rle,
    Flat,
}

fn main() {
    // Process command-line options:
    let options = get_options();

    // Parse the program to AST:
    let program = parse(&options);

    match options.compiler_pass {
        Pass::Ast => {
            interpret(&*program, &options);
        }

        Pass::Rle => {
            let program = rle_ast::compiler::compile(&program);
            interpret(&*program, &options);
        }

        Pass::Flat => {
            let program = rle_ast::compiler::compile(&program);
            let program = flat::compiler::compile(&program);
            interpret(&*program, &options);
        }

    }
}

fn parse(options: &Options) -> ast::Program {
    ast::parser::parse_program(&options.program_text)
        .unwrap_or_else(|e| error_exit(2, format!("Syntax error: {:?}.", e)))
}

fn interpret<P: Interpretable + ?Sized>(program: &P, options: &Options) {
    let state = options.memory_size.map(state::State::with_capacity);
    program.interpret_stdin(state)
        .unwrap_or_else(|e| error_exit(3, format!("Runtime error: {:?}.", e)))
}

fn get_options() -> Options {
    let mut result = Options {
        program_text:  Vec::new(),
        memory_size:   None,
        compiler_pass: Pass::Flat,
    };

    let matches = build_clap_app().get_matches();

    if let Some(size) = matches.value_of("size") {
        let size = size.parse()
            .unwrap_or_else(|e| error_exit(1, format!("Could not parse memory size: {}", e)));
        result.memory_size = Some(size);
    }

    if matches.is_present("ast") {
        result.compiler_pass = Pass::Ast;
    } else if matches.is_present("rle") {
        result.compiler_pass = Pass::Rle;
    } else if matches.is_present("flat") {
        result.compiler_pass = Pass::Flat;
    }

    if let Some(exprs) = matches.values_of("expr") {
        for e in exprs {
            result.program_text.extend(e.as_bytes());
        }
    } else if let Some(files) = matches.values_of("INPUT") {
        for f in files {
            let mut file = File::open(f)
                .unwrap_or_else(|e| error_exit(1, format!("{}: {}", e, f)));
            file.read_to_end(&mut result.program_text)
                .unwrap_or_else(|e| error_exit(1, format!("{}: {}", e, f)));
        }
    } else {
        error_exit(1, "No program given.".to_owned());
    }

    result
}

fn build_clap_app() -> App<'static, 'static> {
    App::new("bfi")
        .version(VERSION)
        .author("Jesse A. Tov <jesse.tov@gmail.com>")
        .about("A Brainfuck interpreter")
        .arg(Arg::with_name("expr")
            .short("e")
            .long("expr")
            .value_name("CODE")
            .help("BF code to execute")
            .multiple(true)
            .takes_value(true)
            .conflicts_with("INPUT"))
        .arg(Arg::with_name("INPUT")
            .help("The source file(s) to interpret")
            .multiple(true)
            .conflicts_with("expr")
            .index(1))
        .arg(Arg::with_name("size")
            .short("s")
            .long("size")
            .value_name("SIZE")
            .help("Memory size in bytes")
            .takes_value(true))
        .arg(Arg::with_name("ast")
            .long("ast")
            .help("Interpret the AST directly")
            .conflicts_with_all(&["flat", "rle"]))
        .arg(Arg::with_name("rle")
            .long("rle")
            .help("Interpret the run-length encoded AST directly")
            .conflicts_with_all(&["ast", "flat"]))
        .arg(Arg::with_name("flat")
            .long("flat")
            .help("Interpret the flattened AST (default)")
            .conflicts_with_all(&["ast", "rle"]))
}

fn error_exit(code: i32, msg: String) -> ! {
    writeln!(io::stderr(), "{}", msg).unwrap();
    exit(code)
}

<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate arg_parser;
extern crate extra;

use std::cell::Cell; // Provide mutable fields in immutable structs
use std::env;
use std::error::Error;
use std::fs;
use std::io::{self, BufReader, Read, Stderr, StdoutLock, Write};
use std::process::exit;
use extra::option::OptionalExt;
use arg_parser::ArgParser;

const MAN_PAGE: &'static str = /* @MANSTART{cat} */ r#"NAME
    cat - concatenate files and print on the standard output

SYNOPSIS
    cat [-h | --help] [-A | --show-all] [-b | --number-nonblank] [-e] [-E | --show-ends]
        [-n | --number] [-s | --squeeze-blank] [-t] [-T] FILES...

DESCRIPTION
    Concatenates all files to the standard output.

    If no file is given, or if FILE is '-', read from standard input.

OPTIONS
    -A
    --show-all
        equivalent to -vET

    -b
    --number-nonblank
        number nonempty output lines, overriding -n

    -e
        equivalent to -vE

    -E
    --show-ends
        display $ at the end of each line

    -n
    --number
        number all output lines

    -s
    --squeeze-blank
        supress repeated empty output lines

    -t
        equivalent to -vT

    -T
    --show_tabs
        display TAB characters as ^I

    -v
    --show-nonprinting
        use caret (^) and M- notation, except for LFD and TAB.

    -h
    --help
        display this help and exit

AUTHOR
    Written by Michael Murphy.
"#; /* @MANEND */

struct Program {
    exit_status:      Cell<i32>,
    number:           bool,
    number_nonblank:  bool,
    show_ends:        bool,
    show_tabs:        bool,
    show_nonprinting: bool,
    squeeze_blank:    bool,
    paths:            Vec<String>,
}

impl Program {
    /// Initialize the program's arguments and flags.
    fn initialize(stdout: &mut StdoutLock, stderr: &mut Stderr) -> Program {
        let mut parser = ArgParser::new(10).
            add_flag(&["A", "show-all"]). //vET
            add_flag(&["b", "number-nonblank"]).
            add_flag(&["e"]). //vE
            add_flag(&["E", "show-ends"]).
            add_flag(&["n", "number"]).
            add_flag(&["s", "squeeze-blank"]).
            add_flag(&["t"]). //vT
            add_flag(&["T", "show-tabs"]).
            add_flag(&["v", "show-nonprinting"]).
            add_flag(&["h", "help"]);
        parser.parse(env::args());

        let mut cat = Program {
            exit_status:      Cell::new(0i32),
            number:           false,
            number_nonblank:  false,
            show_ends:        false,
            show_tabs:        false,
            show_nonprinting: false,
            squeeze_blank:    false,
            paths:            Vec::with_capacity(parser.args.len()),
        };

        if parser.found("help") {
            stdout.write(MAN_PAGE.as_bytes()).try(stderr);
            stdout.flush().try(stderr);
            exit(0);
        }

        if parser.found("show-all") {
            cat.show_nonprinting = true;
            cat.show_ends = true;
            cat.show_tabs = true;
        }

        if parser.found("number") {
            cat.number = true;
            cat.number_nonblank = false;
        }

        if parser.found("number-nonblank") {
            cat.number_nonblank = true;
            cat.number = false;
        }

        if parser.found("show-ends") || parser.found(&'e') {
            cat.show_ends = true;
        }

        if parser.found("squeeze-blank") {
            cat.squeeze_blank = true;
        }

        if parser.found("show-tabs") || parser.found(&'t') {
            cat.show_tabs = true;
        }

        if parser.found("show-nonprinting") || parser.found(&'e') || parser.found(&'t') {
            cat.show_nonprinting = true;
        }

        if !parser.args.is_empty() {
            cat.paths = parser.args;
        }
        cat
    }

    /// Execute the parameters given to the program.
    fn and_execute(&self, stdout: &mut StdoutLock, stderr: &mut Stderr) -> i32 {
        let stdin = io::stdin();
        let line_count = &mut 0usize;
        let flags_enabled = self.number || self.number_nonblank || self.show_ends || self.show_tabs ||
                            self.squeeze_blank || self.show_nonprinting;

        if self.paths.is_empty() && flags_enabled {
            self.cat(&mut stdin.lock(), line_count, stdout, stderr);
        } else if self.paths.is_empty() {
            self.simple_cat(&mut stdin.lock(), stdout, stderr);
        } else {
            for path in &self.paths {
                if flags_enabled && path == "-" {
                    self.cat(&mut stdin.lock(), line_count, stdout, stderr);
                } else if path == "-" {
                    // Copy the standard input directly to the standard output.
                    self.simple_cat(&mut stdin.lock(), stdout, stderr);
                } else if fs::metadata(&path).map(|m| m.is_dir()).unwrap_or(false) {
                    stderr.write(path.as_bytes()).try(stderr);
                    stderr.write(b": Is a directory\n").try(stderr);
                    stderr.flush().try(stderr);
                    self.exit_status.set(1i32);
                } else if flags_enabled {
                    fs::File::open(&path)
                        // Open the file and copy the file's contents to standard output based input arguments.
                        .map(|file| self.cat(BufReader::new(file), line_count, stdout, stderr))
                        // If an error occurred, print the error and set the exit status.
                        .unwrap_or_else(|message| {
                            stderr.write(path.as_bytes()).try(stderr);
                            stderr.write(b": ").try(stderr);
                            stderr.write(message.description().as_bytes()).try(stderr);
                            stderr.write(b"\n").try(stderr);
                            stderr.flush().try(stderr);
                            self.exit_status.set(1i32);
                        });
                } else {
                    // Open a file and copy the contents directly to standard output.
                    fs::File::open(&path).map(|ref mut file| { self.simple_cat(file, stdout, stderr); })
                        // If an error occurs, print the error and set the exit status.
                        .unwrap_or_else(|message| {
                            stderr.write(path.as_bytes()).try(stderr);
                            stderr.write(b": ").try(stderr);
                            stderr.write(message.description().as_bytes()).try(stderr);
                            stderr.write(b"\n").try(stderr);
                            stderr.flush().try(stderr);
                            self.exit_status.set(1i32);
                        });
                }
            }
        }
        self.exit_status.get()
    }

    /// A simple cat that runs a lot faster than self.cat() due to no iterators over single bytes.
    fn simple_cat<F: Read>(&self, file: &mut F, stdout: &mut StdoutLock, stderr: &mut Stderr) {
        let mut buf: [u8; 8*8192] = [0; 8*8192]; // 64K seems to be the sweet spot for a buffer on my machine.
        loop {
            let n_read = file.read(&mut buf).try(stderr);
            if n_read == 0 { // We've reached the end of the input
                break;
            }
            stdout.write_all(&buf[..n_read]).try(stderr);
        }
    }

    /// Cats either a file or stdin based on the flag arguments given to the program.
    fn cat<F: Read>(&self, file: F, line_count: &mut usize, stdout: &mut StdoutLock, stderr: &mut Stderr) {
        let mut character_count = 0;
        let mut last_line_was_blank = false;

        for byte in file.bytes().map(|x| x.unwrap()) {
            if (self.number && character_count == 0) || (character_count == 0 && self.number_nonblank && byte != b'\n') {
                stdout.write(b"     ").try(stderr);
                stdout.write(line_count.to_string().as_bytes()).try(stderr);
                stdout.write(b"  ").try(stderr);
                *line_count += 1;
            }
            match byte {
                0...8 | 11...31 => if self.show_nonprinting {
                    push_caret(stdout, stderr, byte+64);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                },
                9 => {
                    if self.show_tabs {
                        push_caret(stdout, stderr, b'I');
                    } else {
                        stdout.write(&[byte]).try(stderr);
                    }
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                }
                10 => {
                    if character_count == 0 {
                        if self.squeeze_blank && last_line_was_blank {
                            continue
                        } else if !last_line_was_blank {
                            last_line_was_blank = true;
                        }
                    } else {
                        last_line_was_blank = false;
                        character_count = 0;
                    }
                    if self.show_ends {
                        stdout.write(b"$\n").try(stderr);
                    } else {
                        stdout.write(b"\n").try(stderr);
                    }
                    stdout.flush().try(stderr);
                },
                32...126 => {
                    stdout.write(&[byte]).try(stderr);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                },
                127 => if self.show_nonprinting {
                    push_caret(stdout, stderr, b'?');
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                },
                128...159 => if self.show_nonprinting {
                    stdout.write(b"M-^").try(stderr);
                    stdout.write(&[byte-64]).try(stderr);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                } else {
                    stdout.write(&[byte]).try(stderr);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                },
                _ => if self.show_nonprinting {
                    stdout.write(b"M-").try(stderr);
                    stdout.write(&[byte-128]).try(stderr);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                } else {
                    stdout.write(&[byte]).try(stderr);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                },
            }
        }
    }
}
/// Increase the character count by one if number printing is enabled.
fn count_character(character_count: &mut usize, number: &bool, number_nonblank: &bool) {
    if *number || *number_nonblank {
        *character_count += 1;
    }
}

/// Print a caret notation to stdout.
fn push_caret(stdout: &mut StdoutLock, stderr: &mut Stderr, notation: u8) {
    stdout.write(&[b'^']).try(stderr);
    stdout.write(&[notation]).try(stderr);
}

fn main() {
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    let mut stderr = io::stderr();
    exit(Program::initialize(&mut stdout, &mut stderr).and_execute(&mut stdout, &mut stderr));
}
<commit_msg>Performance improvement for cat with arguments (from 58 MB/s to 116 MB/s) by adding a 64KB input buffer, a 192KB output buffer and fixing a badly ordered if statement<commit_after>#![deny(warnings)]

extern crate arg_parser;
extern crate extra;

use std::cell::Cell; // Provide mutable fields in immutable structs
use std::env;
use std::error::Error;
use std::fs;
use std::io::{self, BufReader, Read, Stderr, StdoutLock, Write};
use std::process::exit;
use extra::option::OptionalExt;
use arg_parser::ArgParser;

const MAN_PAGE: &'static str = /* @MANSTART{cat} */ r#"NAME
    cat - concatenate files and print on the standard output

SYNOPSIS
    cat [-h | --help] [-A | --show-all] [-b | --number-nonblank] [-e] [-E | --show-ends]
        [-n | --number] [-s | --squeeze-blank] [-t] [-T] FILES...

DESCRIPTION
    Concatenates all files to the standard output.

    If no file is given, or if FILE is '-', read from standard input.

OPTIONS
    -A
    --show-all
        equivalent to -vET

    -b
    --number-nonblank
        number nonempty output lines, overriding -n

    -e
        equivalent to -vE

    -E
    --show-ends
        display $ at the end of each line

    -n
    --number
        number all output lines

    -s
    --squeeze-blank
        supress repeated empty output lines

    -t
        equivalent to -vT

    -T
    --show_tabs
        display TAB characters as ^I

    -v
    --show-nonprinting
        use caret (^) and M- notation, except for LFD and TAB.

    -h
    --help
        display this help and exit

AUTHOR
    Written by Michael Murphy.
"#; /* @MANEND */

struct Program {
    exit_status:      Cell<i32>,
    number:           bool,
    number_nonblank:  bool,
    show_ends:        bool,
    show_tabs:        bool,
    show_nonprinting: bool,
    squeeze_blank:    bool,
    paths:            Vec<String>,
}

impl Program {
    /// Initialize the program's arguments and flags.
    fn initialize(stdout: &mut StdoutLock, stderr: &mut Stderr) -> Program {
        let mut parser = ArgParser::new(10).
            add_flag(&["A", "show-all"]). //vET
            add_flag(&["b", "number-nonblank"]).
            add_flag(&["e"]). //vE
            add_flag(&["E", "show-ends"]).
            add_flag(&["n", "number"]).
            add_flag(&["s", "squeeze-blank"]).
            add_flag(&["t"]). //vT
            add_flag(&["T", "show-tabs"]).
            add_flag(&["v", "show-nonprinting"]).
            add_flag(&["h", "help"]);
        parser.parse(env::args());

        let mut cat = Program {
            exit_status:      Cell::new(0i32),
            number:           false,
            number_nonblank:  false,
            show_ends:        false,
            show_tabs:        false,
            show_nonprinting: false,
            squeeze_blank:    false,
            paths:            Vec::with_capacity(parser.args.len()),
        };

        if parser.found("help") {
            stdout.write(MAN_PAGE.as_bytes()).try(stderr);
            stdout.flush().try(stderr);
            exit(0);
        }

        if parser.found("show-all") {
            cat.show_nonprinting = true;
            cat.show_ends = true;
            cat.show_tabs = true;
        }

        if parser.found("number") {
            cat.number = true;
            cat.number_nonblank = false;
        }

        if parser.found("number-nonblank") {
            cat.number_nonblank = true;
            cat.number = false;
        }

        if parser.found("show-ends") || parser.found(&'e') {
            cat.show_ends = true;
        }

        if parser.found("squeeze-blank") {
            cat.squeeze_blank = true;
        }

        if parser.found("show-tabs") || parser.found(&'t') {
            cat.show_tabs = true;
        }

        if parser.found("show-nonprinting") || parser.found(&'e') || parser.found(&'t') {
            cat.show_nonprinting = true;
        }

        if !parser.args.is_empty() {
            cat.paths = parser.args;
        }
        cat
    }

    /// Execute the parameters given to the program.
    fn and_execute(&self, stdout: &mut StdoutLock, stderr: &mut Stderr) -> i32 {
        let stdin = io::stdin();
        let line_count = &mut 0usize;
        let flags_enabled = self.number || self.number_nonblank || self.show_ends || self.show_tabs ||
                            self.squeeze_blank || self.show_nonprinting;

        if self.paths.is_empty() && flags_enabled {
            self.cat(&mut stdin.lock(), line_count, stdout, stderr);
        } else if self.paths.is_empty() {
            self.simple_cat(&mut stdin.lock(), stdout, stderr);
        } else {
            for path in &self.paths {
                if flags_enabled && path == "-" {
                    self.cat(&mut stdin.lock(), line_count, stdout, stderr);
                } else if path == "-" {
                    // Copy the standard input directly to the standard output.
                    self.simple_cat(&mut stdin.lock(), stdout, stderr);
                } else if fs::metadata(&path).map(|m| m.is_dir()).unwrap_or(false) {
                    stderr.write(path.as_bytes()).try(stderr);
                    stderr.write(b": Is a directory\n").try(stderr);
                    stderr.flush().try(stderr);
                    self.exit_status.set(1i32);
                } else if flags_enabled {
                    fs::File::open(&path)
                        // Open the file and copy the file's contents to standard output based input arguments.
                        .map(|file| self.cat(&mut BufReader::new(file), line_count, stdout, stderr))
                        // If an error occurred, print the error and set the exit status.
                        .unwrap_or_else(|message| {
                            stderr.write(path.as_bytes()).try(stderr);
                            stderr.write(b": ").try(stderr);
                            stderr.write(message.description().as_bytes()).try(stderr);
                            stderr.write(b"\n").try(stderr);
                            stderr.flush().try(stderr);
                            self.exit_status.set(1i32);
                        });
                } else {
                    // Open a file and copy the contents directly to standard output.
                    fs::File::open(&path).map(|ref mut file| { self.simple_cat(file, stdout, stderr); })
                        // If an error occurs, print the error and set the exit status.
                        .unwrap_or_else(|message| {
                            stderr.write(path.as_bytes()).try(stderr);
                            stderr.write(b": ").try(stderr);
                            stderr.write(message.description().as_bytes()).try(stderr);
                            stderr.write(b"\n").try(stderr);
                            stderr.flush().try(stderr);
                            self.exit_status.set(1i32);
                        });
                }
            }
        }
        self.exit_status.get()
    }

    /// A simple cat that runs a lot faster than self.cat() due to no iterators over single bytes.
    fn simple_cat<F: Read>(&self, file: &mut F, stdout: &mut StdoutLock, stderr: &mut Stderr) {
        let mut buf: [u8; 8*8192] = [0; 8*8192]; // 64K seems to be the sweet spot for a buffer on my machine.
        loop {
            let n_read = file.read(&mut buf).try(stderr);
            if n_read == 0 { // We've reached the end of the input
                break;
            }
            stdout.write_all(&buf[..n_read]).try(stderr);
        }
    }

    /// Cats either a file or stdin based on the flag arguments given to the program.
    fn cat<F: Read>(&self, file: &mut F, line_count: &mut usize, stdout: &mut StdoutLock, stderr: &mut Stderr) {
        let mut character_count = 0;
        let mut last_line_was_blank = false;
        let mut buf: [u8; 8*8192] = [0; 8*8192]; // 64K seems to be the sweet spot for a buffer on my machine.
        let mut out_buf: Vec<u8> = Vec::with_capacity(24*8192); // Worst case 2 chars out per char
        loop {
            let n_read = file.read(&mut buf).try(stderr);
            if n_read == 0 { // We've reached the end of the input
                break;
            }

            for &byte in buf[0..n_read].iter() {
                if character_count == 0 && (self.number || (self.number_nonblank && byte != b'\n')) {
                    out_buf.write(b"     ").try(stderr);
                    out_buf.write(line_count.to_string().as_bytes()).try(stderr);
                    out_buf.write(b"  ").try(stderr);
                    *line_count += 1;
                }
                match byte {
                    0...8 | 11...31 => if self.show_nonprinting {
                        push_caret(&mut out_buf, stderr, byte+64);
                        count_character(&mut character_count, &self.number, &self.number_nonblank);
                    },
                    9 => {
                        if self.show_tabs {
                            push_caret(&mut out_buf, stderr, b'I');
                        } else {
                            out_buf.write(&[byte]).try(stderr);
                        }
                        count_character(&mut character_count, &self.number, &self.number_nonblank);
                    }
                    10 => {
                        if character_count == 0 {
                            if self.squeeze_blank && last_line_was_blank {
                                continue
                            } else if !last_line_was_blank {
                                last_line_was_blank = true;
                            }
                        } else {
                            last_line_was_blank = false;
                            character_count = 0;
                        }
                        if self.show_ends {
                            out_buf.write(b"$\n").try(stderr);
                        } else {
                            out_buf.write(b"\n").try(stderr);
                        }
                    },
                    32...126 => {
                        out_buf.write(&[byte]).try(stderr);
                        count_character(&mut character_count, &self.number, &self.number_nonblank);
                    },
                    127 => if self.show_nonprinting {
                        push_caret(&mut out_buf, stderr, b'?');
                        count_character(&mut character_count, &self.number, &self.number_nonblank);
                    },
                    128...159 => if self.show_nonprinting {
                        out_buf.write(b"M-^").try(stderr);
                        out_buf.write(&[byte-64]).try(stderr);
                        count_character(&mut character_count, &self.number, &self.number_nonblank);
                    } else {
                        out_buf.write(&[byte]).try(stderr);
                        count_character(&mut character_count, &self.number, &self.number_nonblank);
                    },
                    _ => if self.show_nonprinting {
                        out_buf.write(b"M-").try(stderr);
                        out_buf.write(&[byte-128]).try(stderr);
                        count_character(&mut character_count, &self.number, &self.number_nonblank);
                    } else {
                        out_buf.write(&[byte]).try(stderr);
                        count_character(&mut character_count, &self.number, &self.number_nonblank);
                    },
                }
            }
            stdout.write_all(&out_buf).try(stderr);
            out_buf.clear();
        }
    }
}
/// Increase the character count by one if number printing is enabled.
fn count_character(character_count: &mut usize, number: &bool, number_nonblank: &bool) {
    if *number || *number_nonblank {
        *character_count += 1;
    }
}

/// Print a caret notation to stdout.
fn push_caret<T: Write>(stdout: &mut T, stderr: &mut Stderr, notation: u8) {
    stdout.write(&[b'^']).try(stderr);
    stdout.write(&[notation]).try(stderr);
}

fn main() {
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    let mut stderr = io::stderr();
    exit(Program::initialize(&mut stdout, &mut stderr).and_execute(&mut stdout, &mut stderr));
}
<|endoftext|>


<commit_before>extern crate clap;

use clap::{AppSettings, Arg, ArgMatches};

use cargo::{self, CliResult, Config};

use super::list_commands;
use super::commands;
use command_prelude::*;

pub fn main(config: &mut Config) -> CliResult {
    let args = cli().get_matches_safe()?;

    if args.value_of("unstable-features") == Some("help") {
        println!(
            "
Available unstable (nightly-only) flags:

    -Z avoid-dev-deps   -- Avoid installing dev-dependencies if possible
    -Z minimal-versions -- Install minimal dependency versions instead of maximum
    -Z no-index-update  -- Do not update the registry, avoids a network request for benchmarking
    -Z offline          -- Offline mode that does not perform network requests
    -Z unstable-options -- Allow the usage of unstable options such as --registry

Run with 'cargo -Z [FLAG] [SUBCOMMAND]'"
        );
        return Ok(());
    }

    let is_verbose = args.occurrences_of("verbose") > 0;
    if args.is_present("version") {
        let version = cargo::version();
        println!("{}", version);
        if is_verbose {
            println!(
                "release: {}.{}.{}",
                version.major, version.minor, version.patch
            );
            if let Some(ref cfg) = version.cfg_info {
                if let Some(ref ci) = cfg.commit_info {
                    println!("commit-hash: {}", ci.commit_hash);
                    println!("commit-date: {}", ci.commit_date);
                }
            }
        }
        return Ok(());
    }

    if let Some(ref code) = args.value_of("explain") {
        let mut procss = config.rustc()?.process();
        procss.arg("--explain").arg(code).exec()?;
        return Ok(());
    }

    if args.is_present("list") {
        println!("Installed Commands:");
        for command in list_commands(config) {
            let (command, path) = command;
            if is_verbose {
                match path {
                    Some(p) => println!("    {:<20} {}", command, p),
                    None => println!("    {:<20}", command),
                }
            } else {
                println!("    {}", command);
            }
        }
        return Ok(());
    }

    if args.subcommand_name().is_none() {}

    execute_subcommand(config, args)
}

fn execute_subcommand(config: &mut Config, args: ArgMatches) -> CliResult {
    config.configure(
        args.occurrences_of("verbose") as u32,
        if args.is_present("quiet") {
            Some(true)
        } else {
            None
        },
        &args.value_of("color").map(|s| s.to_string()),
        args.is_present("frozen"),
        args.is_present("locked"),
        &args.values_of_lossy("unstable-features")
            .unwrap_or_default(),
    )?;

    let (cmd, args) = match args.subcommand() {
        (cmd, Some(args)) => (cmd, args),
        _ => {
            cli().print_help()?;
            return Ok(());
        }
    };

    if let Some(exec) = commands::builtin_exec(cmd) {
        return exec(config, args);
    }

    if let Some(mut alias) = super::aliased_command(config, cmd)? {
        alias.extend(
            args.values_of("")
                .unwrap_or_default()
                .map(|s| s.to_string()),
        );
        let args = cli()
            .setting(AppSettings::NoBinaryName)
            .get_matches_from_safe(alias)?;
        return execute_subcommand(config, args);
    }
    let mut ext_args: Vec<&str> = vec![cmd];
    ext_args.extend(args.values_of("").unwrap_or_default());
    super::execute_external_subcommand(config, cmd, &ext_args)
}

fn cli() -> App {
    let app = App::new("cargo")
        .settings(&[
            AppSettings::UnifiedHelpMessage,
            AppSettings::DeriveDisplayOrder,
            AppSettings::VersionlessSubcommands,
            AppSettings::AllowExternalSubcommands,
        ])
        .about("")
        .template(
            "\
Rust's package manager

USAGE:
    {usage}

OPTIONS:
{unified}

Some common cargo commands are (see all commands with --list):
    build       Compile the current project
    check       Analyze the current project and report errors, but don't build object files
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    init        Create a new cargo project in an existing directory
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock
    search      Search registry for crates
    publish     Package and upload this project to the registry
    install     Install a Rust binary
    uninstall   Uninstall a Rust binary

See 'cargo help <command>' for more information on a specific command.\n",
        )
        .arg(opt("version", "Print version info and exit").short("V"))
        .arg(opt("list", "List installed commands"))
        .arg(opt("explain", "Run `rustc --explain CODE`").value_name("CODE"))
        .arg(
            opt(
                "verbose",
                "Use verbose output (-vv very verbose/build.rs output)",
            ).short("v")
                .multiple(true)
                .global(true),
        )
        .arg(
            opt("quiet", "No output printed to stdout")
                .short("q")
                .global(true),
        )
        .arg(
            opt("color", "Coloring: auto, always, never")
                .value_name("WHEN")
                .global(true),
        )
        .arg(opt("frozen", "Require Cargo.lock and cache are up to date").global(true))
        .arg(opt("locked", "Require Cargo.lock is up to date").global(true))
        .arg(
            Arg::with_name("unstable-features")
                .help("Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details")
                .short("Z")
                .value_name("FLAG")
                .multiple(true)
                .number_of_values(1)
                .global(true),
        )
        .subcommands(commands::builtin());
    app
}
<commit_msg>chore(cli): Remove dead code in main()<commit_after>extern crate clap;

use clap::{AppSettings, Arg, ArgMatches};

use cargo::{self, CliResult, Config};

use super::list_commands;
use super::commands;
use command_prelude::*;

pub fn main(config: &mut Config) -> CliResult {
    let args = cli().get_matches_safe()?;

    if args.value_of("unstable-features") == Some("help") {
        println!(
            "
Available unstable (nightly-only) flags:

    -Z avoid-dev-deps   -- Avoid installing dev-dependencies if possible
    -Z minimal-versions -- Install minimal dependency versions instead of maximum
    -Z no-index-update  -- Do not update the registry, avoids a network request for benchmarking
    -Z offline          -- Offline mode that does not perform network requests
    -Z unstable-options -- Allow the usage of unstable options such as --registry

Run with 'cargo -Z [FLAG] [SUBCOMMAND]'"
        );
        return Ok(());
    }

    let is_verbose = args.occurrences_of("verbose") > 0;
    if args.is_present("version") {
        let version = cargo::version();
        println!("{}", version);
        if is_verbose {
            println!(
                "release: {}.{}.{}",
                version.major, version.minor, version.patch
            );
            if let Some(ref cfg) = version.cfg_info {
                if let Some(ref ci) = cfg.commit_info {
                    println!("commit-hash: {}", ci.commit_hash);
                    println!("commit-date: {}", ci.commit_date);
                }
            }
        }
        return Ok(());
    }

    if let Some(ref code) = args.value_of("explain") {
        let mut procss = config.rustc()?.process();
        procss.arg("--explain").arg(code).exec()?;
        return Ok(());
    }

    if args.is_present("list") {
        println!("Installed Commands:");
        for command in list_commands(config) {
            let (command, path) = command;
            if is_verbose {
                match path {
                    Some(p) => println!("    {:<20} {}", command, p),
                    None => println!("    {:<20}", command),
                }
            } else {
                println!("    {}", command);
            }
        }
        return Ok(());
    }

    execute_subcommand(config, args)
}

fn execute_subcommand(config: &mut Config, args: ArgMatches) -> CliResult {
    config.configure(
        args.occurrences_of("verbose") as u32,
        if args.is_present("quiet") {
            Some(true)
        } else {
            None
        },
        &args.value_of("color").map(|s| s.to_string()),
        args.is_present("frozen"),
        args.is_present("locked"),
        &args.values_of_lossy("unstable-features")
            .unwrap_or_default(),
    )?;

    let (cmd, args) = match args.subcommand() {
        (cmd, Some(args)) => (cmd, args),
        _ => {
            cli().print_help()?;
            return Ok(());
        }
    };

    if let Some(exec) = commands::builtin_exec(cmd) {
        return exec(config, args);
    }

    if let Some(mut alias) = super::aliased_command(config, cmd)? {
        alias.extend(
            args.values_of("")
                .unwrap_or_default()
                .map(|s| s.to_string()),
        );
        let args = cli()
            .setting(AppSettings::NoBinaryName)
            .get_matches_from_safe(alias)?;
        return execute_subcommand(config, args);
    }
    let mut ext_args: Vec<&str> = vec![cmd];
    ext_args.extend(args.values_of("").unwrap_or_default());
    super::execute_external_subcommand(config, cmd, &ext_args)
}

fn cli() -> App {
    let app = App::new("cargo")
        .settings(&[
            AppSettings::UnifiedHelpMessage,
            AppSettings::DeriveDisplayOrder,
            AppSettings::VersionlessSubcommands,
            AppSettings::AllowExternalSubcommands,
        ])
        .about("")
        .template(
            "\
Rust's package manager

USAGE:
    {usage}

OPTIONS:
{unified}

Some common cargo commands are (see all commands with --list):
    build       Compile the current project
    check       Analyze the current project and report errors, but don't build object files
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    init        Create a new cargo project in an existing directory
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock
    search      Search registry for crates
    publish     Package and upload this project to the registry
    install     Install a Rust binary
    uninstall   Uninstall a Rust binary

See 'cargo help <command>' for more information on a specific command.\n",
        )
        .arg(opt("version", "Print version info and exit").short("V"))
        .arg(opt("list", "List installed commands"))
        .arg(opt("explain", "Run `rustc --explain CODE`").value_name("CODE"))
        .arg(
            opt(
                "verbose",
                "Use verbose output (-vv very verbose/build.rs output)",
            ).short("v")
                .multiple(true)
                .global(true),
        )
        .arg(
            opt("quiet", "No output printed to stdout")
                .short("q")
                .global(true),
        )
        .arg(
            opt("color", "Coloring: auto, always, never")
                .value_name("WHEN")
                .global(true),
        )
        .arg(opt("frozen", "Require Cargo.lock and cache are up to date").global(true))
        .arg(opt("locked", "Require Cargo.lock is up to date").global(true))
        .arg(
            Arg::with_name("unstable-features")
                .help("Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details")
                .short("Z")
                .value_name("FLAG")
                .multiple(true)
                .number_of_values(1)
                .global(true),
        )
        .subcommands(commands::builtin());
    app
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::char;

fn main() {
    let program_string = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.";
    let mut program: Vec<char> = vec![];
    for command in program_string.chars() {
        program.push(command);
    }
    let program = program;

    let mut command_map: HashMap<char, fn(&mut [i8; 30000], &mut usize, &Vec<char>, &mut usize, &mut i32)> = HashMap::new();
    command_map.insert('+', plus);
    command_map.insert('-', minus);
    command_map.insert('<', lessthan);
    command_map.insert('>', greaterthan);
    command_map.insert('.', period);
    command_map.insert('[', openbrace);
    command_map.insert(']', closebrace);
    let command_map = command_map;

    let mut data: [i8; 30000] = [0; 30000];
    let mut dptr: usize = 0;
    let mut pptr: usize = 0;
    let mut depth: i32 = 0;

    loop {
        match command_map.get(&program[pptr]) {
            Some(x) => x(&mut data, &mut dptr, &program, &mut pptr, &mut depth),
            None    => pptr += 1
        }
        if pptr == program.len() {
            break;
        }
    }
}

fn plus(data: &mut [i8;30000], dptr: &mut usize, program: &Vec<char>, pptr: &mut usize, depth: &mut i32) {
    data[*dptr] = data[*dptr].wrapping_add(1);
    *pptr += 1;
}

fn minus(data: &mut [i8;30000], dptr: &mut usize, program: &Vec<char>, pptr: &mut usize, depth: &mut i32) {
    data[*dptr] = data[*dptr].wrapping_sub(1);
    *pptr += 1;
}

fn lessthan(data: &mut [i8;30000], dptr: &mut usize, program: &Vec<char>, pptr: &mut usize, depth: &mut i32) {
    *dptr -= 1;
    *pptr += 1;
}

fn greaterthan(data: &mut [i8;30000], dptr: &mut usize, program: &Vec<char>, pptr: &mut usize, depth: &mut i32) {
    *dptr += 1;
    *pptr += 1;
}

fn period(data: &mut [i8;30000], dptr: &mut usize, program: &Vec<char>, pptr: &mut usize, depth: &mut i32) {
    match char::from_u32(data[*dptr] as u32) {
        Some(x) => print!("{}", x),
        None    => ()
    }
    *pptr += 1;
}

fn openbrace(data: &mut [i8;30000], dptr: &mut usize, program: &Vec<char>, pptr: &mut usize, depth: &mut i32) {
    let old_depth = *depth;
    *depth += 1;
    if data[*dptr] == 0 {
        while *depth != old_depth {
            *pptr += 1;
            match program[*pptr] {
                '[' => *depth += 1,
                ']' => *depth -=1,
                _   => ()
            }
        }
    }
    *pptr += 1;
}

fn closebrace(data: &mut [i8;30000], dptr: &mut usize, program: &Vec<char>, pptr: &mut usize, depth: &mut i32) {
    let old_depth = *depth;
    *depth -= 1;
    if data[*dptr] != 0 {
        while *depth != old_depth {
            *pptr -= 1;
            match program[*pptr] {
                '[' => *depth += 1,
                ']' => *depth -= 1,
                _   => ()
            }
        }
    }
    *pptr += 1;
}
<commit_msg>Allow user to input brainfuck program<commit_after>use std::collections::HashMap;
use std::char;
use std::io;

fn main() {
    let mut program_string = String::new();
    println!("Enter the brainfuck program:");
    io::stdin().read_line(&mut program_string)
        .expect("Failed to read line!");

    let mut program: Vec<char> = vec![];
    for command in program_string.chars() {
        program.push(command);
    }
    let program = program;

    let mut command_map: HashMap<char, fn(&mut [i8; 30000], &mut usize, &Vec<char>, &mut usize, &mut i32)> = HashMap::new();
    command_map.insert('+', plus);
    command_map.insert('-', minus);
    command_map.insert('<', lessthan);
    command_map.insert('>', greaterthan);
    command_map.insert('.', period);
    command_map.insert('[', openbrace);
    command_map.insert(']', closebrace);
    let command_map = command_map;

    let mut data: [i8; 30000] = [0; 30000];
    let mut dptr: usize = 0;
    let mut pptr: usize = 0;
    let mut depth: i32 = 0;

    loop {
        match command_map.get(&program[pptr]) {
            Some(x) => x(&mut data, &mut dptr, &program, &mut pptr, &mut depth),
            None    => pptr += 1
        }
        if pptr == program.len() {
            break;
        }
    }
}

fn plus(data: &mut [i8;30000], dptr: &mut usize, program: &Vec<char>, pptr: &mut usize, depth: &mut i32) {
    data[*dptr] = data[*dptr].wrapping_add(1);
    *pptr += 1;
}

fn minus(data: &mut [i8;30000], dptr: &mut usize, program: &Vec<char>, pptr: &mut usize, depth: &mut i32) {
    data[*dptr] = data[*dptr].wrapping_sub(1);
    *pptr += 1;
}

fn lessthan(data: &mut [i8;30000], dptr: &mut usize, program: &Vec<char>, pptr: &mut usize, depth: &mut i32) {
    *dptr -= 1;
    *pptr += 1;
}

fn greaterthan(data: &mut [i8;30000], dptr: &mut usize, program: &Vec<char>, pptr: &mut usize, depth: &mut i32) {
    *dptr += 1;
    *pptr += 1;
}

fn period(data: &mut [i8;30000], dptr: &mut usize, program: &Vec<char>, pptr: &mut usize, depth: &mut i32) {
    match char::from_u32(data[*dptr] as u32) {
        Some(x) => print!("{}", x),
        None    => ()
    }
    *pptr += 1;
}

fn openbrace(data: &mut [i8;30000], dptr: &mut usize, program: &Vec<char>, pptr: &mut usize, depth: &mut i32) {
    let old_depth = *depth;
    *depth += 1;
    if data[*dptr] == 0 {
        while *depth != old_depth {
            *pptr += 1;
            match program[*pptr] {
                '[' => *depth += 1,
                ']' => *depth -=1,
                _   => ()
            }
        }
    }
    *pptr += 1;
}

fn closebrace(data: &mut [i8;30000], dptr: &mut usize, program: &Vec<char>, pptr: &mut usize, depth: &mut i32) {
    let old_depth = *depth;
    *depth -= 1;
    if data[*dptr] != 0 {
        while *depth != old_depth {
            *pptr -= 1;
            match program[*pptr] {
                '[' => *depth += 1,
                ']' => *depth -= 1,
                _   => ()
            }
        }
    }
    *pptr += 1;
}
<|endoftext|>