<commit_before>extern crate pnet;

use std::old_io::net::ip::{IpAddr, Ipv4Addr};
use pnet::old_packet::{Packet};
use pnet::old_packet::ipv4::{Ipv4Header, Ipv4Packet};
use pnet::old_packet::ip::{IpNextHeaderProtocol,IpNextHeaderProtocols};

use util;

pub trait IcmpPacket : Ipv4Packet {
    fn calculate_icmp_checksum(&self) -> u16 {
        // start at end of IP header packet
        let start_offset = self.get_header_length() as usize * 4;
        let chunked: Vec<u16> = self.packet().slice_from(start_offset).
            chunks(2).
            map(|x| x.iter().fold(0u16, |sum, y|
                                  if sum == 0 {
                                      sum + (*y as u16) << 4
                                  }
                                  else {
                                      sum + *y as u16
                                  }
                                 )).collect();
        util::ones_complement_sum(chunked.as_slice())
    }

    fn start_of_icmp(&self) -> usize {
        self.get_header_length() as usize * 4
    }

    fn get_ip_type(&self) -> u8 {
        let start = self.start_of_icmp();
        self.packet()[start]
    }

    fn get_ip_code(&self) -> u8 {
        let start = self.start_of_icmp();
        self.packet()[start + 1]
    }

    fn get_ip_checksum(&self) -> u16 {
        let start = self.start_of_icmp();
        let b1 = (self.packet()[start + 2] as u16) << 8;
        let b2 = (self.packet()[start + 3] as u16);
        b1 | b2
    }

    fn get_identifier(&self) -> u16 {
        let start = self.start_of_icmp();
        let b1 = (self.packet()[start + 4] as u16) << 8;
        let b2 = (self.packet()[start + 5] as u16);
        b1 | b2
    }

    fn get_sequence(&self) -> u16 {
        let start = self.start_of_icmp();
        let b1 = (self.packet()[start + 6] as u16) << 8;
        let b2 = (self.packet()[start + 7] as u16);
        b1 | b2
    }

    fn get_originate_timestamp(&self) -> u32 {
        let start = self.start_of_icmp();
        let b1 = (self.packet()[start + 8] as u32) << 24;
        let b2 = (self.packet()[start + 9] as u32) << 16;
        let b3 = (self.packet()[start + 10] as u32) << 8;
        let b4 = (self.packet()[start + 11] as u32);
        b1 | b2 | b3 | b4
    }

    fn get_receive_timestamp(&self) -> u32 {
        let start = self.start_of_icmp();
        let b1 = (self.packet()[start + 12] as u32) << 24;
        let b2 = (self.packet()[start + 13] as u32) << 16;
        let b3 = (self.packet()[start + 14] as u32) << 8;
        let b4 = (self.packet()[start + 15] as u32);
        b1 | b2 | b3 | b4
    }

    fn get_transmit_timestamp(&self) -> u32 {
        let start = self.start_of_icmp();
        let b1 = (self.packet()[start + 16] as u32) << 24;
        let b2 = (self.packet()[start + 17] as u32) << 16;
        let b3 = (self.packet()[start + 18] as u32) << 8;
        let b4 = (self.packet()[start + 19] as u32);
        b1 | b2 | b3 | b4
    }
}

pub struct IcmpRequestPacket<'p> {
    packet: &'p [u8]
}

pub struct MutIcmpRequestPacket<'p> {
    packet: &'p mut [u8]
}

// pretty much copy-pasted from pnet, not sure if inline directives are necessary
impl<'a> Packet for IcmpRequestPacket<'a> {
    #[inline(always)]
    fn packet<'p>(&'p self) -> &'p [u8] { self.packet }

    #[inline(always)]
    fn payload<'p>(&'p self) -> &'p [u8] { &self.packet[20..] }
    // use of 20 here should be fine for our case, IHL is 5, no IP options in header
}

impl<'a> Packet for MutIcmpRequestPacket<'a> {
    #[inline(always)]
    fn packet<'p>(&'p self) -> &'p [u8] { self.packet }

    #[inline(always)]
    fn payload<'p>(&'p self) -> &'p [u8] { &self.packet[20..] }
    // use of 20 here should be fine for our case, IHL is 5, no IP options in header
}

impl<'p> Ipv4Packet for IcmpRequestPacket<'p> {}
impl<'p> IcmpPacket for IcmpRequestPacket<'p> {}

impl<'p> Ipv4Packet for MutIcmpRequestPacket<'p> {}
impl<'p> IcmpPacket for MutIcmpRequestPacket<'p> {}

impl<'p> IcmpRequestPacket<'p> {
    pub fn new(packet_slice: &'p [u8]) -> IcmpRequestPacket {
        IcmpRequestPacket {
            packet: packet_slice
        }
    }
}

impl<'p> MutIcmpRequestPacket<'p> {
    pub fn new(packet_slice: &'p mut [u8]) -> MutIcmpRequestPacket {
        MutIcmpRequestPacket {
            packet: packet_slice
        }
    }

    pub fn allocation_size() -> usize {
        // 20 for IP header, 8 for ICMP header, 12 for ICMP data
        20 + 8 + 12
    }

    pub fn prepare_for_sending(&mut self, addr: &IpAddr) {
        self.set_version(4);
        self.set_header_length(5);
        self.set_dscp(0);
        self.set_total_length(40);
        self.set_identification(257);
        self.set_flags(2);
        // no need to set fragment offset, I believe
        self.set_fragment_offset(0);
        self.set_ttl(64);
        self.set_next_level_protocol(IpNextHeaderProtocols::Icmp);
        self.checksum();
        self.set_destination(*addr);
        self.set_source(Ipv4Addr(127, 0, 0, 1));

        self.set_icmp_type();
        self.set_icmp_code();
        self.set_icmp_identifier();
        self.set_icmp_sequence();
        self.set_originate_timestamp();
        self.set_icmp_checksum();
    }

    fn set_icmp_checksum(&mut self) {
        let start = self.start_of_icmp();
        let checksum = self.calculate_icmp_checksum();
        self.packet[start + 2] = (checksum >> 8) as u8;
        self.packet[start + 3] = (checksum & 0xf) as u8;
    }

    fn set_icmp_type(&mut self) {
        let start = self.start_of_icmp();
        self.packet[start] = 13;
    }

    fn set_icmp_code(&mut self) {
        let start = self.start_of_icmp();
        self.packet[start + 1] = 0;
    }

    fn set_icmp_identifier(&mut self) {
    }

    fn set_icmp_sequence(&mut self) {
    }

    fn set_originate_timestamp(&mut self) {
        let start = self.start_of_icmp();
        let time = util::msecs_after_utc();
        // dbl check this offset
        self.packet[start + 8] = (time >> 24) as u8;
        self.packet[start + 9] = ((time >> 16) & 0xf0) as u8;
        self.packet[start + 10] = ((time >> 8) & 0xff0) as u8;
        self.packet[start + 11] = time as u8;
    }

    pub fn set_version(&mut self, version: u8) {
        let ver = version << 4;
        self.packet[0] = (self.packet[0] & 0x0F) | ver;
    }

    /// Set the header length field for the packet
    pub fn set_header_length(&mut self, ihl: u8) {
        let len = ihl & 0xF;
        self.packet[0] = (self.packet[0] & 0xF0) | len;
    }

    /// Set the DSCP field for the packet
    pub fn set_dscp(&mut self, dscp: u8) {
        let cp = dscp & 0xFC;
        self.packet[1] = (self.packet[1] & 3) | (cp << 2);
    }

    /// Set the ECN field for the packet
    pub fn set_ecn(&mut self, ecn: u8) {
        let cn = ecn & 3;
        self.packet[1] = (self.packet[1] & 0xFC) | cn;
    }

    /// Set the total length field for the packet
    pub fn set_total_length(&mut self, len: u16) {
        self.packet[2] = (len >> 8) as u8;
        self.packet[3] = (len & 0xFF) as u8;
    }

    /// Set the identification field for the packet
    pub fn set_identification(&mut self, identification: u16) {
        self.packet[4] = (identification >> 8) as u8;
        self.packet[5] = (identification & 0x00FF) as u8;
    }

    /// Set the flags field for the packet
    pub fn set_flags(&mut self, flags: u8) {
        let fs = (flags & 7) << 5;
        self.packet[6] = (self.packet[6] & 0x1F) | fs;
    }

    /// Set the fragment offset field for the packet
    pub fn set_fragment_offset(&mut self, offset: u16) {
        let fo = offset & 0x1FFF;
        self.packet[6] = (self.packet[6] & 0xE0) | ((fo & 0xFF00) >> 8) as u8;
        self.packet[7] = (fo & 0xFF) as u8;
    }

    /// Set the TTL field for the packet
    pub fn set_ttl(&mut self, ttl: u8) {
        self.packet[8] = ttl;
    }

    /// Set the next level protocol field for the packet
    pub fn set_next_level_protocol(&mut self, IpNextHeaderProtocol(protocol): IpNextHeaderProtocol) {
        self.packet[9] = protocol;
    }

    /// Set the checksum field for the packet
    pub fn set_checksum(&mut self, checksum: u16) {
        let cs1 = ((checksum & 0xFF00) >> 8) as u8;
        let cs2 = (checksum & 0x00FF) as u8;
        self.packet[10] = cs1;
        self.packet[11] = cs2;
    }

    /// Set the source address for the packet
    pub fn set_source(&mut self, ip: IpAddr) {
        match ip {
            Ipv4Addr(a, b, c, d) => {
                self.packet[12] = a;
                self.packet[13] = b;
                self.packet[14] = c;
                self.packet[15] = d;
            },
            _ => ()
        }
    }

    /// Set the destination field for the packet
    pub fn set_destination(&mut self, ip: IpAddr) {
        match ip {
            Ipv4Addr(a, b, c, d) => {
                self.packet[16] = a;
                self.packet[17] = b;
                self.packet[18] = c;
                self.packet[19] = d;
            },
            _ => ()
        }
    }

    /// Calculate the checksum of the packet and then set the field to the value
    /// calculated
    pub fn checksum(&mut self) {
        let checksum = self.calculate_checksum();
        self.set_checksum(checksum);
    }

}
<commit_msg>implementation of icmp identifier and sequence setting<commit_after>extern crate pnet;

use std::old_io::net::ip::{IpAddr, Ipv4Addr};
use pnet::old_packet::{Packet};
use pnet::old_packet::ipv4::{Ipv4Header, Ipv4Packet};
use pnet::old_packet::ip::{IpNextHeaderProtocol,IpNextHeaderProtocols};

use util;

pub trait IcmpPacket : Ipv4Packet {
    fn calculate_icmp_checksum(&self) -> u16 {
        // start at end of IP header packet
        let start_offset = self.get_header_length() as usize * 4;
        let chunked: Vec<u16> = self.packet().slice_from(start_offset).
            chunks(2).
            map(|x| x.iter().fold(0u16, |sum, y|
                                  if sum == 0 {
                                      sum + (*y as u16) << 4
                                  }
                                  else {
                                      sum + *y as u16
                                  }
                                 )).collect();
        util::ones_complement_sum(chunked.as_slice())
    }

    fn start_of_icmp(&self) -> usize {
        self.get_header_length() as usize * 4
    }

    fn get_ip_type(&self) -> u8 {
        let start = self.start_of_icmp();
        self.packet()[start]
    }

    fn get_ip_code(&self) -> u8 {
        let start = self.start_of_icmp();
        self.packet()[start + 1]
    }

    fn get_ip_checksum(&self) -> u16 {
        let start = self.start_of_icmp();
        let b1 = (self.packet()[start + 2] as u16) << 8;
        let b2 = (self.packet()[start + 3] as u16);
        b1 | b2
    }

    fn get_identifier(&self) -> u16 {
        let start = self.start_of_icmp();
        let b1 = (self.packet()[start + 4] as u16) << 8;
        let b2 = (self.packet()[start + 5] as u16);
        b1 | b2
    }

