<commit_before>// Copyright 2015 The Delix Project Authors. See the AUTHORS file at the top level directory.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use std::net::{SocketAddr, ToSocketAddrs};
use std::io;
use std::result;
use std::sync::Arc;
use time::Duration;
use log;

use openssl::{ssl, x509};

use delix::logger;
use delix::metric::{self, Metric};
use delix::node::{self, Node};
use delix::discovery::{self, Discovery};
use delix::relay::{self, Relay};
use delix::transport::{self, Transport};
use delix::transport::direct::balancer;
use configuration::Configuration;

const DEFAULT_KEY_LENGTH: u32 = 2048;

#[derive(Debug)]
pub struct Loader {
    configuration: Configuration,
}

pub type Result<T> = result::Result<T, Error>;

#[derive(Debug)]
pub enum Error {
    NoLogType,
    UnknownLogType(String),
    NoMetricType,
    UnknownMetricType(String),
    NoDiscoveryType,
    UnknownDiscoveryType(String),
    NoTransportType,
    UnknownTransportType(String),
    NoBalancerType,
    UnknownBalancerType(String),
    NoRelayType,
    UnknownRelayType(String),
    NoAddress,
    NoAddresses,
    NoName,
    NoLocalAddress,
    NodeError(node::Error),
    Relay(relay::Error),
    Io(io::Error),
    Ssl(ssl::error::SslError),
}

impl Loader {
    pub fn new(configuration: Configuration) -> Loader {
        Loader { configuration: configuration }
    }

    pub fn load_log(&self, metric: &Arc<Metric>) -> Result<()> {
        let log_type = try!(self.configuration.string_at("log.type").ok_or(Error::NoLogType));

        let log_level_filter = match self.configuration
                                         .string_at("log.level")
                                         .unwrap_or("off".to_string())
                                         .as_ref() {
            "off" => log::LogLevelFilter::Off,
            "error" => log::LogLevelFilter::Error,
            "warn" => log::LogLevelFilter::Warn,
            "info" => log::LogLevelFilter::Info,
            "debug" => log::LogLevelFilter::Debug,
            "trace" => log::LogLevelFilter::Trace,
            _ => log::LogLevelFilter::Off,
        };

        match log_type.as_ref() {
            "console" => {
                logger::Console::init(log_level_filter, "delix", metric).unwrap();
                info!("loaded console log");
            }
            _ => return Err(Error::UnknownLogType(log_type)),
        }

        Ok(())
    }

    pub fn load_metric(&self) -> Result<Arc<metric::Metric>> {
        let metric_type = try!(self.configuration
                                   .string_at("metric.type")
                                   .ok_or(Error::NoMetricType));

        match metric_type.as_ref() {
            "console" => {
                info!("loaded console metric");
                Ok(Arc::new(metric::Memory::new()))
            }
            "terminal" => {
                info!("loaded terminal metric");
                let refresh_interval_ms = self.configuration
                                              .i64_at("metric.refresh_interval_ms")
                                              .unwrap_or(100);
                Ok(Arc::new(metric::Terminal::new(refresh_interval_ms as u32)))
            }
            _ => return Err(Error::UnknownMetricType(metric_type)),
        }
    }

    pub fn load_node(&self, metric: &Arc<metric::Metric>) -> Result<Arc<Node>> {
        let discovery = try!(self.load_discovery());

        let transport = try!(self.load_transport(metric.clone()));

        Ok(Arc::new(try!(Node::new(discovery, transport, metric.clone()))))
    }

    fn load_discovery(&self) -> Result<Box<Discovery>> {
        let discovery_type = try!(self.configuration
                                      .string_at("discovery.type")
                                      .ok_or(Error::NoDiscoveryType));

        match discovery_type.as_ref() {
            "constant" => {
                let addresses = try!(self.configuration
                                         .strings_at("discovery.addresses")
                                         .ok_or(Error::NoAddresses));
                let addresses = try!(resolve_socket_addresses(&addresses));
                let constant = discovery::Constant::new(addresses);
                info!("loaded constant discovery");
                Ok(Box::new(constant))
            }
            _ => Err(Error::UnknownDiscoveryType(discovery_type)),
        }
    }

    fn load_transport(&self, metric: Arc<Metric>) -> Result<Box<Transport>> {
        let transport_type = try!(self.configuration
                                      .string_at("transport.type")
                                      .ok_or(Error::NoTransportType));

        match transport_type.as_ref() {
            "direct" => {
                let local_address = try!(self.configuration
                                             .string_at("transport.local_address")
                                             .ok_or(Error::NoLocalAddress));
                let local_address = try!(resolve_socket_address(&local_address));

                let public_address = match self.configuration
                                               .string_at("transport.public_address") {
                    Some(ref value) => Some(try!(resolve_socket_address(value))),
                    None => None,
                };

                let ca_file_name = self.configuration.string_at("transport.ca_file");
                let cert_file_name = self.configuration.string_at("transport.cert_file");
                let key_file_name = self.configuration.string_at("transport.key_file");

                let mut ssl_context = try!(ssl::SslContext::new(ssl::SslMethod::Tlsv1_2));
                if let (Some(ca_file_name),
                        Some(cert_file_name),
                        Some(key_file_name)) = (ca_file_name, cert_file_name, key_file_name) {

                    try!(ssl_context.set_CA_file(&ca_file_name));
                    try!(ssl_context.set_certificate_file(&cert_file_name,
                                                          x509::X509FileType::PEM));
                    try!(ssl_context.set_private_key_file(&key_file_name, x509::X509FileType::PEM));
                    ssl_context.set_verify(ssl::SSL_VERIFY_PEER, None);
                    try!(ssl_context.check_private_key());
                } else {
                    info!("generating default certificate with a key length of {} ...",
                          DEFAULT_KEY_LENGTH);
                    let generator = x509::X509Generator::new().set_bitlength(DEFAULT_KEY_LENGTH);
                    let (certificate, private_key) = generator.generate().unwrap();

                    try!(ssl_context.set_certificate(&certificate));
                    try!(ssl_context.set_private_key(&private_key));
                }

                let request_timeout = self.configuration
                                          .i64_at("transport.request_timeout_ms")
                                          .map(|value| Duration::milliseconds(value));

                let balancer_type = try!(self.configuration
                                             .string_at("transport.balancer.type")
                                             .ok_or(Error::NoBalancerType));

                let balancer_factory = match balancer_type.as_ref() {
                    "dynamic_round_robin" => Box::new(balancer::DynamicRoundRobinFactory::new()),
                    _ => return Err(Error::UnknownBalancerType(balancer_type)),
                };

                info!("loaded direct transport - listening at {}", local_address);

                Ok(Box::new(transport::Direct::new(ssl_context,
                                                   balancer_factory,
                                                   metric,
                                                   local_address,
                                                   public_address,
                                                   request_timeout)))
            }
            _ => Err(Error::UnknownTransportType(transport_type)),
        }
    }

    pub fn load_relays(&self, node: &Arc<Node>) -> Result<Vec<Box<Relay>>> {
        let mut relays = Vec::new();
        if let Some(configurations) = self.configuration.configurations_at("relay") {
            for configuration in configurations {
                let relay_type = try!(configuration.string_at("type").ok_or(Error::NoRelayType));

                let relay: Box<Relay> = match relay_type.as_ref() {
                    "http_static" => {
                        let address = configuration.string_at("address");
                        let header_field = configuration.string_at("header_field")
                                                        .unwrap_or("X-Delix-Service".to_string());
                        let read_timeout = configuration.i64_at("read_timeout_ms")
                                                        .map(|value| Duration::milliseconds(value));
                        let write_timeout = configuration.i64_at("write_timeout_ms")
                                                         .map(|value| {
                                                             Duration::milliseconds(value)
                                                         });

                        let http_static = relay::HttpStatic::new(node.clone(),
                                                                 &header_field,
                                                                 read_timeout,
                                                                 write_timeout);

                        if let Some(configurations) = configuration.configurations_at("service") {
                            for configuration in configurations {
                                let name = try!(configuration.string_at("name")
                                                             .ok_or(Error::NoName));
                                let address = try!(configuration.string_at("address")
                                                                .ok_or(Error::NoAddress));
                                http_static.add_service(&name, &address);
                            }
                        }

                        if let Some(ref address) = address {
                            try!(http_static.bind(try!(resolve_socket_address(address))));
                            info!("loaded http static relay - listening at {}", address);
                        } else {
                            info!("loaded http static relay");
                        }

                        Box::new(http_static)
                    }
                    _ => return Err(Error::UnknownRelayType(relay_type)),
                };

                relays.push(relay);
            }

        }
        Ok(relays)
    }
}

impl From<node::Error> for Error {
    fn from(error: node::Error) -> Self {
        Error::NodeError(error)
    }
}

impl From<relay::Error> for Error {
    fn from(error: relay::Error) -> Self {
        Error::Relay(error)
    }
}