    fn get_sequence(&self) -> u16 {
        let start = self.start_of_icmp();
        let b1 = (self.packet()[start + 6] as u16) << 8;
        let b2 = (self.packet()[start + 7] as u16);
        b1 | b2
    }

    fn get_originate_timestamp(&self) -> u32 {
        let start = self.start_of_icmp();
        let b1 = (self.packet()[start + 8] as u32) << 24;
        let b2 = (self.packet()[start + 9] as u32) << 16;
        let b3 = (self.packet()[start + 10] as u32) << 8;
        let b4 = (self.packet()[start + 11] as u32);
        b1 | b2 | b3 | b4
    }

    fn get_receive_timestamp(&self) -> u32 {
        let start = self.start_of_icmp();
        let b1 = (self.packet()[start + 12] as u32) << 24;
        let b2 = (self.packet()[start + 13] as u32) << 16;
        let b3 = (self.packet()[start + 14] as u32) << 8;
        let b4 = (self.packet()[start + 15] as u32);
        b1 | b2 | b3 | b4
    }

    fn get_transmit_timestamp(&self) -> u32 {
        let start = self.start_of_icmp();
        let b1 = (self.packet()[start + 16] as u32) << 24;
        let b2 = (self.packet()[start + 17] as u32) << 16;
        let b3 = (self.packet()[start + 18] as u32) << 8;
        let b4 = (self.packet()[start + 19] as u32);
        b1 | b2 | b3 | b4
    }
}

pub struct IcmpRequestPacket<'p> {
    packet: &'p [u8]
}

pub struct MutIcmpRequestPacket<'p> {
    packet: &'p mut [u8]
}

// pretty much copy-pasted from pnet, not sure if inline directives are necessary
impl<'a> Packet for IcmpRequestPacket<'a> {
    #[inline(always)]
    fn packet<'p>(&'p self) -> &'p [u8] { self.packet }

    #[inline(always)]
    fn payload<'p>(&'p self) -> &'p [u8] { &self.packet[20..] }
    // use of 20 here should be fine for our case, IHL is 5, no IP options in header
}

impl<'a> Packet for MutIcmpRequestPacket<'a> {
    #[inline(always)]
    fn packet<'p>(&'p self) -> &'p [u8] { self.packet }

    #[inline(always)]
    fn payload<'p>(&'p self) -> &'p [u8] { &self.packet[20..] }
    // use of 20 here should be fine for our case, IHL is 5, no IP options in header
}

impl<'p> Ipv4Packet for IcmpRequestPacket<'p> {}
impl<'p> IcmpPacket for IcmpRequestPacket<'p> {}

impl<'p> Ipv4Packet for MutIcmpRequestPacket<'p> {}
impl<'p> IcmpPacket for MutIcmpRequestPacket<'p> {}

impl<'p> IcmpRequestPacket<'p> {
    pub fn new(packet_slice: &'p [u8]) -> IcmpRequestPacket {
        IcmpRequestPacket {
            packet: packet_slice
        }
    }
}

impl<'p> MutIcmpRequestPacket<'p> {
    pub fn new(packet_slice: &'p mut [u8]) -> MutIcmpRequestPacket {
        MutIcmpRequestPacket {
            packet: packet_slice
        }
    }

    pub fn allocation_size() -> usize {
        // 20 for IP header, 8 for ICMP header, 12 for ICMP data
        20 + 8 + 12
    }

    pub fn prepare_for_sending(&mut self, addr: &IpAddr) {
        self.set_version(4);
        self.set_header_length(5);
        self.set_dscp(0);
        self.set_total_length(40);
        self.set_identification(257);
        self.set_flags(2);
        // no need to set fragment offset, I believe
        self.set_fragment_offset(0);
        self.set_ttl(64);
        self.set_next_level_protocol(IpNextHeaderProtocols::Icmp);
        self.checksum();
        self.set_destination(*addr);
        self.set_source(Ipv4Addr(127, 0, 0, 1));

        self.set_icmp_type();
        self.set_icmp_code();
        self.set_icmp_identifier(0x9b69);
        self.set_icmp_sequence(1);
        self.set_originate_timestamp();
        self.set_icmp_checksum();
    }

    fn set_icmp_checksum(&mut self) {
        let start = self.start_of_icmp();
        let checksum = self.calculate_icmp_checksum();
        self.packet[start + 2] = (checksum >> 8) as u8;
        self.packet[start + 3] = (checksum & 0xf) as u8;
    }

    fn set_icmp_type(&mut self) {
        let start = self.start_of_icmp();
        self.packet[start] = 13;
    }

    fn set_icmp_code(&mut self) {
        let start = self.start_of_icmp();
        self.packet[start + 1] = 0;
    }

    fn set_icmp_identifier(&mut self, id: u16) {
        let start = self.start_of_icmp();
        self.packet[start + 4] = (id >> 8) as u8;
        self.packet[start + 5] = id as u8;
    }

    fn set_icmp_sequence(&mut self, sequence: u16) {
        let start = self.start_of_icmp();
        self.packet[start + 6] = (sequence >> 8) as u8;
        self.packet[start + 7] = sequence as u8;
    }

    fn set_originate_timestamp(&mut self) {
        let start = self.start_of_icmp();
        let time = util::msecs_after_utc();
        // dbl check this offset
        self.packet[start + 8] = (time >> 24) as u8;
        self.packet[start + 9] = ((time >> 16) & 0xf0) as u8;
        self.packet[start + 10] = ((time >> 8) & 0xff0) as u8;
        self.packet[start + 11] = time as u8;
    }

    pub fn set_version(&mut self, version: u8) {
        let ver = version << 4;
        self.packet[0] = (self.packet[0] & 0x0F) | ver;
    }

    /// Set the header length field for the packet
    pub fn set_header_length(&mut self, ihl: u8) {
        let len = ihl & 0xF;
        self.packet[0] = (self.packet[0] & 0xF0) | len;
    }

    /// Set the DSCP field for the packet
    pub fn set_dscp(&mut self, dscp: u8) {
        let cp = dscp & 0xFC;
        self.packet[1] = (self.packet[1] & 3) | (cp << 2);
    }

    /// Set the ECN field for the packet
    pub fn set_ecn(&mut self, ecn: u8) {
        let cn = ecn & 3;
        self.packet[1] = (self.packet[1] & 0xFC) | cn;
    }

    /// Set the total length field for the packet
    pub fn set_total_length(&mut self, len: u16) {
        self.packet[2] = (len >> 8) as u8;
        self.packet[3] = (len & 0xFF) as u8;
    }

    /// Set the identification field for the packet
    pub fn set_identification(&mut self, identification: u16) {
        self.packet[4] = (identification >> 8) as u8;
        self.packet[5] = (identification & 0x00FF) as u8;
    }

    /// Set the flags field for the packet
    pub fn set_flags(&mut self, flags: u8) {
        let fs = (flags & 7) << 5;
        self.packet[6] = (self.packet[6] & 0x1F) | fs;
    }

    /// Set the fragment offset field for the packet
    pub fn set_fragment_offset(&mut self, offset: u16) {
        let fo = offset & 0x1FFF;
        self.packet[6] = (self.packet[6] & 0xE0) | ((fo & 0xFF00) >> 8) as u8;
        self.packet[7] = (fo & 0xFF) as u8;
    }

    /// Set the TTL field for the packet
    pub fn set_ttl(&mut self, ttl: u8) {
        self.packet[8] = ttl;
    }

    /// Set the next level protocol field for the packet
    pub fn set_next_level_protocol(&mut self, IpNextHeaderProtocol(protocol): IpNextHeaderProtocol) {
        self.packet[9] = protocol;
    }

    /// Set the checksum field for the packet
    pub fn set_checksum(&mut self, checksum: u16) {
        let cs1 = ((checksum & 0xFF00) >> 8) as u8;
        let cs2 = (checksum & 0x00FF) as u8;
        self.packet[10] = cs1;
        self.packet[11] = cs2;
    }

    /// Set the source address for the packet
    pub fn set_source(&mut self, ip: IpAddr) {
        match ip {
            Ipv4Addr(a, b, c, d) => {
                self.packet[12] = a;
                self.packet[13] = b;
                self.packet[14] = c;
                self.packet[15] = d;
            },
            _ => ()
        }
    }

    /// Set the destination field for the packet
    pub fn set_destination(&mut self, ip: IpAddr) {
        match ip {
            Ipv4Addr(a, b, c, d) => {
                self.packet[16] = a;
                self.packet[17] = b;
                self.packet[18] = c;
                self.packet[19] = d;
            },
            _ => ()
        }
    }

    /// Calculate the checksum of the packet and then set the field to the value
    /// calculated
    pub fn checksum(&mut self) {
        let checksum = self.calculate_checksum();
        self.set_checksum(checksum);
    }

}
<|endoftext|>


<commit_before>//! The parser functionality

use crate::bindings::*;
use crate::c_helpers::*;
use crate::tree::*;

use std::convert::AsRef;
use std::ffi::c_void;
use std::ffi::{CStr, CString};
use std::fmt;
use std::fs;
use std::io;
use std::os::raw::{c_char, c_int};
use std::ptr;
use std::slice;
use std::str;

enum XmlParserOption {
  Recover = 1, // Relaxed parsing
  // XML_PARSE_NODEFDTD = 4, // do not default a doctype if not found
  Noerror = 32, // suppress error reports
  Nowarning = 64, // suppress warning reports
                // XML_PARSE_PEDANTIC = 128, // pedantic error reporting
                // XML_PARSE_NOBLANKS = 256, // remove blank nodes
                // XML_PARSE_NONET = 2048, // Forbid network access
                // XML_PARSE_NOIMPLIED = 8192, // Do not add implied Xml/body... elements
                // XML_PARSE_COMPACT = 65536, // compact small text nodes
                // XML_PARSE_IGNORE_ENC = 2097152, // ignore internal document encoding hint
}

enum HtmlParserOption {
  Recover = 1, // Relaxed parsing
  // HTML_PARSE_NODEFDTD = 4, // do not default a doctype if not found
  Noerror = 32, // suppress error reports
  Nowarning = 64, // suppress warning reports
                // HTML_PARSE_PEDANTIC = 128, // pedantic error reporting
                // HTML_PARSE_NOBLANKS = 256, // remove blank nodes
                // HTML_PARSE_NONET = 2048, // Forbid network access
                // HTML_PARSE_NOIMPLIED = 8192, // Do not add implied html/body... elements
                // HTML_PARSE_COMPACT = 65536, // compact small text nodes
                // HTML_PARSE_IGNORE_ENC = 2097152, // ignore internal document encoding hint
}

///Parser Errors
pub enum XmlParseError {
  ///Parsing returned a null pointer as document pointer
  GotNullPointer,
  ///Could not open file error.
  FileOpenError,
  ///Document too large for libxml2.
  DocumentTooLarge,
}

impl fmt::Debug for XmlParseError {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      XmlParseError::GotNullPointer => write!(f, "Got a Null pointer"),
      XmlParseError::FileOpenError => write!(f, "Unable to open path to file."),
      XmlParseError::DocumentTooLarge => write!(f, "Document too large for i32."),
    }
  }
}

/// Default encoding when not provided.
const DEFAULT_ENCODING: *const c_char = ptr::null();

/// Default URL when not provided.
const DEFAULT_URL: *const c_char = ptr::null();

/// Open file function.
fn xml_open(filename: &str) -> io::Result<*mut c_void> {
  let ptr = Box::into_raw(Box::new(fs::File::open(filename)?));
  Ok(ptr as *mut c_void)
}

/// Read callback for an FS file.
unsafe extern "C" fn xml_read(context: *mut c_void, buffer: *mut c_char, len: c_int) -> c_int {
  // Len is always positive, typically 40-4000 bytes.
  let file = context as *mut fs::File;
  let buf = slice::from_raw_parts_mut(buffer as *mut u8, len as usize);
  match io::Read::read(&mut *file, buf) {
    Ok(v) => v as c_int,
    Err(_) => -1,
  }
}

type XmlReadCallback = unsafe extern "C" fn(*mut c_void, *mut c_char, c_int) -> c_int;

/// Close callback for an FS file.
unsafe extern "C" fn xml_close(context: *mut c_void) -> c_int {
  // Take rust ownership of the context and then drop it.
  let file = context as *mut fs::File;
  let _ = Box::from_raw(file);
  0
}

type XmlCloseCallback = unsafe extern "C" fn(*mut c_void) -> c_int;

///Convert usize to i32 safely.
fn try_usize_to_i32(value: usize) -> Result<i32, XmlParseError> {
  if cfg!(target_pointer_width = "16") || (value < i32::max_value() as usize) {
    // Cannot safely use our value comparison, but the conversion if always safe.
    // Or, if the value can be safely represented as a 32-bit signed integer.
    Ok(value as i32)
  } else {
    // Document too large, cannot parse using libxml2.
    Err(XmlParseError::DocumentTooLarge)
  }
}

#[derive(PartialEq)]
/// Enum for the parse formats supported by libxml2
pub enum ParseFormat {
  /// Strict parsing for XML
  XML,
  /// Relaxed parsing for HTML
  HTML,
}
/// Parsing API wrapper for libxml2
pub struct Parser {
  /// The `ParseFormat` for this parser
  pub format: ParseFormat,
}
impl Default for Parser {
  /// Create a parser for XML documents
  fn default() -> Self {
    Parser {
      format: ParseFormat::XML,
    }
  }
}
impl Parser {
  /// Create a parser for HTML documents
  pub fn default_html() -> Self {
    Parser {
      format: ParseFormat::HTML,
    }
  }

  /// Parses the XML/HTML file `filename` to generate a new `Document`
  pub fn parse_file(&self, filename: &str) -> Result<Document, XmlParseError> {
    self.parse_file_with_encoding(filename, None)
  }

  /// Parses the XML/HTML file `filename` with a manually-specified encoding
  /// to generate a new `Document`
  pub fn parse_file_with_encoding(
    &self,
    filename: &str,
    encoding: Option<&str>,
  ) -> Result<Document, XmlParseError> {
    // Create extern C callbacks for to read and close a Rust file through
    // a void pointer.
    let ioread: Option<XmlReadCallback> = Some(xml_read);
    let ioclose: Option<XmlCloseCallback> = Some(xml_close);
    let ioctx = match xml_open(filename) {
      Ok(v) => v,
      Err(_) => return Err(XmlParseError::FileOpenError),
    };

    // Process encoding.
    let encoding_cstring: Option<CString> = encoding.map(|v| CString::new(v).unwrap());
    let encoding_ptr = match encoding_cstring {
      Some(v) => v.as_ptr(),
      None => DEFAULT_ENCODING,
    };

    // Process url.
    let url_ptr = DEFAULT_URL;

    unsafe {
      xmlKeepBlanksDefault(1);
    }
    match self.format {
      ParseFormat::XML => {
        let options: i32 = XmlParserOption::Recover as i32
          + XmlParserOption::Noerror as i32
          + XmlParserOption::Nowarning as i32;
        unsafe {
          let doc_ptr = xmlReadIO(ioread, ioclose, ioctx, url_ptr, encoding_ptr, options);
          if doc_ptr.is_null() {
            Err(XmlParseError::GotNullPointer)
          } else {
            Ok(Document::new_ptr(doc_ptr))
          }
        }
      }
      ParseFormat::HTML => {
        // TODO: Allow user-specified options later on
        let options: i32 = HtmlParserOption::Recover as i32
          + HtmlParserOption::Noerror as i32
          + HtmlParserOption::Nowarning as i32;
        unsafe {
          let doc_ptr = htmlReadIO(ioread, ioclose, ioctx, url_ptr, encoding_ptr, options);
          if doc_ptr.is_null() {
            Err(XmlParseError::GotNullPointer)
          } else {
            Ok(Document::new_ptr(doc_ptr))
          }
        }
      }
    }
  }

  ///Parses the XML/HTML bytes `input` to generate a new `Document`
  pub fn parse_string<Bytes: AsRef<[u8]>>(&self, input: Bytes) -> Result<Document, XmlParseError> {
    self.parse_string_with_encoding(input, None)
  }

  ///Parses the XML/HTML bytes `input` with a manually-specified
  ///encoding to generate a new `Document`
  pub fn parse_string_with_encoding<Bytes: AsRef<[u8]>>(
    &self,
    input: Bytes,
    encoding: Option<&str>,
  ) -> Result<Document, XmlParseError> {
    // Process input bytes.
    let input_bytes = input.as_ref();
    let input_ptr = input_bytes.as_ptr() as *const c_char;
    let input_len = try_usize_to_i32(input_bytes.len())?;

    // Process encoding.
    let encoding_cstring: Option<CString> = encoding.map(|v| CString::new(v).unwrap());
    let encoding_ptr = match encoding_cstring {
      Some(v) => v.as_ptr(),
      None => DEFAULT_ENCODING,
    };

    // Process url.
    let url_ptr = DEFAULT_URL;
    match self.format {
      ParseFormat::XML => unsafe {
        let options: i32 = XmlParserOption::Recover as i32
          + XmlParserOption::Noerror as i32
          + XmlParserOption::Nowarning as i32;
        let docptr = xmlReadMemory(input_ptr, input_len, url_ptr, encoding_ptr, options);
        if docptr.is_null() {
          Err(XmlParseError::GotNullPointer)
        } else {
          Ok(Document::new_ptr(docptr))
        }
      },
      ParseFormat::HTML => unsafe {
        let options: i32 = HtmlParserOption::Recover as i32
          + HtmlParserOption::Noerror as i32
          + HtmlParserOption::Nowarning as i32;
        let docptr = htmlReadMemory(input_ptr, input_len, url_ptr, encoding_ptr, options);
        if docptr.is_null() {
          Err(XmlParseError::GotNullPointer)
        } else {
          Ok(Document::new_ptr(docptr))
        }
      },
    }
  }

  /// Checks a string for well-formedness.
  pub fn is_well_formed_html<Bytes: AsRef<[u8]>>(&self, input: Bytes) -> bool {
    self.is_well_formed_html_with_encoding(input, None)
  }

  /// Checks a string for well-formedness with manually-specified encoding.
  /// IMPORTANT: This function is currently implemented in a HACKY way, to ignore invalid errors for HTML5 elements (such as <math>)
  ///            this means you should NEVER USE IT WHILE THREADING, it is CERTAIN TO BREAK
  ///
  /// Help is welcome in implementing it correctly.
  pub fn is_well_formed_html_with_encoding<Bytes: AsRef<[u8]>>(
    &self,
    input: Bytes,
    encoding: Option<&str>,
  ) -> bool {
    // Process input string.
    let input_bytes = input.as_ref();
    if input_bytes.is_empty() {
      return false;
    }
    let input_ptr = input_bytes.as_ptr() as *const c_char;
    let input_len = match try_usize_to_i32(input_bytes.len()) {
      Ok(v) => v,
      Err(_) => return false,
    };

    // Process encoding.
    let encoding_cstring: Option<CString> = encoding.map(|v| CString::new(v).unwrap());
    let encoding_ptr = match encoding_cstring {
      Some(v) => v.as_ptr(),
      None => DEFAULT_ENCODING,
    };

    // Process url.
    let url_ptr = DEFAULT_URL;
    // disable generic error lines from libxml2
    match self.format {
      ParseFormat::XML => false, // TODO: Add support for XML at some point
      ParseFormat::HTML => unsafe {
        let ctxt = htmlNewParserCtxt();
        setWellFormednessHandler(ctxt);
        let docptr = htmlCtxtReadMemory(ctxt, input_ptr, input_len, url_ptr, encoding_ptr, 10_596); // htmlParserOption = 4+32+64+256+2048+8192
        let well_formed_final = if htmlWellFormed(ctxt) {
          // Basic well-formedness passes, let's check if we have an <html> element as root too
          if !docptr.is_null() {
            let node_ptr = xmlDocGetRootElement(docptr);
            let name_ptr = xmlNodeGetName(node_ptr);
            if name_ptr.is_null() {
              false
            }
            //empty string
            else {
              let c_root_name = CStr::from_ptr(name_ptr);
              let root_name = str::from_utf8(c_root_name.to_bytes()).unwrap().to_owned();
              root_name == "html"
            }
          } else {
            false
          }
        } else {
          false
        };

        if !ctxt.is_null() {
          htmlFreeParserCtxt(ctxt);
        }
        if !docptr.is_null() {
          xmlFreeDoc(docptr);
        }
        well_formed_final
      },
    }
  }
}
<commit_msg>Implements std Error trait impl for XmlParseError<commit_after>//! The parser functionality

use crate::bindings::*;
use crate::c_helpers::*;
use crate::tree::*;

use std::convert::AsRef;
use std::ffi::c_void;
use std::ffi::{CStr, CString};
use std::fmt;
use std::fs;
use std::io;
use std::os::raw::{c_char, c_int};
use std::ptr;
use std::error;
use std::slice;
use std::str;

use std::error::Error;

enum XmlParserOption {
  Recover = 1, // Relaxed parsing
  // XML_PARSE_NODEFDTD = 4, // do not default a doctype if not found
  Noerror = 32, // suppress error reports
  Nowarning = 64, // suppress warning reports
                // XML_PARSE_PEDANTIC = 128, // pedantic error reporting
                // XML_PARSE_NOBLANKS = 256, // remove blank nodes
                // XML_PARSE_NONET = 2048, // Forbid network access
                // XML_PARSE_NOIMPLIED = 8192, // Do not add implied Xml/body... elements
                // XML_PARSE_COMPACT = 65536, // compact small text nodes
                // XML_PARSE_IGNORE_ENC = 2097152, // ignore internal document encoding hint
}

enum HtmlParserOption {
  Recover = 1, // Relaxed parsing
  // HTML_PARSE_NODEFDTD = 4, // do not default a doctype if not found
  Noerror = 32, // suppress error reports
  Nowarning = 64, // suppress warning reports
                // HTML_PARSE_PEDANTIC = 128, // pedantic error reporting
                // HTML_PARSE_NOBLANKS = 256, // remove blank nodes
                // HTML_PARSE_NONET = 2048, // Forbid network access
                // HTML_PARSE_NOIMPLIED = 8192, // Do not add implied html/body... elements
                // HTML_PARSE_COMPACT = 65536, // compact small text nodes
                // HTML_PARSE_IGNORE_ENC = 2097152, // ignore internal document encoding hint
}

///Parser Errors
pub enum XmlParseError {
  ///Parsing returned a null pointer as document pointer
  GotNullPointer,
  ///Could not open file error.
  FileOpenError,
  ///Document too large for libxml2.
  DocumentTooLarge,
}

impl fmt::Debug for XmlParseError
{
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", self.description())
  }
}

impl fmt::Display for XmlParseError
{
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", self.description())
  }
}

impl error::Error for XmlParseError
{
  fn description(&self) -> &str {
    match self {
      XmlParseError::GotNullPointer   => "Got a Null pointer",
      XmlParseError::FileOpenError    => "Unable to open path to file.",
      XmlParseError::DocumentTooLarge => "Document too large for i32.",
    }
  }
}

/// Default encoding when not provided.
const DEFAULT_ENCODING: *const c_char = ptr::null();

/// Default URL when not provided.
const DEFAULT_URL: *const c_char = ptr::null();

/// Open file function.
fn xml_open(filename: &str) -> io::Result<*mut c_void> {
  let ptr = Box::into_raw(Box::new(fs::File::open(filename)?));
  Ok(ptr as *mut c_void)
}