impl From<io::Error> for Error {
    fn from(error: io::Error) -> Self {
        Error::Io(error)
    }
}

impl From<ssl::error::SslError> for Error {
    fn from(error: ssl::error::SslError) -> Self {
        Error::Ssl(error)
    }
}

fn resolve_socket_address(address: &str) -> io::Result<SocketAddr> {
    Ok(try!(try!(address.to_socket_addrs())
                .next()
                .ok_or(io::Error::new(io::ErrorKind::Other,
                                      format!("could not resolve address [{}]", address)))))
}

fn resolve_socket_addresses(addresses: &[String]) -> io::Result<Vec<SocketAddr>> {
    let mut result = Vec::new();
    for address in addresses {
        result.append(&mut try!(address.to_socket_addrs()).collect::<Vec<SocketAddr>>());
    }
    Ok(result)
}
<commit_msg>refactored loader<commit_after>// Copyright 2015 The Delix Project Authors. See the AUTHORS file at the top level directory.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use std::net::{SocketAddr, ToSocketAddrs};
use std::io;
use std::result;
use std::sync::Arc;
use time::Duration;
use log;

use openssl::{ssl, x509};

use delix::logger;
use delix::metric::{self, Metric};
use delix::node::{self, Node};
use delix::discovery::{self, Discovery};
use delix::relay::{self, Relay};
use delix::transport::{self, Transport};
use delix::transport::direct::balancer;
use configuration::Configuration;

const DEFAULT_KEY_LENGTH: u32 = 2048;

#[derive(Debug)]
pub struct Loader {
    configuration: Configuration,
}

pub type Result<T> = result::Result<T, Error>;

#[derive(Debug)]
pub enum Error {
    MissingField(&'static str),
    InvalidValue(&'static str, String, Vec<&'static str>),
    NodeError(node::Error),
    Relay(relay::Error),
    Resolve(io::Error),
    Ssl(ssl::error::SslError),
}

impl Loader {
    pub fn new(configuration: Configuration) -> Loader {
        Loader { configuration: configuration }
    }

    pub fn load_metric(&self) -> Result<Arc<metric::Metric>> {
        let metric_type = try!(self.configuration
                                   .string_at("metric.type")
                                   .ok_or(Error::MissingField("metric.type")));

        match metric_type.as_ref() {
            "console" => {
                info!("loaded console metric");
                Ok(Arc::new(metric::Memory::new()))
            }
            "terminal" => {
                info!("loaded terminal metric");
                let refresh_interval_ms = self.configuration
                                              .i64_at("metric.refresh_interval_ms")
                                              .unwrap_or(100);
                Ok(Arc::new(metric::Terminal::new(refresh_interval_ms as u32)))
            }
            _ => {
                Err(Error::InvalidValue("metric.type",
                                        metric_type.to_string(),
                                        vec!["console", "terminal"]))
            }
        }
    }

    pub fn load_log(&self, metric: &Arc<Metric>) -> Result<()> {
        let log_type = try!(self.configuration
                                .string_at("log.type")
                                .ok_or(Error::MissingField("log.type")));

        let log_level_filter = match self.configuration
                                         .string_at("log.level")
                                         .unwrap_or("off".to_string())
                                         .as_ref() {
            "off" => log::LogLevelFilter::Off,
            "error" => log::LogLevelFilter::Error,
            "warn" => log::LogLevelFilter::Warn,
            "info" => log::LogLevelFilter::Info,
            "debug" => log::LogLevelFilter::Debug,
            "trace" => log::LogLevelFilter::Trace,
            _ => log::LogLevelFilter::Off,
        };

        match log_type.as_ref() {
            "console" => {
                logger::Console::init(log_level_filter, "delix", metric).unwrap();
                info!("loaded console log");
                Ok(())
            }
            _ => Err(Error::InvalidValue("log.type", log_type.to_string(), vec!["console"])),
        }
    }

    pub fn load_node(&self, metric: &Arc<metric::Metric>) -> Result<Arc<Node>> {
        let discovery = try!(self.load_discovery());

        let transport = try!(self.load_transport(metric.clone()));

        Ok(Arc::new(try!(Node::new(discovery, transport, metric.clone()))))
    }

    fn load_discovery(&self) -> Result<Box<Discovery>> {
        let discovery_type = try!(self.configuration
                                      .string_at("discovery.type")
                                      .ok_or(Error::MissingField("discovery.type")));

        match discovery_type.as_ref() {
            "constant" => {
                let addresses = try!(self.configuration
                                         .strings_at("discovery.addresses")
                                         .ok_or(Error::MissingField("discovery.addresses")));
                let addresses = try!(resolve_socket_addresses(&addresses));
                let constant = discovery::Constant::new(addresses);
                info!("loaded constant discovery");
                Ok(Box::new(constant))
            }
            _ => {
                Err(Error::InvalidValue("discovery.type",
                                        discovery_type.to_string(),
                                        vec!["constant"]))
            }
        }
    }

    fn load_transport(&self, metric: Arc<Metric>) -> Result<Box<Transport>> {
        let transport_type = try!(self.configuration
                                      .string_at("transport.type")
                                      .ok_or(Error::MissingField("transport.type")));

        match transport_type.as_ref() {
            "direct" => {
                let local_address = try!(self.configuration
                                             .string_at("transport.local_address")
                                             .ok_or(Error::MissingField("transport.\
                                                                         local_address")));
                let local_address = try!(resolve_socket_address(&local_address));

                let public_address = match self.configuration
                                               .string_at("transport.public_address") {
                    Some(ref value) => Some(try!(resolve_socket_address(value))),
                    None => None,
                };

                let ca_file_name = self.configuration.string_at("transport.ca_file");
                let cert_file_name = self.configuration.string_at("transport.cert_file");
                let key_file_name = self.configuration.string_at("transport.key_file");

                let mut ssl_context = try!(ssl::SslContext::new(ssl::SslMethod::Tlsv1_2));
                if let (Some(ca_file_name),
                        Some(cert_file_name),
                        Some(key_file_name)) = (ca_file_name, cert_file_name, key_file_name) {

                    try!(ssl_context.set_CA_file(&ca_file_name));
                    try!(ssl_context.set_certificate_file(&cert_file_name,
                                                          x509::X509FileType::PEM));
                    try!(ssl_context.set_private_key_file(&key_file_name, x509::X509FileType::PEM));
                    ssl_context.set_verify(ssl::SSL_VERIFY_PEER, None);
                    try!(ssl_context.check_private_key());
                } else {
                    info!("generating default certificate with a key length of {} ...",
                          DEFAULT_KEY_LENGTH);
                    let generator = x509::X509Generator::new().set_bitlength(DEFAULT_KEY_LENGTH);
                    let (certificate, private_key) = generator.generate().unwrap();

                    try!(ssl_context.set_certificate(&certificate));
                    try!(ssl_context.set_private_key(&private_key));
                }

                let request_timeout = self.configuration
                                          .i64_at("transport.request_timeout_ms")
                                          .map(|value| Duration::milliseconds(value));

                let balancer_type = try!(self.configuration
                                             .string_at("transport.balancer.type")
                                             .ok_or(Error::MissingField("transport.balancer.\
                                                                         type")));

                let balancer_factory = match balancer_type.as_ref() {
                    "dynamic_round_robin" => Box::new(balancer::DynamicRoundRobinFactory::new()),
                    _ => {
                        return Err(Error::InvalidValue("transport.balancer.type",
                                                       balancer_type.to_string(),
                                                       vec!["dynamic_round_robin"]))
                    }
                };

                info!("loaded direct transport - listening at {}", local_address);

                Ok(Box::new(transport::Direct::new(ssl_context,
                                                   balancer_factory,
                                                   metric,
                                                   local_address,
                                                   public_address,
                                                   request_timeout)))
            }
            _ => {
                Err(Error::InvalidValue("transport.type",
                                        transport_type.to_string(),
                                        vec!["direct"]))
            }
        }
    }