/// Read callback for an FS file.
unsafe extern "C" fn xml_read(context: *mut c_void, buffer: *mut c_char, len: c_int) -> c_int {
  // Len is always positive, typically 40-4000 bytes.
  let file = context as *mut fs::File;
  let buf = slice::from_raw_parts_mut(buffer as *mut u8, len as usize);
  match io::Read::read(&mut *file, buf) {
    Ok(v) => v as c_int,
    Err(_) => -1,
  }
}

type XmlReadCallback = unsafe extern "C" fn(*mut c_void, *mut c_char, c_int) -> c_int;

/// Close callback for an FS file.
unsafe extern "C" fn xml_close(context: *mut c_void) -> c_int {
  // Take rust ownership of the context and then drop it.
  let file = context as *mut fs::File;
  let _ = Box::from_raw(file);
  0
}

type XmlCloseCallback = unsafe extern "C" fn(*mut c_void) -> c_int;

///Convert usize to i32 safely.
fn try_usize_to_i32(value: usize) -> Result<i32, XmlParseError> {
  if cfg!(target_pointer_width = "16") || (value < i32::max_value() as usize) {
    // Cannot safely use our value comparison, but the conversion if always safe.
    // Or, if the value can be safely represented as a 32-bit signed integer.
    Ok(value as i32)
  } else {
    // Document too large, cannot parse using libxml2.
    Err(XmlParseError::DocumentTooLarge)
  }
}

#[derive(PartialEq)]
/// Enum for the parse formats supported by libxml2
pub enum ParseFormat {
  /// Strict parsing for XML
  XML,
  /// Relaxed parsing for HTML
  HTML,
}
/// Parsing API wrapper for libxml2
pub struct Parser {
  /// The `ParseFormat` for this parser
  pub format: ParseFormat,
}
impl Default for Parser {
  /// Create a parser for XML documents
  fn default() -> Self {
    Parser {
      format: ParseFormat::XML,
    }
  }
}
impl Parser {
  /// Create a parser for HTML documents
  pub fn default_html() -> Self {
    Parser {
      format: ParseFormat::HTML,
    }
  }

  /// Parses the XML/HTML file `filename` to generate a new `Document`
  pub fn parse_file(&self, filename: &str) -> Result<Document, XmlParseError> {
    self.parse_file_with_encoding(filename, None)
  }

  /// Parses the XML/HTML file `filename` with a manually-specified encoding
  /// to generate a new `Document`
  pub fn parse_file_with_encoding(
    &self,
    filename: &str,
    encoding: Option<&str>,
  ) -> Result<Document, XmlParseError> {
    // Create extern C callbacks for to read and close a Rust file through
    // a void pointer.
    let ioread: Option<XmlReadCallback> = Some(xml_read);
    let ioclose: Option<XmlCloseCallback> = Some(xml_close);
    let ioctx = match xml_open(filename) {
      Ok(v) => v,
      Err(_) => return Err(XmlParseError::FileOpenError),
    };

    // Process encoding.
    let encoding_cstring: Option<CString> = encoding.map(|v| CString::new(v).unwrap());
    let encoding_ptr = match encoding_cstring {
      Some(v) => v.as_ptr(),
      None => DEFAULT_ENCODING,
    };

    // Process url.
    let url_ptr = DEFAULT_URL;

    unsafe {
      xmlKeepBlanksDefault(1);
    }
    match self.format {
      ParseFormat::XML => {
        let options: i32 = XmlParserOption::Recover as i32
          + XmlParserOption::Noerror as i32
          + XmlParserOption::Nowarning as i32;
        unsafe {
          let doc_ptr = xmlReadIO(ioread, ioclose, ioctx, url_ptr, encoding_ptr, options);
          if doc_ptr.is_null() {
            Err(XmlParseError::GotNullPointer)
          } else {
            Ok(Document::new_ptr(doc_ptr))
          }
        }
      }
      ParseFormat::HTML => {
        // TODO: Allow user-specified options later on
        let options: i32 = HtmlParserOption::Recover as i32
          + HtmlParserOption::Noerror as i32
          + HtmlParserOption::Nowarning as i32;
        unsafe {
          let doc_ptr = htmlReadIO(ioread, ioclose, ioctx, url_ptr, encoding_ptr, options);
          if doc_ptr.is_null() {
            Err(XmlParseError::GotNullPointer)
          } else {
            Ok(Document::new_ptr(doc_ptr))
          }
        }
      }
    }
  }

  ///Parses the XML/HTML bytes `input` to generate a new `Document`
  pub fn parse_string<Bytes: AsRef<[u8]>>(&self, input: Bytes) -> Result<Document, XmlParseError> {
    self.parse_string_with_encoding(input, None)
  }

  ///Parses the XML/HTML bytes `input` with a manually-specified
  ///encoding to generate a new `Document`
  pub fn parse_string_with_encoding<Bytes: AsRef<[u8]>>(
    &self,
    input: Bytes,
    encoding: Option<&str>,
  ) -> Result<Document, XmlParseError> {
    // Process input bytes.
    let input_bytes = input.as_ref();
    let input_ptr = input_bytes.as_ptr() as *const c_char;
    let input_len = try_usize_to_i32(input_bytes.len())?;

    // Process encoding.
    let encoding_cstring: Option<CString> = encoding.map(|v| CString::new(v).unwrap());
    let encoding_ptr = match encoding_cstring {
      Some(v) => v.as_ptr(),
      None => DEFAULT_ENCODING,
    };

    // Process url.
    let url_ptr = DEFAULT_URL;
    match self.format {
      ParseFormat::XML => unsafe {
        let options: i32 = XmlParserOption::Recover as i32
          + XmlParserOption::Noerror as i32
          + XmlParserOption::Nowarning as i32;
        let docptr = xmlReadMemory(input_ptr, input_len, url_ptr, encoding_ptr, options);
        if docptr.is_null() {
          Err(XmlParseError::GotNullPointer)
        } else {
          Ok(Document::new_ptr(docptr))
        }
      },
      ParseFormat::HTML => unsafe {
        let options: i32 = HtmlParserOption::Recover as i32
          + HtmlParserOption::Noerror as i32
          + HtmlParserOption::Nowarning as i32;
        let docptr = htmlReadMemory(input_ptr, input_len, url_ptr, encoding_ptr, options);
        if docptr.is_null() {
          Err(XmlParseError::GotNullPointer)
        } else {
          Ok(Document::new_ptr(docptr))
        }
      },
    }
  }

  /// Checks a string for well-formedness.
  pub fn is_well_formed_html<Bytes: AsRef<[u8]>>(&self, input: Bytes) -> bool {
    self.is_well_formed_html_with_encoding(input, None)
  }

  /// Checks a string for well-formedness with manually-specified encoding.
  /// IMPORTANT: This function is currently implemented in a HACKY way, to ignore invalid errors for HTML5 elements (such as <math>)
  ///            this means you should NEVER USE IT WHILE THREADING, it is CERTAIN TO BREAK
  ///
  /// Help is welcome in implementing it correctly.
  pub fn is_well_formed_html_with_encoding<Bytes: AsRef<[u8]>>(
    &self,
    input: Bytes,
    encoding: Option<&str>,
  ) -> bool {
    // Process input string.
    let input_bytes = input.as_ref();
    if input_bytes.is_empty() {
      return false;
    }
    let input_ptr = input_bytes.as_ptr() as *const c_char;
    let input_len = match try_usize_to_i32(input_bytes.len()) {
      Ok(v) => v,
      Err(_) => return false,
    };

    // Process encoding.
    let encoding_cstring: Option<CString> = encoding.map(|v| CString::new(v).unwrap());
    let encoding_ptr = match encoding_cstring {
      Some(v) => v.as_ptr(),
      None => DEFAULT_ENCODING,
    };

    // Process url.
    let url_ptr = DEFAULT_URL;
    // disable generic error lines from libxml2
    match self.format {
      ParseFormat::XML => false, // TODO: Add support for XML at some point
      ParseFormat::HTML => unsafe {
        let ctxt = htmlNewParserCtxt();
        setWellFormednessHandler(ctxt);
        let docptr = htmlCtxtReadMemory(ctxt, input_ptr, input_len, url_ptr, encoding_ptr, 10_596); // htmlParserOption = 4+32+64+256+2048+8192
        let well_formed_final = if htmlWellFormed(ctxt) {
          // Basic well-formedness passes, let's check if we have an <html> element as root too
          if !docptr.is_null() {
            let node_ptr = xmlDocGetRootElement(docptr);
            let name_ptr = xmlNodeGetName(node_ptr);
            if name_ptr.is_null() {
              false
            }
            //empty string
            else {
              let c_root_name = CStr::from_ptr(name_ptr);
              let root_name = str::from_utf8(c_root_name.to_bytes()).unwrap().to_owned();
              root_name == "html"
            }
          } else {
            false
          }
        } else {
          false
        };

        if !ctxt.is_null() {
          htmlFreeParserCtxt(ctxt);
        }
        if !docptr.is_null() {
          xmlFreeDoc(docptr);
        }
        well_formed_final
      },
    }
  }
}
<|endoftext|>


<commit_before>///
/// Description: Parse soruce code, returning a vector of bytes representing the compiled program
///

use std::hashmap::HashMap;
use parser::trans::MarkerId;
use parser::trans::VarId;

mod lexer;
mod trans;
mod asm;

#[deriving(Eq)]
enum BlockType {
    IfBlock,
    LoopBlock,
    FunctionBlock,
}

struct MarkerStack {
    priv markers: ~[(BlockType, MarkerId)],
    last_marker: MarkerId
}

impl MarkerStack {
    fn new() -> MarkerStack {
        MarkerStack {
            markers: ~[],
            last_marker: 0
        }
    }

    /// Add a new marker to the marker stack
    fn push(&mut self, block_type: BlockType) {
        self.markers.push((block_type, self.last_marker));
        self.last_marker += 1;
    }

    /// Pop the last marker added
    fn pop(&mut self) -> (BlockType, MarkerId) {
        self.markers.pop()
    }

    /// Find the top most marker of the specified type
    fn find_type(&mut self, block_type: BlockType) -> Option<MarkerId> {
        self.markers.rev_iter().find(|& &(btype, _)| btype == block_type).map(|&(_, id)| id)
    }
}

static SYSTEM_CALLS: [&'static str, ..8] = [
    "__clear", "__draw_pos", "__set_addr", "__draw", "__random", "__set_delay",
    "__get_font", "__key_wait"
];

struct Parser {
    variables: HashMap<~str, VarId>,
    var_index: VarId,
    marker_stack: MarkerStack,
    code: ~[lexer::Token],
    pos: uint,
}

pub fn parse(source_code: &str) -> ~[u8] {
    let mut parser = Parser {
        variables: HashMap::new(),
        var_index: 0,
        marker_stack: MarkerStack::new(),
        code: lexer::Lexer::new(source_code).collect(),
        pos: 0,
    };
    println!("{:?}\n", parser.code);
    let ops = trans::block_to_asm(parser.parse_block(FunctionBlock));
    for op in ops.iter() {
        println!("{:?}", op);
    }
    println!("");
    asm::compile(ops, parser.marker_stack.last_marker)
}

impl Parser {
    fn parse_block(&mut self, block_type: BlockType) -> trans::Block {
        let mut statements = ~[];
        self.marker_stack.push(block_type);
        self.marker_stack.push(block_type);
        // Parse the block
        match self.code[self.pos].clone() {
            lexer::LeftBrace => {
                self.pos += 1;
                // Loop through all the statements in the block
                loop {
                    match self.code[self.pos].clone() {
                        lexer::RightBrace => break,
                        _ => statements.push(self.parse_statement()),
                    }
                }
            },
            xx => fail!("Error: expected `LeftBrace` but found `{:?}`", xx)
        }
        self.pos += 1;
        // Get the block markers
        let (_, end_id) = self.marker_stack.pop();
        let (_, start_id) = self.marker_stack.pop();
        trans::Block {
            statements: statements,
            start_id: start_id,
            end_id: end_id,
        }
    }