    pub fn load_relays(&self, node: &Arc<Node>) -> Result<Vec<Box<Relay>>> {
        let mut relays = Vec::new();
        if let Some(configurations) = self.configuration.configurations_at("relay") {
            for configuration in configurations {
                relays.push(try!(load_relay(&configuration, node)));
            }
        }
        Ok(relays)
    }
}

impl From<node::Error> for Error {
    fn from(error: node::Error) -> Self {
        Error::NodeError(error)
    }
}

impl From<relay::Error> for Error {
    fn from(error: relay::Error) -> Self {
        Error::Relay(error)
    }
}

impl From<io::Error> for Error {
    fn from(error: io::Error) -> Self {
        Error::Resolve(error)
    }
}

impl From<ssl::error::SslError> for Error {
    fn from(error: ssl::error::SslError) -> Self {
        Error::Ssl(error)
    }
}

fn load_relay(configuration: &Configuration, node: &Arc<Node>) -> Result<Box<Relay>> {
    let relay_type = try!(configuration.string_at("type")
                                       .ok_or(Error::MissingField("relay.type")));

    match relay_type.as_ref() {
        "http_static" => {
            let address = configuration.string_at("address");
            let header_field = configuration.string_at("header_field")
                                            .unwrap_or("X-Delix-Service".to_string());
            let read_timeout = configuration.i64_at("read_timeout_ms")
                                            .map(|value| Duration::milliseconds(value));
            let write_timeout = configuration.i64_at("write_timeout_ms")
                                             .map(|value| Duration::milliseconds(value));

            let http_static = relay::HttpStatic::new(node.clone(),
                                                     &header_field,
                                                     read_timeout,
                                                     write_timeout);

            if let Some(configurations) = configuration.configurations_at("service") {
                for configuration in configurations {
                    let name = try!(configuration.string_at("name")
                                                 .ok_or(Error::MissingField("relay.service.name")));
                    let address = try!(configuration.string_at("address")
                                                    .ok_or(Error::MissingField("relay.service.\
                                                                                address")));
                    http_static.add_service(&name, &address);
                }
            }

            if let Some(ref address) = address {
                try!(http_static.bind(try!(resolve_socket_address(address))));
                info!("loaded http static relay - listening at {}", address);
            } else {
                info!("loaded http static relay");
            }

            Ok(Box::new(http_static))
        }
        _ => Err(Error::InvalidValue("relay.type", relay_type.to_string(), vec!["http_static"])),
    }
}

fn resolve_socket_address(address: &str) -> io::Result<SocketAddr> {
    Ok(try!(try!(address.to_socket_addrs())
                .next()
                .ok_or(io::Error::new(io::ErrorKind::Other,
                                      format!("could not resolve address [{}]", address)))))
}

fn resolve_socket_addresses(addresses: &[String]) -> io::Result<Vec<SocketAddr>> {
    let mut result = Vec::new();
    for address in addresses {
        result.append(&mut try!(address.to_socket_addrs()).collect::<Vec<SocketAddr>>());
    }
    Ok(result)
}
<|endoftext|>


<commit_before>macro_rules! define_ty {
    ($name:ident, $($elty:ident),+) => {
        #[repr(simd)]
        #[derive(Clone, Copy, Debug, PartialEq)]
        #[allow(non_camel_case_types)]
        pub struct $name($($elty),*);
    }
}

macro_rules! define_impl {
    (
        $name:ident, $elemty:ident, $nelems:expr, $boolname:ident,
        $($elname:ident),+
    ) => {
        impl $name {
            #[inline]
            pub fn new($($elname: $elemty),*) -> $name {
                $name($($elname),*)
            }

            #[inline]
            pub fn splat(value: $elemty) -> $name {
                $name($({
                    #[allow(non_camel_case_types, dead_code)]
                    struct $elname;
                    value
                }),*)
            }

            #[inline]
            pub fn extract(self, idx: u32) -> $elemty {
                assert!(idx < $nelems);
                unsafe { simd_extract(self, idx) }
            }

            #[inline]
            pub fn replace(self, idx: u32, val: $elemty) -> $name {
                assert!(idx < $nelems);
                unsafe { simd_insert(self, idx, val) }
            }

            #[inline]
            pub fn store(self, slice: &mut [$elemty], offset: usize) {
                assert!(slice[offset..].len() >= $nelems);
                unsafe { self.store_unchecked(slice, offset) }
            }

            #[inline]
            pub unsafe fn store_unchecked(
                self,
                slice: &mut [$elemty],
                offset: usize,
            ) {
                use std::mem::size_of;
                use std::ptr;

                ptr::copy_nonoverlapping(
                    &self as *const $name as *const u8,
                    slice.get_unchecked_mut(offset) as *mut $elemty as *mut u8,
                    size_of::<$name>());
            }

            #[inline]
            pub fn load(slice: &[$elemty], offset: usize) -> $name {
                assert!(slice[offset..].len() >= $nelems);
                unsafe { $name::load_unchecked(slice, offset) }
            }

            #[inline]
            pub unsafe fn load_unchecked(
                slice: &[$elemty],
                offset: usize,
            ) -> $name {
                use std::mem::size_of;
                use std::ptr;

                let mut x = $name::splat(0 as $elemty);
                ptr::copy_nonoverlapping(
                    slice.get_unchecked(offset) as *const $elemty as *const u8,
                    &mut x as *mut $name as *mut u8,
                    size_of::<$name>());
                x
            }

            #[inline]
            pub fn eq(self, other: $name) -> $boolname {
                unsafe { simd_eq(self, other) }
            }

            #[inline]
            pub fn ne(self, other: $name) -> $boolname {
                unsafe { simd_ne(self, other) }
            }

            #[inline]
            pub fn lt(self, other: $name) -> $boolname {
                unsafe { simd_lt(self, other) }
            }

            #[inline]
            pub fn le(self, other: $name) -> $boolname {
                unsafe { simd_le(self, other) }
            }

            #[inline]
            pub fn gt(self, other: $name) -> $boolname {
                unsafe { simd_gt(self, other) }
            }

            #[inline]
            pub fn ge(self, other: $name) -> $boolname {
                unsafe { simd_ge(self, other) }
            }
        }
    }
}

macro_rules! define_from {
    ($to:ident, $($from:ident),+) => {
        $(
            impl From<$from> for $to {
                fn from(f: $from) -> $to {
                    unsafe { ::std::mem::transmute(f) }
                }
            }
        )+
    }
}

macro_rules! define_common_ops {
    ($($ty:ident),+) => {
        $(
            impl ::std::ops::Add for $ty {
                type Output = Self;
                #[inline(always)]
                fn add(self, other: Self) -> Self {
                    unsafe { simd_add(self, other) }
                }
            }

            impl ::std::ops::Sub for $ty {
                type Output = Self;
                #[inline(always)]
                fn sub(self, other: Self) -> Self {
                    unsafe { simd_sub(self, other) }
                }
            }

            impl ::std::ops::Mul for $ty {
                type Output = Self;
                #[inline(always)]
                fn mul(self, other: Self) -> Self {
                    unsafe { simd_mul(self, other) }
                }
            }
        )+
    }
}

macro_rules! define_float_ops {
    ($($ty:ident),+) => {
        $(
            impl ::std::ops::Div for $ty {
                type Output = Self;
                #[inline(always)]
                fn div(self, other: Self) -> Self {
                    unsafe { simd_div(self, other) }
                }
            }
        )+
    }
}

macro_rules! define_shifts {
    ($ty:ident, $elem:ident, $($by:ident),+) => {
        $(
            impl ::std::ops::Shl<$by> for $ty {
                type Output = Self;
                #[inline(always)]
                fn shl(self, other: $by) -> Self {
                    unsafe { simd_shl(self, $ty::splat(other as $elem)) }
                }
            }
            impl ::std::ops::Shr<$by> for $ty {
                type Output = Self;
                #[inline(always)]
                fn shr(self, other: $by) -> Self {
                    unsafe { simd_shr(self, $ty::splat(other as $elem)) }
                }
            }
        )+
    }
}

macro_rules! define_integer_ops {
    ($(($ty:ident, $elem:ident)),+) => {
        $(
            impl ::std::ops::BitAnd for $ty {
                type Output = Self;
                #[inline(always)]
                fn bitand(self, other: Self) -> Self {
                    unsafe { simd_and(self, other) }
                }
            }
            impl ::std::ops::BitOr for $ty {
                type Output = Self;
                #[inline(always)]
                fn bitor(self, other: Self) -> Self {
                    unsafe { simd_or(self, other) }
                }
            }
            impl ::std::ops::BitXor for $ty {
                type Output = Self;
                #[inline(always)]
                fn bitxor(self, other: Self) -> Self {
                    unsafe { simd_xor(self, other) }
                }
            }
            impl ::std::ops::Not for $ty {
                type Output = Self;
                #[inline(always)]
                fn not(self) -> Self {
                    $ty::splat(!0) ^ self
                }
            }
            define_shifts!(
                $ty, $elem,
                u8, u16, u32, u64, usize,
                i8, i16, i32, i64, isize);
        )+
    }
}

macro_rules! define_casts {
    ($(($ty:ident, $floatty:ident, $floatcast:ident)),+) => {
        $(
            impl $ty {
                pub fn $floatcast(self) -> ::$floatty {
                    unsafe { simd_cast(self) }
                }
            }
        )+
    }
}
<commit_msg>Add `fmt::LowerHex` to integer simd for debugging<commit_after>macro_rules! define_ty {
    ($name:ident, $($elty:ident),+) => {
        #[repr(simd)]
        #[derive(Clone, Copy, Debug, PartialEq)]
        #[allow(non_camel_case_types)]
        pub struct $name($($elty),*);
    }
}

macro_rules! define_impl {
    (
        $name:ident, $elemty:ident, $nelems:expr, $boolname:ident,
        $($elname:ident),+
    ) => {
        impl $name {
            #[inline]
            pub fn new($($elname: $elemty),*) -> $name {
                $name($($elname),*)
            }

            #[inline]
            pub fn splat(value: $elemty) -> $name {
                $name($({
                    #[allow(non_camel_case_types, dead_code)]
                    struct $elname;
                    value
                }),*)
            }

            #[inline]
            pub fn extract(self, idx: u32) -> $elemty {
                assert!(idx < $nelems);
                unsafe { simd_extract(self, idx) }
            }

            #[inline]
            pub fn replace(self, idx: u32, val: $elemty) -> $name {
                assert!(idx < $nelems);
                unsafe { simd_insert(self, idx, val) }
            }

            #[inline]
            pub fn store(self, slice: &mut [$elemty], offset: usize) {
                assert!(slice[offset..].len() >= $nelems);
                unsafe { self.store_unchecked(slice, offset) }
            }

            #[inline]
            pub unsafe fn store_unchecked(
                self,
                slice: &mut [$elemty],
                offset: usize,
            ) {
                use std::mem::size_of;
                use std::ptr;

                ptr::copy_nonoverlapping(
                    &self as *const $name as *const u8,
                    slice.get_unchecked_mut(offset) as *mut $elemty as *mut u8,
                    size_of::<$name>());
            }

            #[inline]
            pub fn load(slice: &[$elemty], offset: usize) -> $name {
                assert!(slice[offset..].len() >= $nelems);
                unsafe { $name::load_unchecked(slice, offset) }
            }

            #[inline]
            pub unsafe fn load_unchecked(
                slice: &[$elemty],
                offset: usize,
            ) -> $name {
                use std::mem::size_of;
                use std::ptr;

                let mut x = $name::splat(0 as $elemty);
                ptr::copy_nonoverlapping(
                    slice.get_unchecked(offset) as *const $elemty as *const u8,
                    &mut x as *mut $name as *mut u8,
                    size_of::<$name>());
                x
            }

            #[inline]
            pub fn eq(self, other: $name) -> $boolname {
                unsafe { simd_eq(self, other) }
            }

            #[inline]
            pub fn ne(self, other: $name) -> $boolname {
                unsafe { simd_ne(self, other) }
            }

            #[inline]
            pub fn lt(self, other: $name) -> $boolname {
                unsafe { simd_lt(self, other) }
            }

            #[inline]
            pub fn le(self, other: $name) -> $boolname {
                unsafe { simd_le(self, other) }
            }

            #[inline]
            pub fn gt(self, other: $name) -> $boolname {
                unsafe { simd_gt(self, other) }
            }

            #[inline]
            pub fn ge(self, other: $name) -> $boolname {
                unsafe { simd_ge(self, other) }
            }
        }
    }
}

macro_rules! define_from {
    ($to:ident, $($from:ident),+) => {
        $(
            impl From<$from> for $to {
                fn from(f: $from) -> $to {
                    unsafe { ::std::mem::transmute(f) }
                }
            }
        )+
    }
}

macro_rules! define_common_ops {
    ($($ty:ident),+) => {
        $(
            impl ::std::ops::Add for $ty {
                type Output = Self;
                #[inline(always)]
                fn add(self, other: Self) -> Self {
                    unsafe { simd_add(self, other) }
                }
            }

            impl ::std::ops::Sub for $ty {
                type Output = Self;
                #[inline(always)]
                fn sub(self, other: Self) -> Self {
                    unsafe { simd_sub(self, other) }
                }
            }

            impl ::std::ops::Mul for $ty {
                type Output = Self;
                #[inline(always)]
                fn mul(self, other: Self) -> Self {
                    unsafe { simd_mul(self, other) }
                }
            }
        )+
    }
}

macro_rules! define_float_ops {
    ($($ty:ident),+) => {
        $(
            impl ::std::ops::Div for $ty {
                type Output = Self;
                #[inline(always)]
                fn div(self, other: Self) -> Self {
                    unsafe { simd_div(self, other) }
                }
            }
        )+
    }
}

macro_rules! define_shifts {
    ($ty:ident, $elem:ident, $($by:ident),+) => {
        $(
            impl ::std::ops::Shl<$by> for $ty {
                type Output = Self;
                #[inline(always)]
                fn shl(self, other: $by) -> Self {
                    unsafe { simd_shl(self, $ty::splat(other as $elem)) }
                }
            }
            impl ::std::ops::Shr<$by> for $ty {
                type Output = Self;
                #[inline(always)]
                fn shr(self, other: $by) -> Self {
                    unsafe { simd_shr(self, $ty::splat(other as $elem)) }
                }
            }
        )+
    }
}

macro_rules! define_integer_ops {
    ($(($ty:ident, $elem:ident)),+) => {
        $(
            impl ::std::ops::BitAnd for $ty {
                type Output = Self;
                #[inline(always)]
                fn bitand(self, other: Self) -> Self {
                    unsafe { simd_and(self, other) }
                }
            }
            impl ::std::ops::BitOr for $ty {
                type Output = Self;
                #[inline(always)]
                fn bitor(self, other: Self) -> Self {
                    unsafe { simd_or(self, other) }
                }
            }
            impl ::std::ops::BitXor for $ty {
                type Output = Self;
                #[inline(always)]
                fn bitxor(self, other: Self) -> Self {
                    unsafe { simd_xor(self, other) }
                }
            }
            impl ::std::ops::Not for $ty {
                type Output = Self;
                #[inline(always)]
                fn not(self) -> Self {
                    $ty::splat(!0) ^ self
                }
            }
            define_shifts!(
                $ty, $elem,
                u8, u16, u32, u64, usize,
                i8, i16, i32, i64, isize);

            impl ::std::fmt::LowerHex for $ty {
                fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                    write!(f, "{}(", stringify!($ty))?;
                    let n = ::std::mem::size_of_val(self) / ::std::mem::size_of::<$elem>();
                    for i in 0..n {
                        if i > 0 {
                            write!(f, ", ")?;
                        }
                        write!(f, "{:#x}", self.extract(i as u32))?;
                    }
                    write!(f, ")")
                }
            }
        )+
    }
}

macro_rules! define_casts {
    ($(($ty:ident, $floatty:ident, $floatcast:ident)),+) => {
        $(
            impl $ty {
                pub fn $floatcast(self) -> ::$floatty {
                    unsafe { simd_cast(self) }
                }
            }
        )+
    }
}
<|endoftext|>


<commit_before>use rand::distributions::normal::Normal;
use rand;
use rand::distributions::IndependentSample;
use nalgebra::{DMatrix, DVector};

/// Network type which shows how the Network looks like
pub struct Network {
    /// a Vec giving the sizes of the layers
    /// the first entry corresponds to the inputlayer
    /// and the last entry corresponds to the outputlayer
    layers: Vec<u8>,
    /// a Vec that contains the weights of the respective layer
    weights: Vec<DMatrix<f32>>,
    ///
    biases: Vec<DVector<f32>>,
}

impl Network {
    /// build a new Network by given parameters
    pub fn new(sizes: Vec<u8>) -> Result<Network, &'static str> {
        use rand::distributions::{Normal, IndependentSample};

        if sizes.len() < 3 {
            return Err("Not enough layers");
        }

        // Store the weights and biases in lists
        // We will not need weights or biases for input layer, so ignore that (hence -1)
        let mut weights: Vec<DMatrix<f32>> = Vec::with_capacity(sizes.len() - 1);
        let mut biases: Vec<DVector<f32>> = Vec::with_capacity(sizes.len() - 1);

        let mut rng = rand::thread_rng();
        let normal = Normal::new(0.0, 1.0);

        for i in 1..sizes.len() {

            unsafe {
                biases.push(DVector::new_uninitialized(sizes[i] as usize));
            }

            for j in 0..sizes[i] {
                biases[i - 1][j as usize] = normal.ind_sample(&mut rng) as f32;
            }
            weights.push(DMatrix::new_random_normal(sizes[i - 1] as usize, sizes[i] as usize));
        }

        Ok(Network {
            layers: sizes,
            weights: weights,
            biases: biases,
        })
    }

    /// returns the layers
    pub fn get_layers(&self) -> &Vec<u8> {
        &self.layers
    }

    /// returns the weights
    pub fn get_weights(&self) -> &Vec<DMatrix<f32>> {
        &self.weights
    }

    /// returns the biases
    pub fn get_biases(&self) -> &Vec<DVector<f32>> {
        &self.biases
    }
}

/// trait for implementing random values from 0 to 1
trait Random {
    fn new_random_normal(rows: usize, columns: usize) -> DMatrix<f32>;
}