    fn parse_statement(&mut self) -> trans::Statement {
        match self.code[self.pos].clone() {
            lexer::Let => self.parse_let(),
            lexer::If => self.parse_if(),
            lexer::For => fail!("ICE: Unimplemented"),
            lexer::While => fail!("ICE: Unimplemented"),
            lexer::Fn => fail!("ICE: Unimplemented"),
            lexer::Loop => self.parse_loop(),
            lexer::Break => self.parse_break(),
            lexer::Ident(ref s) => self.parse_ident_statement(s),
            xx => fail!("Unexpected token found: `{:?}`", xx)
        }
    }

    fn parse_let(&mut self) -> trans::Statement {
        self.pos += 1;
        // Determine the variables name
        let var_name = match self.code[self.pos].clone() {
            lexer::Ident(ref s) => s.clone(),
            xx => fail!("Error: expected `Ident` but found `{:?}`", xx)
        };
        // Check if variable is already defined
        if SYSTEM_CALLS.iter().any(|&x| x == var_name) {
            fail!("Error: `{}` is a system command");
        }
        if self.variables.contains_key(&var_name) {
            fail!("Error: Shadowing is unsupported. (`{}` was already defined)", var_name);
        }
        // Add the variable to the variable list
        self.variables.insert(var_name.clone(), self.var_index);
        self.var_index += 1;
        self.pos += 1;
        // Check if we are assigning to the variable
        match self.code[self.pos].clone() {
            lexer::Assignment => {
                self.pos += 1;
                // Parse the assignment
                self.parse_assignment(self.var_index-1)
            },
            lexer::StatementEnd => {
                self.pos += 1;
                // Variable declaration without assignment is a NOP
                trans::Nop
            },
            xx => fail!("Error: expected `Assignment` or `StatementEnd` but found `{:?}`", xx),
        }
    }

    fn parse_assignment(&mut self, var_id: VarId) -> trans::Statement {
        // Parse the rhs expression
        let expr = self.parse_expression();
        // Check for statement end
        match self.code[self.pos].clone() {
            lexer::StatementEnd => {},
            xx => fail!("Error: expected `StatementEnd` but found `{:?}`", xx)
        }
        self.pos += 1;
        trans::Assignment(var_id, expr)
    }

    fn parse_if(&mut self) -> trans::Statement {
        self.pos += 1;
        // Parse the condition
        let condition_expr = self.parse_expression();
        // Parse the if block
        let if_block = self.parse_block(IfBlock);
        // Parse the else block
        let else_block = match self.code[self.pos].clone() {
            lexer::Else => {
                self.pos += 1;
                self.parse_block(IfBlock)
            },
            _ => {
                // Create a blank block if the else block was not specified
                self.marker_stack.last_marker += 2;
                trans::Block {
                    statements: ~[],
                    start_id: self.marker_stack.last_marker-2,
                    end_id: self.marker_stack.last_marker-1,
                }
            }
        };
        trans::If(condition_expr, if_block, else_block)
    }

    fn parse_loop(&mut self) -> trans::Statement {
        self.pos += 1;
        let mut loop_block = self.parse_block(LoopBlock);
        // Add the jump back to the start of the loop
        loop_block.statements.push(trans::Jump(loop_block.start_id));
        trans::Loop(loop_block)
    }

    fn parse_break(&mut self) -> trans::Statement {
        let jump_id = match self.marker_stack.find_type(LoopBlock) {
            Some(id) => id,
            None => fail!("Error: `Break` is not valid here.")
        };

        self.pos += 1;
        match self.code[self.pos].clone() {
            lexer::StatementEnd => {
                self.pos += 1;
                trans::Jump(jump_id)
            },
            xx => fail!("Error: expected `StatementEnd` but found `{:?}`", xx),
        }
    }

    fn parse_expression(&mut self) -> trans::Expression {
        let mut current_expr = None;
        loop {
            current_expr = match self.code[self.pos].clone() {
                lexer::Ident(ref s) => {
                    Some(trans::Variable(self.get_variable(s)))
                },
                lexer::LitNum(n) => {
                    self.pos += 1;
                    Some(trans::LitNum(n as u8))
                },
                lexer::Plus => Some(self.parse_operator(current_expr, trans::Plus)),
                lexer::Minus => Some(self.parse_operator(current_expr, trans::Minus)),
                _ => break,
            };
        }
        // Return the expression if there was one
        match current_expr {
            Some(expr) => expr,
            None => fail!("Error: expected expression")
        }
    }

    fn parse_operator(&mut self,
            lhs: Option<trans::Expression>,
            operator: trans::Operator) -> trans::Expression {
        // Check that there is a valid lhs expression
        let lhs = match lhs {
            Some(expr) => expr,
            None => fail!("Error: invalid LHS operand"),
        };
        self.pos += 1;
        // Parse the rhs expression
        let rhs = self.parse_expression();
        trans::OperatorExpr(~rhs, operator, ~lhs)
    }

    fn parse_ident_statement(&mut self, name: &~str) -> trans::Statement {
        // Check if the identifier was a system call
        match SYSTEM_CALLS.iter().find(|& &x| x == *name) {
            Some(&n) => {
                self.pos += 1;
                return trans::CallSys(match n {
                    "__clear"     => self.parse_syscall_clear(),
                    "__draw_pos"  => self.parse_syscall_draw_pos(),
                    "__set_addr"  => fail!("Unimplemented"),
                    "__draw"      => self.parse_syscall_draw(),
                    "__random"    => fail!("Unimplemented"),
                    "__set_delay" => fail!("Unimplemented"),
                    "__get_font"  => self.parse_syscall_get_font(),
                    "__key_wait"  => self.parse_syscall_key_wait(),

                    _ => fail!("Unreachable")
                });
            },
            None => {}
        }

        // Check if the identifier is a variable
        match self.variables.find(name) {
            Some(&var_id) => {
                self.pos += 1;
                match self.code[self.pos].clone() {
                    // If the identifier was a variable, then there should be an assignment
                    lexer::Assignment => {
                        self.pos += 1;
                        return self.parse_assignment(var_id);
                    },
                    xx => fail!("Error: expected `Assignment` but found `{:?}`", xx)
                }
            },
            None => {}
        }

        fail!("Error: `{}` is undefined", *name);
    }