impl Random for DMatrix<f32> {
    /// Implements random number initializer for DMatrix
    fn new_random_normal(rows: usize, columns: usize) -> DMatrix<f32> {

        // Init the DMatrix with rows and columns
        let mut res;
        unsafe {
            res = DMatrix::new_uninitialized(rows, columns);
        }

        // random number between 0 and 1
        let mut rng = rand::thread_rng();
        let normal = Normal::new(0.0, 1.0);

        // fills matrix with random numbers from 0 and 1
        for i in 0..rows {
            for j in 0..columns {
                res[(i, j)] = normal.ind_sample(&mut rng) as f32;
            }
        }

        res
    }
}
<commit_msg>improve nn/mod.rs<commit_after>use rand;
use rand::Rng;
use rand::distributions::normal::StandardNormal;
use nalgebra::DMatrix;

/// Artificial Neural Network
///
/// This struct represents a simple Artificial Neural Network (ANN) using
/// feedforward and backpropagation. It uses Stochastic Gradient Descent(SGD)
/// and a sigmoid activation function.
///
/// [Source](http://neuralnetworksanddeeplearning.com/chap1.html)
///
/// # Example
///
/// ```rust
/// // This will create a new ANN with the following topology:
/// // 3 "neurons" in the input layer
/// // 5 "neurons" in the first hidden layer
/// // 3 "neurons" in the second hidden layer
/// // 2 "neurons" in the output layer
/// let nnet = Network::new(vec![3, 5, 2]);
/// ```
#[derive(Debug, Clone)]
pub struct Network {
    /// a Vec outlining the topology of the ANN
    /// the first entry corresponds to the inputlayer,
    /// the intermediate entries correspond to the hidden layers
    /// and the last entry corresponds to the outputlayer.
    layers: Vec<u8>,
    /// a Vec that contains the weights of the respective layer
    weights: Vec<DMatrix<f64>>,
    /// a Vec cointaining the biases of the respective layer
    biases: Vec<DMatrix<f64>>,
}

impl Network {
    /// build a new Network with a topology Vector
    pub fn new(sizes: Vec<u8>) -> Result<Network, &'static str> {
        if sizes.len() < 3 {
            return Err("Not enough layers");
        }

        // Store the weights and biases in lists
        // We will not need weights or biases for input layer, so ignore that (hence -1)
        let mut weights: Vec<DMatrix<f64>> = Vec::with_capacity(sizes.len() - 1);
        let mut biases: Vec<DMatrix<f64>> = Vec::with_capacity(sizes.len() - 1);

        let mut rng = rand::thread_rng();

        // we use the standard normal distribution to initialize weights and biases - why?
        for (i, layer) in sizes.iter().enumerate().skip(1) {
            // initialize weight matrices
            weights.push(DMatrix::from_fn(sizes[i - 1] as usize, *layer as usize, |_, _| {
                let StandardNormal(x) = rng.gen();
                x
            }));

            // initialize biases
            biases.push(DMatrix::from_fn(*layer as usize, 1, |_, _| {
                let StandardNormal(x) = rng.gen();
                x
            }));
        }

        Ok(Network {
            layers: sizes,
            weights: weights,
            biases: biases,
        })
    }

    /// return the layers used to initialize the ANN
    pub fn get_layers(&self) -> &Vec<u8> {
        &self.layers
    }

    /// return a vector of the weight matrices of the ANN
    pub fn get_weights(&self) -> &Vec<DMatrix<f64>> {
        &self.weights
    }

    /// return a vector of the bias matrices of the ANN
    pub fn get_biases(&self) -> &Vec<DMatrix<f64>> {
        &self.biases
    }
}
<|endoftext|>


<commit_before>//! The parser works based on the following grammar
//!
//! Equation ==> Term { "+" Term }
//!           |  Term { "-" Term }
//!
//! Term     ==> Function Product
//!           |  Product
//!
//! Product  ==> Factor { "*" Factor }
//!           |  Factor { "/" Factor }
//!
//! Factor   ==> "-" Factor
//!           |  Exponent { "^" Factor }
//!
//! Exponent ==> Number { "!" }
//!
//! Number   ==> "(" Equation ")"
//!           |  "|" Equation "|"
//!           |  Constant
//!           |  { Digit }
//!
//! Function ==> "sin" | "cos" | "tan" | "asin" | "acos" | "atan" | "sqrt" | "qbrt" | "abs" | "exp"
//!           |  "ln" | "log"
//!
//! Constant ==> "pi" | "e" | "phi"
//!
//! Digit    ==> "0".."9"

use std::str::CharRange;
use errors::{CResult, CError};
use ast::{Ast, AstFunc};
use ast::AstBranch::*;
use ast::AstVal::*;
use ast::AstFunc::*;
use ast::AstOp::*;
use ast::AstConst::*;

#[derive(Debug)]
pub struct Parser {
    pos: usize,
    input: String,
    paren_level: u32,
    abs_level: u32,
}

impl Parser {
    pub fn new(input: String) -> Self {
        Parser {
            pos: 0,
            input: input,
            paren_level: 0,
            abs_level: 0,
        }
    }

    pub fn parse_equation(&mut self) -> CResult<Ast> {
        let mut lhs = try!(self.parse_term());
        self.consume_whitespace();
        while self.peek_char() == Some('+') || self.peek_char() == Some('-') {
            let op_pos = self.pos;
            let op = if self.consume_char() == '+' {
                Plus
            } else {
                Minus
            };
            self.consume_whitespace();
            let rhs = try!(self.parse_term());
            lhs = Ast {
                val: Op(op),
                span: (op_pos, op_pos),
                branches: Binary(Box::new(lhs), Box::new(rhs)),
            };
            self.consume_whitespace();
        }
        Ok(lhs)
    }

    fn parse_term(&mut self) -> CResult<Ast> {
        let begin_pos = self.pos;
        if let Some(func) = self.consume_function() {
            let end_pos = self.pos;
            self.consume_whitespace();
            let arg = try!(self.parse_product());
            Ok(Ast {
                val: Func(func),
                span: (begin_pos, end_pos),
                branches: Unary(Box::new(arg)),
            })
        } else {
            self.parse_product()
        }
    }

    fn parse_product(&mut self) -> CResult<Ast> {
        let mut lhs = try!(self.parse_factor());
        self.consume_whitespace();
        while self.peek_char() == Some('*') || self.peek_char() == Some('/') {
            let op_pos = self.pos;
            let op = if self.consume_char() == '*' {
                Mult
            } else {
                Div
            };
            self.consume_whitespace();
            let rhs = try!(self.parse_factor());
            lhs = Ast {
                val: Op(op),
                span: (op_pos, op_pos),
                branches: Binary(Box::new(lhs), Box::new(rhs)),
            };
            self.consume_whitespace();
        }
        Ok(lhs)
    }

    fn parse_factor(&mut self) -> CResult<Ast> {
        if self.peek_char() == Some('-') {
            let op_pos = self.pos;
            self.consume_char();
            let rhs = try!(self.parse_factor());
            Ok(Ast {
                val: Op(Neg),
                span: (op_pos, op_pos),
                branches: Unary(Box::new(rhs)),
            })
        } else {
            let lhs = try!(self.parse_exponent());
            if self.peek_char() == Some('^') {
                let op_pos = self.pos;
                self.consume_char();
                let rhs = try!(self.parse_factor());
                Ok(Ast {
                    val: Op(Pow),
                    span: (op_pos, op_pos),
                    branches: Binary(Box::new(lhs), Box::new(rhs)),
                })
            } else {
                Ok(lhs)
            }
        }
    }

    fn parse_exponent(&mut self) -> CResult<Ast> {
        let mut out = try!(self.parse_number());
        self.consume_whitespace();

        // we don't parse the factorial signs (`!`) using recursion, since we need to put the
        // current `out` at the bottum of the tree at each step, so it is easier if we have access
        // to each node as we create them.
        while self.peek_char() == Some('!') {
            let op_pos = self.pos;
            self.consume_char();
            self.consume_whitespace();
            out = Ast {
                val: Op(Fact),
                span: (op_pos, op_pos),
                branches: Unary(Box::new(out)),
            };
        }
        Ok(out)
    }

    fn parse_number(&mut self) -> CResult<Ast> {
        match self.peek_char() {
            Some('(') => {
                // store the current pos in case we need to report a paren error
                let pre_pos = self.pos;
                self.consume_char();
                self.consume_whitespace();
                self.paren_level += 1;
                let eq = try!(self.parse_equation());

                if self.eof() || self.consume_char() != ')' {
                    Err(CError {
                        desc: "Missing closing parentheses".to_string(),
                        span: (pre_pos, pre_pos),
                    })
                } else {
                    self.paren_level -= 1;
                    Ok(eq)
                }
            },
            Some('|') => {
                // store the current pos in case we need to report an abs delim error
                let pre_pos = self.pos;
                self.consume_char();
                self.consume_whitespace();
                self.abs_level += 1;
                let eq = try!(self.parse_equation());

                if self.eof() || self.consume_char() != '|' {
                    Err(CError {
                        desc: "Missing closing abs delimiter".to_string(),
                        span: (pre_pos, pre_pos),
                    })
                } else {
                    self.abs_level -= 1;
                    Ok(Ast {
                        val: Func(Abs),
                        span: (pre_pos, pre_pos),
                        branches: Unary(Box::new(eq)),
                    })
                }
            },
            Some(ch) if ch.is_alphabetic() => {
                let cnst_str = self.consume_while(|ch| ch.is_alphabetic());
                let cnst = match cnst_str.as_slice() {
                    "pi" => Pi,
                    "e" => E,
                    "phi" => Phi,
                    _ => return Err(CError {
                        desc: format!("Invalid function or constant: {}", cnst_str),
                        span: (self.pos - cnst_str.len(), self.pos),
                    }),
                };
                Ok(Ast {
                    val: Const(cnst),
                    span: (self.pos - cnst_str.len(), self.pos),
                    branches: Leaf,
                })
            },
            Some(ch) if ch.is_numeric() => {
                let num_str = self.consume_while(|ch| ch.is_numeric() || ch == '.');
                if let Ok(num) = num_str.parse::<f64>() {
                    Ok(Ast {
                        val: Num(num),
                        span: (self.pos - num_str.len(), self.pos),
                        branches: Leaf,
                    })
                } else {
                    Err(CError {
                        desc: format!("Invalid number: {}", num_str),
                        span: (self.pos - num_str.len(), self.pos),
                    })
                }
            },
            Some(')') => {
                Err(CError {
                    desc: format!("Missing opening parentheses"),
                    span: (self.pos, self.pos),
                })
            },
            Some(ch) => {
                Err(CError {
                    desc: format!("Illegal character: {}", ch),
                    span: (self.pos, self.pos),
                })
            },
            _ => Err(CError {
                desc: format!("Unexpected end of equation"),
                span: (self.pos, self.pos),
            }),
        }
    }

    fn consume_function(&mut self) -> Option<AstFunc> {
        let pre_pos = self.pos;
        match self.consume_while(|ch| ch.is_alphabetic()).as_slice() {
            "sin" => Some(Sin),
            "cos" => Some(Cos),
            "tan" => Some(Tan),
            "asin" => Some(Asin),
            "acos" => Some(Acos),
            "atan" => Some(Atan),
            "sqrt" => Some(Sqrt),
            "qbrt" => Some(Qbrt),
            "abs" => Some(Abs),
            "exp" => Some(Exp),
            "ln" => Some(Ln),
            "log" => Some(Log),
            _ => {
                // no function found, so restore the previous position
                self.pos = pre_pos;
                None
            },
        }
    }

    /// Peeks at the next `char` and returns `Some` if one was found, or `None` if none are left
    fn peek_char(&self) -> Option<char> {
        if self.eof() {
            None
        } else {
            Some(self.input.char_at(self.pos).to_lowercase())
        }
    }

    /// Consumes a `char` - thereby advanding `pos` - and returns it
    ///
    /// # Panics
    /// This function panics if there are no more chars to consume
    fn consume_char(&mut self) -> char {
        let CharRange { ch, next } = self.input.char_range_at(self.pos);
        self.pos = next;
        ch.to_lowercase()
    }

    /// Consumes `char`s long as `pred` returns true and we are not eof
    ///
    /// The `char`s are returned as a `String`. Note that unlike `consume_char` this function will
    /// panic.
    fn consume_while<F>(&mut self, pred: F) -> String where F: Fn(char) -> bool {
        let mut out = String::new();
        loop {
            match self.peek_char() {
                Some(ch) if pred(ch) => out.push(self.consume_char()),
                _ => break,
            }
        }
        out
    }

    /// Consumes any current whitespace
    fn consume_whitespace(&mut self) {
        self.consume_while(|ch| ch.is_whitespace());
    }

    /// Returns true if we are the end of input
    fn eof(&self) -> bool {
        self.pos >= self.input.len()
    }
}<commit_msg>Simplify error reporting in the parser<commit_after>//! The parser works based on the following grammar
//!
//! Equation ==> Term { "+" Term }
//!           |  Term { "-" Term }
//!
//! Term     ==> Function Product
//!           |  Product
//!
//! Product  ==> Factor { "*" Factor }
//!           |  Factor { "/" Factor }
//!
//! Factor   ==> "-" Factor
//!           |  Exponent { "^" Factor }
//!
//! Exponent ==> Number { "!" }
//!
//! Number   ==> "(" Equation ")"
//!           |  "|" Equation "|"
//!           |  Constant
//!           |  { Digit }
//!
//! Function ==> "sin" | "cos" | "tan" | "asin" | "acos" | "atan" | "sqrt" | "qbrt" | "abs" | "exp"
//!           |  "ln" | "log"
//!
//! Constant ==> "pi" | "e" | "phi"
//!
//! Digit    ==> "0".."9"

use std::str::CharRange;
use errors::{CResult, CError};
use ast::{Ast, AstFunc};
use ast::AstBranch::*;
use ast::AstVal::*;
use ast::AstFunc::*;
use ast::AstOp::*;
use ast::AstConst::*;

#[derive(Debug)]
pub struct Parser {
    pos: usize,
    input: String,
    paren_level: u32,
    abs_level: u32,
}

impl Parser {
    pub fn new(input: String) -> Self {
        Parser {
            pos: 0,
            input: input,
            paren_level: 0,
            abs_level: 0,
        }
    }

    pub fn parse_equation(&mut self) -> CResult<Ast> {
        let mut lhs = try!(self.parse_term());
        self.consume_whitespace();
        while self.peek_char() == Some('+') || self.peek_char() == Some('-') {
            let op_pos = self.pos;
            let op = if self.consume_char() == '+' {
                Plus
            } else {
                Minus
            };
            self.consume_whitespace();
            let rhs = try!(self.parse_term());
            lhs = Ast {
                val: Op(op),
                span: (op_pos, op_pos),
                branches: Binary(Box::new(lhs), Box::new(rhs)),
            };
            self.consume_whitespace();
        }
        Ok(lhs)
    }

    fn parse_term(&mut self) -> CResult<Ast> {
        let begin_pos = self.pos;
        if let Some(func) = self.consume_function() {
            let end_pos = self.pos;
            self.consume_whitespace();
            let arg = try!(self.parse_product());
            Ok(Ast {
                val: Func(func),
                span: (begin_pos, end_pos),
                branches: Unary(Box::new(arg)),
            })
        } else {
            self.parse_product()
        }
    }

    fn parse_product(&mut self) -> CResult<Ast> {
        let mut lhs = try!(self.parse_factor());
        self.consume_whitespace();
        while self.peek_char() == Some('*') || self.peek_char() == Some('/') {
            let op_pos = self.pos;
            let op = if self.consume_char() == '*' {
                Mult
            } else {
                Div
            };
            self.consume_whitespace();
            let rhs = try!(self.parse_factor());
            lhs = Ast {
                val: Op(op),
                span: (op_pos, op_pos),
                branches: Binary(Box::new(lhs), Box::new(rhs)),
            };
            self.consume_whitespace();
        }
        Ok(lhs)
    }

    fn parse_factor(&mut self) -> CResult<Ast> {
        if self.peek_char() == Some('-') {
            let op_pos = self.pos;
            self.consume_char();
            let rhs = try!(self.parse_factor());
            Ok(Ast {
                val: Op(Neg),
                span: (op_pos, op_pos),
                branches: Unary(Box::new(rhs)),
            })
        } else {
            let lhs = try!(self.parse_exponent());
            if self.peek_char() == Some('^') {
                let op_pos = self.pos;
                self.consume_char();
                let rhs = try!(self.parse_factor());
                Ok(Ast {
                    val: Op(Pow),
                    span: (op_pos, op_pos),
                    branches: Binary(Box::new(lhs), Box::new(rhs)),
                })
            } else {
                Ok(lhs)
            }
        }
    }

    fn parse_exponent(&mut self) -> CResult<Ast> {
        let mut out = try!(self.parse_number());
        self.consume_whitespace();

        // we don't parse the factorial signs (`!`) using recursion, since we need to put the
        // current `out` at the bottum of the tree at each step, so it is easier if we have access
        // to each node as we create them.
        while self.peek_char() == Some('!') {
            let op_pos = self.pos;
            self.consume_char();
            self.consume_whitespace();
            out = Ast {
                val: Op(Fact),
                span: (op_pos, op_pos),
                branches: Unary(Box::new(out)),
            };
        }
        Ok(out)
    }