    fn parse_syscall_clear(&mut self) -> trans::SysCall {
        if self.code[self.pos].clone() != lexer::LeftParen {
            fail!("Expected `LeftParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        if self.code[self.pos].clone() != lexer::RightParen {
            fail!("Expected `RightParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        if self.code[self.pos].clone() != lexer::StatementEnd {
            fail!("Expected `StatementEnd` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        trans::Clear
    }

    fn parse_syscall_draw_pos(&mut self) -> trans::SysCall {
        if self.code[self.pos].clone() != lexer::LeftParen {
            fail!("Expected `LeftParen` but found `{:?}`", self.code[self.pos]);
        }
        self.pos += 1;
        let x_expr = self.parse_expression();
        if self.code[self.pos].clone() != lexer::Comma {
            fail!("Expected `Comma` but found `{:?}`", self.code[self.pos]);
        }
        self.pos += 1;
        let y_expr = self.parse_expression();
        if self.code[self.pos].clone() != lexer::RightParen {
            fail!("Expected `RightParen` but found `{:?}`", self.code[self.pos]);
        }
        self.pos += 1;
        if self.code[self.pos].clone() != lexer::StatementEnd {
            fail!("Expected `StatementEnd` but found `{:?}`", self.code[self.pos]);
        }
        self.pos += 1;
        trans::DrawPos(x_expr, y_expr)
    }

    fn parse_syscall_draw(&mut self) -> trans::SysCall {
        if self.code[self.pos].clone() != lexer::LeftParen {
            fail!("Expected `LeftParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        let command = match self.code[self.pos].clone() {
            lexer::LitNum(n) => {
                assert!(n < 0x10);
                trans::Draw(n as u8)
            },
            xx => fail!("Expected `LitNum` but found `{:?}`", xx)
        };
        self.pos += 1;
        if self.code[self.pos].clone() != lexer::RightParen {
            fail!("Expected `RightParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        if self.code[self.pos].clone() != lexer::StatementEnd {
            fail!("Expected `StatementEnd` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        command
    }

    fn parse_syscall_get_font(&mut self) -> trans::SysCall {
        if self.code[self.pos].clone() != lexer::LeftParen {
            fail!("Expected `LeftParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        let expr = self.parse_expression();
        if self.code[self.pos].clone() != lexer::RightParen {
            fail!("Expected `RightParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        if self.code[self.pos].clone() != lexer::StatementEnd {
            fail!("Expected `StatementEnd` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        trans::GetFont(expr)
    }

    fn parse_syscall_key_wait(&mut self) -> trans::SysCall {
        if self.code[self.pos].clone() != lexer::LeftParen {
            fail!("Expected `LeftParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        let expr = self.parse_expression();
        if self.code[self.pos].clone() != lexer::RightParen {
            fail!("Expected `RightParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        if self.code[self.pos].clone() != lexer::StatementEnd {
            fail!("Expected `StatementEnd` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        trans::KeyWait(expr)
    }

    /// Returns the id of a variable name
    fn get_variable(&mut self, var_name: &~str) -> VarId {
        let var_id = match self.variables.find(var_name) {
            Some(id) => id,
            None => fail!("Error: `{}` is undefined", *var_name)
        };
        self.pos += 1;
        *var_id
    }
}
<commit_msg>Handle statement endings a bit better<commit_after>///
/// Description: Parse soruce code, returning a vector of bytes representing the compiled program
///

use std::hashmap::HashMap;
use parser::trans::MarkerId;
use parser::trans::VarId;

mod lexer;
mod trans;
mod asm;

#[deriving(Eq)]
enum BlockType {
    IfBlock,
    LoopBlock,
    FunctionBlock,
}

struct MarkerStack {
    priv markers: ~[(BlockType, MarkerId)],
    last_marker: MarkerId
}

impl MarkerStack {
    fn new() -> MarkerStack {
        MarkerStack {
            markers: ~[],
            last_marker: 0
        }
    }

    /// Add a new marker to the marker stack
    fn push(&mut self, block_type: BlockType) {
        self.markers.push((block_type, self.last_marker));
        self.last_marker += 1;
    }

    /// Pop the last marker added
    fn pop(&mut self) -> (BlockType, MarkerId) {
        self.markers.pop()
    }

    /// Find the top most marker of the specified type
    fn find_type(&mut self, block_type: BlockType) -> Option<MarkerId> {
        self.markers.rev_iter().find(|& &(btype, _)| btype == block_type).map(|&(_, id)| id)
    }
}

static SYSTEM_CALLS: [&'static str, ..8] = [
    "__clear", "__draw_pos", "__set_addr", "__draw", "__random", "__set_delay",
    "__get_font", "__key_wait"
];

struct Parser {
    variables: HashMap<~str, VarId>,
    var_index: VarId,
    marker_stack: MarkerStack,
    code: ~[lexer::Token],
    pos: uint,
}

pub fn parse(source_code: &str) -> ~[u8] {
    let mut parser = Parser {
        variables: HashMap::new(),
        var_index: 0,
        marker_stack: MarkerStack::new(),
        code: lexer::Lexer::new(source_code).collect(),
        pos: 0,
    };
    println!("{:?}\n", parser.code);
    let ops = trans::block_to_asm(parser.parse_block(FunctionBlock));
    for op in ops.iter() {
        println!("{:?}", op);
    }
    println!("");
    asm::compile(ops, parser.marker_stack.last_marker)
}

impl Parser {
    fn parse_block(&mut self, block_type: BlockType) -> trans::Block {
        let mut statements = ~[];
        self.marker_stack.push(block_type);
        self.marker_stack.push(block_type);
        // Parse the block
        match self.code[self.pos].clone() {
            lexer::LeftBrace => {
                self.pos += 1;
                // Loop through all the statements in the block
                loop {
                    match self.code[self.pos].clone() {
                        lexer::RightBrace => break,
                        _ => statements.push(self.parse_statement()),
                    }
                }
            },
            xx => fail!("Error: expected `LeftBrace` but found `{:?}`", xx)
        }
        self.pos += 1;
        // Get the block markers
        let (_, end_id) = self.marker_stack.pop();
        let (_, start_id) = self.marker_stack.pop();
        trans::Block {
            statements: statements,
            start_id: start_id,
            end_id: end_id,
        }
    }

    fn parse_statement(&mut self) -> trans::Statement {
        match self.code[self.pos].clone() {
            lexer::Let => self.parse_let(),
            lexer::If => self.parse_if(),
            lexer::For => fail!("ICE: Unimplemented"),
            lexer::While => fail!("ICE: Unimplemented"),
            lexer::Fn => fail!("ICE: Unimplemented"),
            lexer::Loop => self.parse_loop(),
            lexer::Break => self.parse_break(),
            lexer::Ident(ref s) => self.parse_ident_statement(s),
            xx => fail!("Unexpected token found: `{:?}`", xx)
        }
    }

    fn parse_statement_end(&mut self) {
        match self.code[self.pos].clone() {
            lexer::StatementEnd => self.pos += 1,
            xx => fail!("Error: expected `StatementEnd` but found `{:?}`", xx)
        }
    }

    fn parse_let(&mut self) -> trans::Statement {
        self.pos += 1;
        // Determine the variables name
        let var_name = match self.code[self.pos].clone() {
            lexer::Ident(ref s) => s.clone(),
            xx => fail!("Error: expected `Ident` but found `{:?}`", xx)
        };
        // Check if variable is already defined
        if SYSTEM_CALLS.iter().any(|&x| x == var_name) {
            fail!("Error: `{}` is a system command");
        }
        if self.variables.contains_key(&var_name) {
            fail!("Error: Shadowing is unsupported. (`{}` was already defined)", var_name);
        }
        // Add the variable to the variable list
        self.variables.insert(var_name.clone(), self.var_index);
        self.var_index += 1;
        self.pos += 1;
        // Check if we are assigning to the variable
        match self.code[self.pos].clone() {
            lexer::Assignment => {
                self.pos += 1;
                // Parse the assignment
                self.parse_assignment(self.var_index-1)
            },
            _ => {
                self.parse_statement_end();
                // Variable declaration without assignment is a NOP
                trans::Nop
            },
        }
    }

    fn parse_assignment(&mut self, var_id: VarId) -> trans::Statement {
        // Parse the rhs expression
        let expr = self.parse_expression();
        self.parse_statement_end();
        trans::Assignment(var_id, expr)
    }

    fn parse_if(&mut self) -> trans::Statement {
        self.pos += 1;
        // Parse the condition
        let condition_expr = self.parse_expression();
        // Parse the if block
        let if_block = self.parse_block(IfBlock);
        // Parse the else block
        let else_block = match self.code[self.pos].clone() {
            lexer::Else => {
                self.pos += 1;
                self.parse_block(IfBlock)
            },
            _ => {
                // Create a blank block if the else block was not specified
                self.marker_stack.last_marker += 2;
                trans::Block {
                    statements: ~[],
                    start_id: self.marker_stack.last_marker-2,
                    end_id: self.marker_stack.last_marker-1,
                }
            }
        };
        trans::If(condition_expr, if_block, else_block)
    }

    fn parse_loop(&mut self) -> trans::Statement {
        self.pos += 1;
        let mut loop_block = self.parse_block(LoopBlock);
        // Add the jump back to the start of the loop
        loop_block.statements.push(trans::Jump(loop_block.start_id));
        trans::Loop(loop_block)
    }

    fn parse_break(&mut self) -> trans::Statement {
        let jump_id = match self.marker_stack.find_type(LoopBlock) {
            Some(id) => id,
            None => fail!("Error: `Break` is not valid here.")
        };

        self.pos += 1;

        self.parse_statement_end();
        trans::Jump(jump_id)
    }

    fn parse_expression(&mut self) -> trans::Expression {
        let mut current_expr = None;
        loop {
            current_expr = match self.code[self.pos].clone() {
                lexer::Ident(ref s) => {
                    Some(trans::Variable(self.get_variable(s)))
                },
                lexer::LitNum(n) => {
                    self.pos += 1;
                    Some(trans::LitNum(n as u8))
                },
                lexer::Plus => Some(self.parse_operator(current_expr, trans::Plus)),
                lexer::Minus => Some(self.parse_operator(current_expr, trans::Minus)),
                _ => break,
            };
        }
        // Return the expression if there was one
        match current_expr {
            Some(expr) => expr,
            None => fail!("Error: expected expression")
        }
    }

    fn parse_operator(&mut self,
            lhs: Option<trans::Expression>,
            operator: trans::Operator) -> trans::Expression {
        // Check that there is a valid lhs expression
        let lhs = match lhs {
            Some(expr) => expr,
            None => fail!("Error: invalid LHS operand"),
        };
        self.pos += 1;
        // Parse the rhs expression
        let rhs = self.parse_expression();
        trans::OperatorExpr(~rhs, operator, ~lhs)
    }

    fn parse_ident_statement(&mut self, name: &~str) -> trans::Statement {
        // Check if the identifier was a system call
        match SYSTEM_CALLS.iter().find(|& &x| x == *name) {
            Some(&n) => {
                self.pos += 1;
                return trans::CallSys(match n {
                    "__clear"     => self.parse_syscall_clear(),
                    "__draw_pos"  => self.parse_syscall_draw_pos(),
                    "__set_addr"  => fail!("Unimplemented"),
                    "__draw"      => self.parse_syscall_draw(),
                    "__random"    => fail!("Unimplemented"),
                    "__set_delay" => fail!("Unimplemented"),
                    "__get_font"  => self.parse_syscall_get_font(),
                    "__key_wait"  => self.parse_syscall_key_wait(),

                    _ => fail!("Unreachable")
                });
            },
            None => {}
        }

        // Check if the identifier is a variable
        match self.variables.find(name) {
            Some(&var_id) => {
                self.pos += 1;
                match self.code[self.pos].clone() {
                    // If the identifier was a variable, then there should be an assignment
                    lexer::Assignment => {
                        self.pos += 1;
                        return self.parse_assignment(var_id);
                    },
                    xx => fail!("Error: expected `Assignment` but found `{:?}`", xx)
                }
            },
            None => {}
        }

        fail!("Error: `{}` is undefined", *name);
    }

    fn parse_syscall_clear(&mut self) -> trans::SysCall {
        if self.code[self.pos].clone() != lexer::LeftParen {
            fail!("Expected `LeftParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        if self.code[self.pos].clone() != lexer::RightParen {
            fail!("Expected `RightParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        if self.code[self.pos].clone() != lexer::StatementEnd {
            fail!("Expected `StatementEnd` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        trans::Clear
    }

    fn parse_syscall_draw_pos(&mut self) -> trans::SysCall {
        if self.code[self.pos].clone() != lexer::LeftParen {
            fail!("Expected `LeftParen` but found `{:?}`", self.code[self.pos]);
        }
        self.pos += 1;
        let x_expr = self.parse_expression();
        if self.code[self.pos].clone() != lexer::Comma {
            fail!("Expected `Comma` but found `{:?}`", self.code[self.pos]);
        }
        self.pos += 1;
        let y_expr = self.parse_expression();
        if self.code[self.pos].clone() != lexer::RightParen {
            fail!("Expected `RightParen` but found `{:?}`", self.code[self.pos]);
        }
        self.pos += 1;
        self.parse_statement_end();
        trans::DrawPos(x_expr, y_expr)
    }

    fn parse_syscall_draw(&mut self) -> trans::SysCall {
        if self.code[self.pos].clone() != lexer::LeftParen {
            fail!("Expected `LeftParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        let command = match self.code[self.pos].clone() {
            lexer::LitNum(n) => {
                assert!(n < 0x10);
                trans::Draw(n as u8)
            },
            xx => fail!("Expected `LitNum` but found `{:?}`", xx)
        };
        self.pos += 1;
        if self.code[self.pos].clone() != lexer::RightParen {
            fail!("Expected `RightParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        self.parse_statement_end();
        command
    }

    fn parse_syscall_get_font(&mut self) -> trans::SysCall {
        if self.code[self.pos].clone() != lexer::LeftParen {
            fail!("Expected `LeftParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        let expr = self.parse_expression();
        if self.code[self.pos].clone() != lexer::RightParen {
            fail!("Expected `RightParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        self.parse_statement_end();
        trans::GetFont(expr)
    }

    fn parse_syscall_key_wait(&mut self) -> trans::SysCall {
        if self.code[self.pos].clone() != lexer::LeftParen {
            fail!("Expected `LeftParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        let expr = self.parse_expression();
        if self.code[self.pos].clone() != lexer::RightParen {
            fail!("Expected `RightParen` but found {:?}", self.code[self.pos]);
        }
        self.pos += 1;
        self.parse_statement_end();
        trans::KeyWait(expr)
    }

    /// Returns the id of a variable name
    fn get_variable(&mut self, var_name: &~str) -> VarId {
        let var_id = match self.variables.find(var_name) {
            Some(id) => id,
            None => fail!("Error: `{}` is undefined", *var_name)
        };
        self.pos += 1;
        *var_id
    }
}
<|endoftext|>


<commit_before>use regex::Regex;
use collections::BTreeMap;
use serialize::json::{Json, ToJson};
use url::percent_encoding::lossy_utf8_percent_decode;

use merge::merge;
use helpers::{create_array, push_item_to_array};

static PARENT_REGEX: Regex = regex!(r"^([^][]+)");
static CHILD_REGEX: Regex = regex!(r"(\[[^][]*\])");

#[derive(Debug)]
#[allow(missing_copy_implementations)]
pub enum ParseErrorKind {
    DecodingError,
    Other
}

#[derive(Debug)]
pub struct ParseError {
    pub kind: ParseErrorKind,
    pub message: String
}

pub type ParseResult<T> = Result<T,ParseError>;

pub fn decode_component(source: &str) -> Result<String,String> {
    return Ok(lossy_utf8_percent_decode(source.as_bytes()));
}

fn parse_pairs(body: &str) -> Vec<(&str, Option<&str>)> {

    let mut pairs = vec![];

    for part in body.split_str("&") {
        let separator = part.find_str("]=")
                            .and_then(|pos| Some(pos+1))
                            .or_else(|| part.find_str("="));

        match separator {
            None => pairs.push((part, None)),
            Some(pos) => {
                let key = &part[..pos];
                let val = &part[(pos + 1)..];
                pairs.push((key, Some(val)));
            }
        }
    }

    return pairs
}

fn parse_key(key: &str) -> ParseResult<Vec<String>> {
    let mut keys: Vec<String> = vec![];

    match PARENT_REGEX.captures(key) {
        Some(captures) => {
            match decode_component(captures.at(1).unwrap()) {
                Ok(decoded_key) => keys.push(decoded_key),
                Err(err_msg) => return Err(ParseError{ kind: ParseErrorKind::DecodingError, message: err_msg })
            }
        }
        None => ()
    };

    for captures in CHILD_REGEX.captures_iter(key) {
        match decode_component(captures.at(1).unwrap()) {
            Ok(decoded_key) => keys.push(decoded_key),
            Err(err_msg) => return Err(ParseError{ kind: ParseErrorKind::DecodingError, message: err_msg })
        }
    }

    Ok(keys)
}

fn cleanup_key(key: &str) -> &str {
    if key.starts_with("[") && key.ends_with("]") {
        key.slice_chars(1, key.len()-1)
    } else {
        key
    }
}

fn create_idx_merger(idx: usize, obj: Json) -> Json {
    let mut tree: BTreeMap<String,Json> = BTreeMap::new();
    tree.insert("__idx".to_string(), idx.to_json());
    tree.insert("__object".to_string(), obj);
    return Json::Object(tree)
}

fn create_object_with_key(key: String, obj: Json) -> Json {
    let mut tree: BTreeMap<String,Json> = BTreeMap::new();
    tree.insert(key, obj);
    return Json::Object(tree)
}

fn apply_object(keys: &[String], val: Json) -> Json {

    if keys.len() > 0 {
        let key = keys.get(0).unwrap();
        if key.as_slice() == "[]" {
            let mut new_array = create_array();
            let item = apply_object(keys.tail(), val);
            push_item_to_array(&mut new_array, item);
            return new_array;
        } else {
            let key = cleanup_key(key.as_slice());
            let array_index = key.parse();

            match array_index {
                Ok(idx) => {
                    let result = apply_object(keys.tail(), val);
                    let item = create_idx_merger(idx, result);
                    return item;
                },
                Err(_) => {
                    return create_object_with_key(key.to_string(), apply_object(keys.tail(), val));
                }
            }
        }

    } else {
        return val;
    }
}

pub fn parse(params: &str) -> ParseResult<Json> {
    let tree: BTreeMap<String,Json> = BTreeMap::new();
    let mut obj = tree.to_json();
    let pairs = parse_pairs(params);
    for &(key, value) in pairs.iter() {
        let parse_key_res = try!(parse_key(key));
        let key_chain = &parse_key_res[0..];
        let decoded_value = match decode_component(value.unwrap_or("")) {
            Ok(val) => val,
            Err(err) => return Err(ParseError{ kind: ParseErrorKind::DecodingError, message: err })
        };
        let partial = apply_object(key_chain, decoded_value.to_json());
        merge(&mut obj, &partial);
    }

    Ok(obj)
}

#[test]
fn it_parses_simple_string() {
    assert_eq!(parse("0=foo").ok().unwrap().to_string(), r#"{"0":"foo"}"#.to_string());
    assert_eq!(parse("a[<=>]==23").ok().unwrap().to_string(), r#"{"a":{"<=>":"=23"}}"#.to_string());
    assert_eq!(parse(" foo = bar = baz ").ok().unwrap().to_string(), r#"{" foo ":" bar = baz "}"#.to_string());
}

#[test]
fn it_parses_nested_string() {
    assert_eq!(parse("a[b][c][d][e][f][g][h]=i").ok().unwrap().to_string(),
        r#"{"a":{"b":{"c":{"d":{"e":{"f":{"g":{"h":"i"}}}}}}}}"#.to_string())
}

#[test]
fn it_parses_simple_array() {
    assert_eq!(parse("a=b&a=c&a=d&a=e").ok().unwrap().to_string(),
        r#"{"a":["b","c","d","e"]}"#.to_string())
}

#[test]
fn it_parses_explicit_array() {
    assert_eq!(parse("a[]=b&a[]=c&a[]=d").ok().unwrap().to_string(),
        r#"{"a":["b","c","d"]}"#.to_string())
}

#[test]
fn it_parses_nested_array() {
    assert_eq!(parse("a[b][]=c&a[b][]=d").ok().unwrap().to_string(),
        r#"{"a":{"b":["c","d"]}}"#.to_string())
}

#[test]
fn it_allows_to_specify_array_indexes() {
    assert_eq!(parse("a[0][]=c&a[1][]=d").ok().unwrap().to_string(),
        r#"{"a":[["c"],["d"]]}"#.to_string())
}

#[test]
fn it_transforms_arrays_to_object() {
    assert_eq!(parse("foo[0]=bar&foo[bad]=baz").ok().unwrap().to_string(),
        r#"{"foo":{"0":"bar","bad":"baz"}}"#.to_string());

    assert_eq!(parse("foo[0][a]=a&foo[0][b]=b&foo[1][a]=aa&foo[1][b]=bb").ok().unwrap().to_string(),
        r#"{"foo":[{"a":"a","b":"b"},{"a":"aa","b":"bb"}]}"#.to_string());
}

#[test]
fn it_doesnt_produce_empty_keys() {
    assert_eq!(parse("_r=1&").ok().unwrap().to_string(),
        r#"{"_r":"1"}"#.to_string());
}

#[test]
fn it_supports_encoded_strings() {
    assert_eq!(parse("a[b%20c]=c%20d").ok().unwrap().to_string(),
        r#"{"a":{"b c":"c d"}}"#.to_string());
}
<commit_msg>refactor(lib): rustup<commit_after>use regex::Regex;
use collections::BTreeMap;
use serialize::json::{Json, ToJson};
use url::percent_encoding::lossy_utf8_percent_decode;

use merge::merge;
use helpers::{create_array, push_item_to_array};

static PARENT_REGEX: Regex = regex!(r"^([^][]+)");
static CHILD_REGEX: Regex = regex!(r"(\[[^][]*\])");

#[derive(Debug)]
#[allow(missing_copy_implementations)]
pub enum ParseErrorKind {
    DecodingError,
    Other
}

#[derive(Debug)]
pub struct ParseError {
    pub kind: ParseErrorKind,
    pub message: String
}

pub type ParseResult<T> = Result<T,ParseError>;

pub fn decode_component(source: &str) -> Result<String,String> {
    return Ok(lossy_utf8_percent_decode(source.as_bytes()));
}

fn parse_pairs(body: &str) -> Vec<(&str, Option<&str>)> {

    let mut pairs = vec![];

    for part in body.split("&") {
        let separator = part.find("]=")
                            .and_then(|pos| Some(pos+1))
                            .or_else(|| part.find("="));

        match separator {
            None => pairs.push((part, None)),
            Some(pos) => {
                let key = &part[..pos];
                let val = &part[(pos + 1)..];
                pairs.push((key, Some(val)));
            }
        }
    }

    return pairs
}

fn parse_key(key: &str) -> ParseResult<Vec<String>> {
    let mut keys: Vec<String> = vec![];

    match PARENT_REGEX.captures(key) {
        Some(captures) => {
            match decode_component(captures.at(1).unwrap()) {
                Ok(decoded_key) => keys.push(decoded_key),
                Err(err_msg) => return Err(ParseError{ kind: ParseErrorKind::DecodingError, message: err_msg })
            }
        }
        None => ()
    };

    for captures in CHILD_REGEX.captures_iter(key) {
        match decode_component(captures.at(1).unwrap()) {
            Ok(decoded_key) => keys.push(decoded_key),
            Err(err_msg) => return Err(ParseError{ kind: ParseErrorKind::DecodingError, message: err_msg })
        }
    }

    Ok(keys)
}

fn cleanup_key(key: &str) -> &str {
    if key.starts_with("[") && key.ends_with("]") {
        key.slice_chars(1, key.len()-1)
    } else {
        key
    }
}

fn create_idx_merger(idx: usize, obj: Json) -> Json {
    let mut tree: BTreeMap<String,Json> = BTreeMap::new();
    tree.insert("__idx".to_string(), idx.to_json());
    tree.insert("__object".to_string(), obj);
    return Json::Object(tree)
}

fn create_object_with_key(key: String, obj: Json) -> Json {
    let mut tree: BTreeMap<String,Json> = BTreeMap::new();
    tree.insert(key, obj);
    return Json::Object(tree)
}

fn apply_object(keys: &[String], val: Json) -> Json {

    if keys.len() > 0 {
        let key = keys.get(0).unwrap();
        if key.as_slice() == "[]" {
            let mut new_array = create_array();
            let item = apply_object(keys.tail(), val);
            push_item_to_array(&mut new_array, item);
            return new_array;
        } else {
            let key = cleanup_key(key.as_slice());
            let array_index = key.parse();

            match array_index {
                Ok(idx) => {
                    let result = apply_object(keys.tail(), val);
                    let item = create_idx_merger(idx, result);
                    return item;
                },
                Err(_) => {
                    return create_object_with_key(key.to_string(), apply_object(keys.tail(), val));
                }
            }
        }

    } else {
        return val;
    }
}

pub fn parse(params: &str) -> ParseResult<Json> {
    let tree: BTreeMap<String,Json> = BTreeMap::new();
    let mut obj = tree.to_json();
    let pairs = parse_pairs(params);
    for &(key, value) in pairs.iter() {
        let parse_key_res = try!(parse_key(key));
        let key_chain = &parse_key_res[0..];
        let decoded_value = match decode_component(value.unwrap_or("")) {
            Ok(val) => val,
            Err(err) => return Err(ParseError{ kind: ParseErrorKind::DecodingError, message: err })
        };
        let partial = apply_object(key_chain, decoded_value.to_json());
        merge(&mut obj, &partial);
    }

    Ok(obj)
}

#[test]
fn it_parses_simple_string() {
    assert_eq!(parse("0=foo").ok().unwrap().to_string(), r#"{"0":"foo"}"#.to_string());
    assert_eq!(parse("a[<=>]==23").ok().unwrap().to_string(), r#"{"a":{"<=>":"=23"}}"#.to_string());
    assert_eq!(parse(" foo = bar = baz ").ok().unwrap().to_string(), r#"{" foo ":" bar = baz "}"#.to_string());
}

#[test]
fn it_parses_nested_string() {
    assert_eq!(parse("a[b][c][d][e][f][g][h]=i").ok().unwrap().to_string(),
        r#"{"a":{"b":{"c":{"d":{"e":{"f":{"g":{"h":"i"}}}}}}}}"#.to_string())
}

#[test]
fn it_parses_simple_array() {
    assert_eq!(parse("a=b&a=c&a=d&a=e").ok().unwrap().to_string(),
        r#"{"a":["b","c","d","e"]}"#.to_string())
}

#[test]
fn it_parses_explicit_array() {
    assert_eq!(parse("a[]=b&a[]=c&a[]=d").ok().unwrap().to_string(),
        r#"{"a":["b","c","d"]}"#.to_string())
}

#[test]
fn it_parses_nested_array() {
    assert_eq!(parse("a[b][]=c&a[b][]=d").ok().unwrap().to_string(),
        r#"{"a":{"b":["c","d"]}}"#.to_string())
}

#[test]
fn it_allows_to_specify_array_indexes() {
    assert_eq!(parse("a[0][]=c&a[1][]=d").ok().unwrap().to_string(),
        r#"{"a":[["c"],["d"]]}"#.to_string())
}

#[test]
fn it_transforms_arrays_to_object() {
    assert_eq!(parse("foo[0]=bar&foo[bad]=baz").ok().unwrap().to_string(),
        r#"{"foo":{"0":"bar","bad":"baz"}}"#.to_string());

    assert_eq!(parse("foo[0][a]=a&foo[0][b]=b&foo[1][a]=aa&foo[1][b]=bb").ok().unwrap().to_string(),
        r#"{"foo":[{"a":"a","b":"b"},{"a":"aa","b":"bb"}]}"#.to_string());
}

#[test]
fn it_doesnt_produce_empty_keys() {
    assert_eq!(parse("_r=1&").ok().unwrap().to_string(),
        r#"{"_r":"1"}"#.to_string());
}

#[test]
fn it_supports_encoded_strings() {
    assert_eq!(parse("a[b%20c]=c%20d").ok().unwrap().to_string(),
        r#"{"a":{"b c":"c d"}}"#.to_string());
}
<|endoftext|>


<commit_before>use nom::{IResult, not_line_ending, line_ending};

fn csv_line(input: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
	terminated!(input, separated_list!(is_not_bytes!(&b"\n\r,"[..]), not_line_ending), line_ending)
}

#[test]
fn check_file() {
	let f = b"nom,age\ncarles,30\nlaure,28";

	csv_line(f);
}
<commit_msg>Setting everything up before the big start<commit_after>use nom::{IResult, not_line_ending, line_ending};

// http://rust.unhandledexpression.com/nom/macro.escaped!.html
// http://rust.unhandledexpression.com/nom/
// https://fr.wikipedia.org/wiki/Comma-separated_values
// https://github.com/Geal/nom/wiki/Making-a-new-parser-from-scratch
// https://github.com/Geal/nom
fn csv_line(input: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
    terminated!(input, separated_list!(is_not_bytes!(&b"\n\r,"[..]), not_line_ending), line_ending)
}

fn parse_string_between_quotes(input: &str) {

}

fn get_data(input: &str) -> Vec<Vec<String>> {

}

#[test]
fn check_file() {
    let f = b"nom,age\ncarles,30\nlaure,28";

    csv_line(f);
}
<|endoftext|>


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

use std::mem;
use std::os::unix::io::{RawFd, AsRawFd};
use std::io::{Read, Write, Error, ErrorKind};

use openssl::ssl::SslStream;
use openssl::ssl::error::Error as SslStreamError;

use frame;
use super::{Blocking, NonBlocking};

const BUF_SIZE: usize = 1024;

#[derive(Clone)]
pub struct Secure<T: Read + Write> {
    inner: SslStream<T>,
    rx_buf: Vec<u8>,
    tx_buf: Vec<u8>
}

impl<T: Read + Write> Secure<T> {
    pub fn new(stream: SslStream<T>) -> Secure<T> {
        Secure {
            inner: stream,
            rx_buf: Vec::<u8>::with_capacity(BUF_SIZE),
            tx_buf: Vec::<u8>::with_capacity(BUF_SIZE)
        }
    }
}

impl<T: Read + Write> Blocking for Secure<T> {
    fn b_recv(&mut self) -> Result<Vec<u8>, Error> {
        loop {
            let mut buf = [0u8; BUF_SIZE];
            let read_result = self.inner.read(&mut buf);
            if read_result.is_err() {
                let err = read_result.unwrap_err();
                return Err(err);
            }

            let num_read = read_result.unwrap();
            self.rx_buf.extend_from_slice(&buf[0..num_read]);

            match frame::from_raw_parts(&mut self.rx_buf) {
                Some(frame) => {
                    return Ok(frame);
                }
                None => { }
            };
        }
    }

    fn b_send(&mut self, buf: &[u8]) -> Result<(), Error> {
        let frame = frame::new(buf);
        let write_result = self.inner.write(&frame[..]);
        if write_result.is_err() {
            let err = write_result.unwrap_err();
            return Err(err);
        }

        Ok(())
    }
}

impl<T: Read + Write> NonBlocking for Secure<T> {
    fn nb_recv(&mut self) -> Result<Vec<Vec<u8>>, Error> {
        loop {
            let mut buf = [0u8; BUF_SIZE];
            let read_result = self.inner.ssl_read(&mut buf);
            if read_result.is_err() {
                let err = read_result.unwrap_err();
                match err {
                    SslStreamError::ZeroReturn => {
                        return Err(Error::new(ErrorKind::UnexpectedEof, "UnexpectedEof"));
                    }
                    SslStreamError::WantRead(_) => {
                        break;
                    }
                    SslStreamError::WantX509Lookup => {
                        return Err(Error::new(ErrorKind::Other, "WantX509Lookup"));
                    }
                    SslStreamError::Stream(e) => {
                        return Err(e);
                    }
                    SslStreamError::Ssl(ssl_errs) => {
                        let mut err_str = String::new();
                        err_str.push_str("The following Ssl Error codes were thrown: ");

                        for ssl_err in ssl_errs.iter() {
                            err_str.push_str(&(format!("{} ", ssl_err.error_code())[..]));
                        }

                        return Err(Error::new(ErrorKind::Other, &err_str[..]));
                    }
                    _ => {
                        // Other error types should not be thrown from this operation
                        return Err(Error::new(ErrorKind::Other, "Unknown error during ssl_read"));
                    }
                };
            }

            let num_read = read_result.unwrap();
            self.rx_buf.extend_from_slice(&buf[0..num_read]);
        }

        let mut ret_buf = Vec::<Vec<u8>>::with_capacity(5);
        while let Some(frame) = frame::from_raw_parts(&mut self.rx_buf) {
            ret_buf.push(frame);
        }

        if ret_buf.len() > 0 {
            return Ok(ret_buf);
        }

        Err(Error::new(ErrorKind::WouldBlock, "WouldBlock"))
    }

    fn nb_send(&mut self, buf: &[u8]) -> Result<(), Error> {
        let frame = frame::new(buf);
        self.tx_buf.extend_from_slice(&frame[..]);

        let write_result = self.inner.ssl_write(&self.tx_buf[..]);
        if write_result.is_err() {
            let err = write_result.unwrap_err();
            match err {
                SslStreamError::WantWrite(_) => {
                    return Err(Error::new(ErrorKind::WouldBlock, "WouldBlock"));
                }
                SslStreamError::WantX509Lookup => {
                    return Err(Error::new(ErrorKind::Other, "WantX509Lookup"));
                }
                SslStreamError::Stream(e) => {
                    return Err(e);
                }
                SslStreamError::Ssl(ssl_errs) => {
                    let mut err_str = String::new();
                    err_str.push_str("The following Ssl Error codes were thrown: ");

                    for ssl_err in ssl_errs.iter() {
                        err_str.push_str(&(format!("{} ", ssl_err.error_code())[..]));
                    }

                    return Err(Error::new(ErrorKind::Other, &err_str[..]));
                }
                _ => {
                    // Other error types should not be thrown from this operation
                    return Err(Error::new(ErrorKind::Other, "Unknown error during ssl_write"))
                }
            };
        }

        let num_written = write_result.unwrap();
        if num_written == 0 {
            return Err(Error::new(ErrorKind::Other, "Write returned zero"));
        }

        if num_written < self.tx_buf.len() {
            let tx_buf_len = self.tx_buf.len();
            let remaining_len = self.tx_buf.len() - num_written;

            let mut buf = Vec::<u8>::with_capacity(remaining_len);
            buf.extend_from_slice(&self.tx_buf[num_written..tx_buf_len]);

            mem::swap(&mut buf, &mut self.tx_buf);

            return Err(Error::new(ErrorKind::WouldBlock, "WouldBlock"));
        }

        Ok(())
    }
}

impl<T: Read + Write + AsRawFd> AsRawFd for Secure<T> {
    fn as_raw_fd(&self) -> RawFd {
        self.inner.as_raw_fd()
    }
}
<commit_msg>Fixes to non-blocking writes.<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

use std::mem;
use std::os::unix::io::{RawFd, AsRawFd};
use std::io::{Read, Write, Error, ErrorKind};

use openssl::ssl::SslStream;
use openssl::ssl::error::Error as SslStreamError;

use frame;
use super::{Blocking, NonBlocking};

const BUF_SIZE: usize = 1024;

#[derive(Clone)]
pub struct Secure<T: Read + Write> {
    inner: SslStream<T>,
    rx_buf: Vec<u8>,
    tx_buf: Vec<u8>
}

impl<T: Read + Write> Secure<T> {
    pub fn new(stream: SslStream<T>) -> Secure<T> {
        Secure {
            inner: stream,
            rx_buf: Vec::<u8>::with_capacity(BUF_SIZE),
            tx_buf: Vec::<u8>::with_capacity(BUF_SIZE)
        }
    }
}

impl<T: Read + Write> Blocking for Secure<T> {
    fn b_recv(&mut self) -> Result<Vec<u8>, Error> {
        loop {
            let mut buf = [0u8; BUF_SIZE];
            let read_result = self.inner.read(&mut buf);
            if read_result.is_err() {
                let err = read_result.unwrap_err();
                return Err(err);
            }

            let num_read = read_result.unwrap();
            self.rx_buf.extend_from_slice(&buf[0..num_read]);

            match frame::from_raw_parts(&mut self.rx_buf) {
                Some(frame) => {
                    return Ok(frame);
                }
                None => { }
            };
        }
    }

    fn b_send(&mut self, buf: &[u8]) -> Result<(), Error> {
        let frame = frame::new(buf);
        let write_result = self.inner.write(&frame[..]);
        if write_result.is_err() {
            let err = write_result.unwrap_err();
            return Err(err);
        }

        Ok(())
    }
}

impl<T: Read + Write> NonBlocking for Secure<T> {
    fn nb_recv(&mut self) -> Result<Vec<Vec<u8>>, Error> {
        loop {
            let mut buf = [0u8; BUF_SIZE];
            let read_result = self.inner.ssl_read(&mut buf);
            if read_result.is_err() {
                let err = read_result.unwrap_err();
                match err {
                    SslStreamError::ZeroReturn => {
                        return Err(Error::new(ErrorKind::UnexpectedEof, "UnexpectedEof"));
                    }
                    SslStreamError::WantRead(_) => {
                        break;
                    }
                    SslStreamError::WantX509Lookup => {
                        return Err(Error::new(ErrorKind::Other, "WantX509Lookup"));
                    }
                    SslStreamError::Stream(e) => {
                        return Err(e);
                    }
                    SslStreamError::Ssl(ssl_errs) => {
                        let mut err_str = String::new();
                        err_str.push_str("The following Ssl Error codes were thrown: ");

                        for ssl_err in ssl_errs.iter() {
                            err_str.push_str(&(format!("{} ", ssl_err.error_code())[..]));
                        }

                        return Err(Error::new(ErrorKind::Other, &err_str[..]));
                    }
                    _ => {
                        // Other error types should not be thrown from this operation
                        return Err(Error::new(ErrorKind::Other, "Unknown error during ssl_read"));
                    }
                };
            }

            let num_read = read_result.unwrap();
            self.rx_buf.extend_from_slice(&buf[0..num_read]);
        }

        let mut ret_buf = Vec::<Vec<u8>>::with_capacity(5);
        while let Some(frame) = frame::from_raw_parts(&mut self.rx_buf) {
            ret_buf.push(frame);
        }

        if ret_buf.len() > 0 {
            return Ok(ret_buf);
        }

        Err(Error::new(ErrorKind::WouldBlock, "WouldBlock"))
    }

    fn nb_send(&mut self, buf: &[u8]) -> Result<(), Error> {
        let frame = frame::new(buf);
        self.tx_buf.extend_from_slice(&frame[..]);

        let mut out_buf = Vec::<u8>::with_capacity(BUF_SIZE);
        mem::swap(&mut self.tx_buf, &mut out_buf);

        let write_result = self.inner.ssl_write(&out_buf[..]);
        if write_result.is_err() {
            let err = write_result.unwrap_err();
            match err {
                SslStreamError::WantWrite(_) => {
                    return Err(Error::new(ErrorKind::WouldBlock, "WouldBlock"));
                }
                SslStreamError::WantX509Lookup => {
                    return Err(Error::new(ErrorKind::Other, "WantX509Lookup"));
                }
                SslStreamError::Stream(e) => {
                    return Err(e);
                }
                SslStreamError::Ssl(ssl_errs) => {
                    let mut err_str = String::new();
                    err_str.push_str("The following Ssl Error codes were thrown: ");

                    for ssl_err in ssl_errs.iter() {
                        err_str.push_str(&(format!("{} ", ssl_err.error_code())[..]));
                    }

                    return Err(Error::new(ErrorKind::Other, &err_str[..]));
                }
                _ => {
                    // Other error types should not be thrown from this operation
                    return Err(Error::new(ErrorKind::Other, "Unknown error during ssl_write"))
                }
            };
        }

        let num_written = write_result.unwrap();
        if num_written == 0 {
            return Err(Error::new(ErrorKind::Other, "Write returned zero"));
        }

        if num_written < out_buf.len() {
            let out_buf_len = out_buf.len();
            self.tx_buf.extend_from_slice(&out_buf[num_written..out_buf_len]);

            return Err(Error::new(ErrorKind::WouldBlock, "WouldBlock"));
        }

        Ok(())
    }
}

impl<T: Read + Write + AsRawFd> AsRawFd for Secure<T> {
    fn as_raw_fd(&self) -> RawFd {
        self.inner.as_raw_fd()
    }
}
<|endoftext|>