    fn parse_number(&mut self) -> CResult<Ast> {
        match self.peek_char() {
            Some('(') => {
                // store the current pos in case we need to report a paren error
                let pre_pos = self.pos;
                self.consume_char();
                self.consume_whitespace();
                self.paren_level += 1;
                let eq = try!(self.parse_equation());

                if self.eof() || self.consume_char() != ')' {
                    Err(CError {
                        desc: "Missing closing parentheses".to_string(),
                        span: (pre_pos, pre_pos),
                    })
                } else {
                    self.paren_level -= 1;
                    Ok(eq)
                }
            },
            Some('|') => {
                // store the current pos in case we need to report an abs delim error
                let pre_pos = self.pos;
                self.consume_char();
                self.consume_whitespace();
                self.abs_level += 1;
                let eq = try!(self.parse_equation());

                if self.eof() || self.consume_char() != '|' {
                    Err(CError {
                        desc: "Missing closing abs delimiter".to_string(),
                        span: (pre_pos, pre_pos),
                    })
                } else {
                    self.abs_level -= 1;
                    Ok(Ast {
                        val: Func(Abs),
                        span: (pre_pos, pre_pos),
                        branches: Unary(Box::new(eq)),
                    })
                }
            },
            Some(ch) if ch.is_alphabetic() => {
                let cnst_str = self.consume_while(|ch| ch.is_alphabetic());
                let cnst = match cnst_str.as_slice() {
                    "pi" => Pi,
                    "e" => E,
                    "phi" => Phi,
                    _ => return Err(CError {
                        desc: format!("Invalid function or constant: {}", cnst_str),
                        span: (self.pos - cnst_str.len(), self.pos),
                    }),
                };
                Ok(Ast {
                    val: Const(cnst),
                    span: (self.pos - cnst_str.len(), self.pos),
                    branches: Leaf,
                })
            },
            Some(ch) if ch.is_numeric() => {
                let num_str = self.consume_while(|ch| ch.is_numeric() || ch == '.');
                if let Ok(num) = num_str.parse::<f64>() {
                    Ok(Ast {
                        val: Num(num),
                        span: (self.pos - num_str.len(), self.pos),
                        branches: Leaf,
                    })
                } else {
                    Err(CError {
                        desc: format!("Invalid number: {}", num_str),
                        span: (self.pos - num_str.len(), self.pos),
                    })
                }
            },
            _ => Err(CError {
                desc: format!("Expected number or constant"),
                span: (self.pos, self.pos),
            }),
        }
    }

    fn consume_function(&mut self) -> Option<AstFunc> {
        let pre_pos = self.pos;
        match self.consume_while(|ch| ch.is_alphabetic()).as_slice() {
            "sin" => Some(Sin),
            "cos" => Some(Cos),
            "tan" => Some(Tan),
            "asin" => Some(Asin),
            "acos" => Some(Acos),
            "atan" => Some(Atan),
            "sqrt" => Some(Sqrt),
            "qbrt" => Some(Qbrt),
            "abs" => Some(Abs),
            "exp" => Some(Exp),
            "ln" => Some(Ln),
            "log" => Some(Log),
            _ => {
                // no function found, so restore the previous position
                self.pos = pre_pos;
                None
            },
        }
    }

    /// Peeks at the next `char` and returns `Some` if one was found, or `None` if none are left
    fn peek_char(&self) -> Option<char> {
        if self.eof() {
            None
        } else {
            Some(self.input.char_at(self.pos).to_lowercase())
        }
    }

    /// Consumes a `char` - thereby advanding `pos` - and returns it
    ///
    /// # Panics
    /// This function panics if there are no more chars to consume
    fn consume_char(&mut self) -> char {
        let CharRange { ch, next } = self.input.char_range_at(self.pos);
        self.pos = next;
        ch.to_lowercase()
    }

    /// Consumes `char`s long as `pred` returns true and we are not eof
    ///
    /// The `char`s are returned as a `String`. Note that unlike `consume_char` this function will
    /// panic.
    fn consume_while<F>(&mut self, pred: F) -> String where F: Fn(char) -> bool {
        let mut out = String::new();
        loop {
            match self.peek_char() {
                Some(ch) if pred(ch) => out.push(self.consume_char()),
                _ => break,
            }
        }
        out
    }

    /// Consumes any current whitespace
    fn consume_whitespace(&mut self) {
        self.consume_while(|ch| ch.is_whitespace());
    }

    /// Returns true if we are the end of input
    fn eof(&self) -> bool {
        self.pos >= self.input.len()
    }
}<|endoftext|>


<commit_before>use super::ast::{Instruction, Program};

pub fn parse_program(input: &[u8]) -> Result<Program, &'static str> {
    let (program, rest) = parse_instructions(input)?;
    if rest.is_empty() {
        Ok(program)
    } else {
        Err("extra input")
    }
}

type Parser<'a, R> = Result<(R, &'a [u8]), &'static str>;

fn parse_instruction(mut input: &[u8]) -> Parser<Option<Instruction>> {
    loop {
        if input.is_empty() {
            return Ok((None, input));
        } else {
            let c = input[0];
            input = &input[1..];
            match c {
                b'<' => return Ok((Some(Instruction::Left), input)),
                b'>' => return Ok((Some(Instruction::Right), input)),
                b'+' => return Ok((Some(Instruction::Up), input)),
                b'-' => return Ok((Some(Instruction::Down), input)),
                b',' => return Ok((Some(Instruction::In), input)),
                b'.' => return Ok((Some(Instruction::Out), input)),
                b']' => return Err("extra input"),
                b'[' => match parse_instructions(input) {
                    Err(e) => return Err(e),
                    Ok((program, next_input)) => {
                        input = next_input;
                        loop {
                            if input.is_empty() {
                                return Err("unmatched [");
                            } else {
                                let c = input[0];
                                input = &input[1..];
                                match c {
                                    b']' => return Ok((Some(Instruction::Loop(program)), input)),
                                    _    => { /* pass */ }
                                }
                            }
                        }
                    }
                },
                _   => {
                    // pass
                },
            }
        }
    }
}

fn parse_instructions(mut input: &[u8]) -> Parser<Program> {
    let mut instructions = Vec::new();

    loop {
        match parse_instruction(input) {
            Ok((Some(instruction), next_input)) => {
                instructions.push(instruction);
                input = next_input;
            }

            Ok((None, next_input)) => {
                input = next_input;
                break;
            }

            Err(e @ "unmatched [") => return Err(e),

            _ => break,
        }
    }

    Ok((instructions.into_boxed_slice(), input))
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::super::ast::*;
    use self::Instruction::*;

    #[test]
    fn single_byte_instructions_parse() {
        assert_parse("<", &[Left]);
        assert_parse(">", &[Right]);
        assert_parse("+", &[Up]);
        assert_parse("-", &[Down]);
        assert_parse(",", &[In]);
        assert_parse(".", &[Out]);
    }

    #[test]
    fn multiple_instructions_parse() {
        assert_parse("<><>+-+-.",
                     &[Left, Right, Left, Right, Up, Down, Up, Down, Out]);
    }

    #[test]
    fn empty_program_parses() {
        assert_parse("", &[]);
    }

    #[test]
    fn empty_loop_parses() {
        assert_parse("[]", &[make_loop(vec![])]);
    }

    #[test]
    fn non_empty_loop_parses() {
        assert_parse("[<]", &[make_loop(vec![Left])]);
        assert_parse("[<.>]", &[make_loop(vec![Left, Out, Right])]);
    }

    #[test]
    fn nested_loops_parse() {
        assert_parse("[<[]]",
                     &[make_loop(vec![Left, make_loop(vec![])])]);
        assert_parse("[<[+],]",
                     &[make_loop(vec![Left, make_loop(vec![Up]), In])]);
    }

    #[test]
    fn comment_is_ignored() {
        assert_parse("hello <", &[Left]);
        assert_parse("h[e<l[l+o] ,world]",
                     &[make_loop(vec![Left, make_loop(vec![Up]), In])]);
    }

    #[test]
    fn trailing_comment_is_ignored() {
        assert_parse("< hello", &[Left]);
    }

    #[test]
    fn all_comment_program_parses() {
        assert_parse("hello", &[]);
    }

    #[test]
    fn left_bracket_without_right_is_error() {
        assert_parse_error("[", "unmatched [");
    }

    #[test]
    fn right_bracket_without_left_is_error() {
        assert_parse_error("]", "extra input");
    }

    fn assert_parse(input: &str, program: &[Instruction]) {
        assert_eq!(parse_program(input.as_bytes()), Ok(program.to_vec().into_boxed_slice()));
    }

    fn assert_parse_error(input: &str, message: &str) {
        assert_eq!(parse_program(input.as_bytes()), Err(message));
    }
}
<commit_msg>Better error messages.<commit_after>use super::ast::{Instruction, Program};

pub fn parse_program(input: &[u8]) -> Result<Program, &'static str> {
    let (program, rest) = parse_instructions(input)?;
    if rest.is_empty() {
        Ok(program)
    } else {
        Err("unmatched ]")
    }
}

type Parser<'a, R> = Result<(R, &'a [u8]), &'static str>;

fn parse_instruction(mut input: &[u8]) -> Parser<Option<Instruction>> {
    loop {
        if input.is_empty() {
            return Ok((None, input));
        } else {
            let c = input[0];
            input = &input[1..];
            match c {
                b'<' => return Ok((Some(Instruction::Left), input)),
                b'>' => return Ok((Some(Instruction::Right), input)),
                b'+' => return Ok((Some(Instruction::Up), input)),
                b'-' => return Ok((Some(Instruction::Down), input)),
                b',' => return Ok((Some(Instruction::In), input)),
                b'.' => return Ok((Some(Instruction::Out), input)),
                b']' => return Err("unmatched ]"),
                b'[' => match parse_instructions(input) {
                    Err(e) => return Err(e),
                    Ok((program, next_input)) => {
                        input = next_input;
                        loop {
                            if input.is_empty() {
                                return Err("unmatched [");
                            } else {
                                let c = input[0];
                                input = &input[1..];
                                match c {
                                    b']' => return Ok((Some(Instruction::Loop(program)), input)),
                                    _    => { /* pass */ }
                                }
                            }
                        }
                    }
                },
                _   => {
                    // pass
                },
            }
        }
    }
}

fn parse_instructions(mut input: &[u8]) -> Parser<Program> {
    let mut instructions = Vec::new();

    loop {
        match parse_instruction(input) {
            Ok((Some(instruction), next_input)) => {
                instructions.push(instruction);
                input = next_input;
            }

            Ok((None, next_input)) => {
                input = next_input;
                break;
            }

            Err(e @ "unmatched [") => return Err(e),

            _ => break,
        }
    }

    Ok((instructions.into_boxed_slice(), input))
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::super::ast::*;
    use self::Instruction::*;

    #[test]
    fn single_byte_instructions_parse() {
        assert_parse("<", &[Left]);
        assert_parse(">", &[Right]);
        assert_parse("+", &[Up]);
        assert_parse("-", &[Down]);
        assert_parse(",", &[In]);
        assert_parse(".", &[Out]);
    }

    #[test]
    fn multiple_instructions_parse() {
        assert_parse("<><>+-+-.",
                     &[Left, Right, Left, Right, Up, Down, Up, Down, Out]);
    }

    #[test]
    fn empty_program_parses() {
        assert_parse("", &[]);
    }

    #[test]
    fn empty_loop_parses() {
        assert_parse("[]", &[make_loop(vec![])]);
    }

    #[test]
    fn non_empty_loop_parses() {
        assert_parse("[<]", &[make_loop(vec![Left])]);
        assert_parse("[<.>]", &[make_loop(vec![Left, Out, Right])]);
    }

    #[test]
    fn nested_loops_parse() {
        assert_parse("[<[]]",
                     &[make_loop(vec![Left, make_loop(vec![])])]);
        assert_parse("[<[+],]",
                     &[make_loop(vec![Left, make_loop(vec![Up]), In])]);
    }

    #[test]
    fn comment_is_ignored() {
        assert_parse("hello <", &[Left]);
        assert_parse("h[e<l[l+o] ,world]",
                     &[make_loop(vec![Left, make_loop(vec![Up]), In])]);
    }

    #[test]
    fn trailing_comment_is_ignored() {
        assert_parse("< hello", &[Left]);
    }

    #[test]
    fn all_comment_program_parses() {
        assert_parse("hello", &[]);
    }

    #[test]
    fn left_bracket_without_right_is_error() {
        assert_parse_error("[", "unmatched [");
        assert_parse_error("[<[.]", "unmatched [");
    }

    #[test]
    fn right_bracket_without_left_is_error() {
        assert_parse_error("]", "unmatched ]");
        assert_parse_error(".[.].]", "unmatched ]");
    }

    fn assert_parse(input: &str, program: &[Instruction]) {
        assert_eq!(parse_program(input.as_bytes()), Ok(program.to_vec().into_boxed_slice()));
    }

    fn assert_parse_error(input: &str, message: &str) {
        assert_eq!(parse_program(input.as_bytes()), Err(message));
    }
}
<|endoftext|>


<commit_before>//! A parser for lambda expressions

use term::{Term, Notation, abs, app};
use term::Term::*;
use self::Token::*;
use self::CToken::*;
use self::Error::*;
use self::Expression::*;
pub use term::Notation::*;

/// A type to represent a parsing error.
#[derive(Debug, PartialEq)]
pub enum Error {
    /// an invalid character was encountered
    InvalidCharacter((usize, char)),
    /// the expression is invalid
    InvalidExpression,
    /// the expression is empty
    EmptyExpression
}

#[derive(Debug, PartialEq)]
enum Token {
    /// λ or \
    Lambda,
    /// left parenthesis
    Lparen,
    /// right parenthesis
    Rparen,
    /// a number
    Number(usize)
}

#[derive(Debug, PartialEq)]
enum CToken {
    /// an abstraction with a bound variable
    CLambda(String),
    /// left parenthesis
    CLparen,
    /// right parenthesis
    CRparen,
    /// a variable with an identifier
    CName(String)
}

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

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

    Ok(tokens)
}

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

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

    Ok(tokens)
}

fn convert_classic_tokens(tokens: &[CToken]) -> Vec<Token> {
    _convert_classic_tokens(tokens, &mut Vec::new(), &mut 0)
}

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

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

    output
}

#[derive(Debug, PartialEq)]
enum Expression {
    /// an abstraction
    Abstraction,
    /// a sequence of Expressions
    Sequence(Vec<Expression>),
    /// a variable with a De Bruijn index
    Variable(usize)
}

fn get_ast(tokens: &[Token]) -> Result<Expression, Error> {
    _get_ast(tokens, &mut 0)
}

fn _get_ast(tokens: &[Token], pos: &mut usize) -> Result<Expression, Error> {
    if tokens.is_empty() { return Err(EmptyExpression) }

    let mut expr = Vec::new();

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

    Ok(Sequence(expr))
}

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

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

    fold_exprs(&exprs)
}

fn fold_exprs(exprs: &[Expression]) -> Result<Term, Error> {
    let mut depth  = 0;
    let mut output = Vec::new();

    for expr in exprs.iter() {
        match *expr {
            Variable(i) => output.push(Var(i)),
            Abstraction => depth += 1,
            Sequence(ref exprs) => {
                let subexpr = try!(fold_exprs(exprs));
                output.push(subexpr)
            }
        }
    }

    let mut ret = try!(fold_terms(output));

    for _ in 0..depth {
        ret = abs(ret);
    }

    Ok(ret)
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

use term::{Term, Notation, abs, app};
use term::Term::*;
use self::Token::*;
use self::CToken::*;
use self::Error::*;
use self::Expression::*;
pub use term::Notation::*;

/// A type to represent a parsing error.
#[derive(Debug, PartialEq)]
pub enum Error {
    /// an invalid character was encountered
    InvalidCharacter((usize, char)),
    /// the expression is invalid
    InvalidExpression,
    /// the expression is empty
    EmptyExpression
}

#[derive(Debug, PartialEq)]
enum Token {
    /// λ or \
    Lambda,
    /// left parenthesis
    Lparen,
    /// right parenthesis
    Rparen,
    /// a number
    Number(usize)
}

#[derive(Debug, PartialEq)]
enum CToken {
    /// an abstraction with a bound variable
    CLambda(String),
    /// left parenthesis
    CLparen,
    /// right parenthesis
    CRparen,
    /// a variable with an identifier
    CName(String)
}

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

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

    Ok(tokens)
}

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

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

    Ok(tokens)
}

fn convert_classic_tokens(tokens: &[CToken]) -> Vec<Token> {
    _convert_classic_tokens(tokens, &mut Vec::new(), &mut 0)
}

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

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

    output
}

#[derive(Debug, PartialEq)]
enum Expression {
    /// an abstraction
    Abstraction,
    /// a sequence of Expressions
    Sequence(Vec<Expression>),
    /// a variable with a De Bruijn index
    Variable(usize)
}

fn get_ast(tokens: &[Token]) -> Result<Expression, Error> {
    _get_ast(tokens, &mut 0)
}

fn _get_ast(tokens: &[Token], pos: &mut usize) -> Result<Expression, Error> {
    if tokens.is_empty() { return Err(EmptyExpression) }

    let mut expr = Vec::new();

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

    Ok(Sequence(expr))
}

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

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

    fold_exprs(&exprs)
}

fn fold_exprs(exprs: &[Expression]) -> Result<Term, Error> {
    let mut depth  = 0;
    let mut output = Vec::new();

    for expr in exprs.iter() {
        match *expr {
            Variable(i) => output.push(Var(i)),
            Abstraction => depth += 1,
            Sequence(ref exprs) => {
                let subexpr = try!(fold_exprs(exprs));
                output.push(subexpr)
            }
        }
    }

    let mut ret = try!(fold_terms(output));

    for _ in 0..depth {
        ret = abs(ret);
    }

    Ok(ret)
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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