<commit_before>/// # Models
///
/// Here lies the data structures that a rocket league replay is decoded into. All of the models
/// are contained in this one file because of serde.
///
/// For serde, we only care about serialization, JSON serialization. Deserialization is not
/// implemented from our JSON output because it is lossy (JSON isn't the best with different
/// numeric/string types). Asking "why JSON" would be next logical step, and that's due to other
/// rocket league replay parsers (like Octane) using JSON; however, the output of this library is
/// not compatible with that of other rocket league replay parsers.

use serde::{Serialize, Serializer};
use serde::ser::{SerializeMap, SerializeSeq};
use std::collections::HashMap;
use std::borrow::Cow;
use network::Frame;

/// The structure that a rocket league replay is parsed into.
#[derive(Serialize, PartialEq, Debug, Clone)]
pub struct Replay<'a> {
    pub header_size: i32,
    pub header_crc: i32,
    pub major_version: i32,
    pub minor_version: i32,
    pub net_version: Option<i32>,
    pub game_type: Cow<'a, str>,

    /// Could use a map to represent properties but I don't want to assume that duplicate keys
    /// can't exist, so to be safe, use a traditional vector.
    #[serde(serialize_with = "pair_vec")]
    pub properties: Vec<(&'a str, HeaderProp<'a>)>,
    pub content_size: i32,
    pub content_crc: i32,
    pub network_frames: Option<NetworkFrames>,
    pub levels: Vec<Cow<'a, str>>,
    pub keyframes: Vec<KeyFrame>,
    pub debug_info: Vec<DebugInfo<'a>>,
    pub tick_marks: Vec<TickMark<'a>>,
    pub packages: Vec<Cow<'a, str>>,
    pub objects: Vec<Cow<'a, str>>,
    pub names: Vec<Cow<'a, str>>,
    pub class_indices: Vec<ClassIndex<'a>>,
    pub net_cache: Vec<ClassNetCache>,
}

/// The frames decoded from the network data
#[derive(Serialize, PartialEq, Debug, Clone)]
pub struct NetworkFrames {
    pub frames: Vec<Frame>,
}

/// In Rocket league replays, there are tickmarks that typically represent a significant event in
/// the game (eg. a goal). The tick mark is placed before the event happens so there is a ramp-up
/// time. For instance, a tickmark could be at frame 396 for a goal at frame 441. At 30 fps, this
/// would be 1.5 seconds of ramp up time.
#[derive(Serialize, PartialEq, Debug, Clone)]
pub struct TickMark<'a> {
    pub description: Cow<'a, str>,
    pub frame: i32,
}

/// Keyframes as defined by the video compression section in the [wikipedia][] article, are the
/// main frames that are derived from in the following frame data. The key frames decoded will
/// match up with the frames decoded from the network data.
///
/// [wikipedia]: https://en.wikipedia.org/wiki/Key_frame#Video_compression
#[derive(Serialize, PartialEq, Debug, Clone, Copy)]
pub struct KeyFrame {
    pub time: f32,
    pub frame: i32,
    pub position: i32,
}

/// All the interesting data are stored as properties in the header, properties such as:
///
/// - When and who scored a goal
/// - Player stats (goals, assists, score, etc).
/// - Date and level played on
///
/// A property can be a number, string, or a more complex object such as an array containing
/// additional properties.
#[derive(PartialEq, Debug, Clone)]
pub enum HeaderProp<'a> {
    Array(Vec<Vec<(&'a str, HeaderProp<'a>)>>),
    Bool(bool),
    Byte,
    Float(f32),
    Int(i32),
    Name(Cow<'a, str>),
    QWord(i64),
    Str(Cow<'a, str>),
}

/// Debugging info stored in the replay if debugging is enabled.
#[derive(Serialize, PartialEq, Debug, Clone)]
pub struct DebugInfo<'a> {
    pub frame: i32,
    pub user: Cow<'a, str>,
    pub text: Cow<'a, str>,
}

/// A mapping between an object's name and its index. Largely redundant
#[derive(Serialize, PartialEq, Debug, Clone)]
pub struct ClassIndex<'a> {
    /// Should be equivalent to `Replay::objects(self.index)`
    pub class: &'a str,

    /// The index that the object appears in the `Replay::objects`
    pub index: i32,
}

/// A mapping between an object (that's an attribute)'s index and what its id will be when encoded
/// in the network data
#[derive(Serialize, PartialEq, Debug, Clone, Copy)]
pub struct CacheProp {
    /// The index that the object appears in the `Replay::objects`
    pub object_ind: i32,

    /// An attribute / property id that appears in the network data. Stream ids are often re-used
    /// between multiple different properties
    pub stream_id: i32,
}

/// Contains useful information when decoding the network stream, which we aren't
#[derive(Serialize, PartialEq, Debug, Clone)]
pub struct ClassNetCache {
    /// The index that the object appears in the `Replay::objects`
    pub object_ind: i32,

    /// The cache id of the parent. The child class inherits all the parent's properties.
    pub parent_id: i32,

    /// The cache id of the object
    pub cache_id: i32,

    /// List of properties that is on the object.
    pub properties: Vec<CacheProp>,
}

/// Serialize a vector of key value tuples into a map. This is useful when the data we're ingesting
/// (rocket league replay data) doesn't have a defined spec, so it may be assuming too much to
/// store it into an associative array, so it's stored as a normal sequence. Here we serialize as a
/// map structure because most replay parser do this, so we should be compliant and the data format
/// doesn't dictate that the keys in a sequence of key value pairs must be distinct. It's true,
/// JSON doesn't need the keys to be unique: <http://stackoverflow.com/q/21832701/433785>
fn pair_vec<K, V, S>(inp: &[(K, V)], serializer: S) -> Result<S::Ok, S::Error>
where
    K: Serialize,
    V: Serialize,
    S: Serializer,
{
    let mut state = try!(serializer.serialize_map(Some(inp.len())));
    for &(ref key, ref val) in inp.iter() {
        try!(state.serialize_key(key));
        try!(state.serialize_value(val));
    }
    state.end()
}

/// By default serde will generate a serialization method that writes out the enum as well as the
/// enum value. Since header values are self describing in JSON, we do not need to serialize the
/// enum type. This is slightly lossy as in the serialized format it will be ambiguous if a value
/// is a `Name` or `Str`, as well as `Byte`, `Float`, `Int`, or `QWord`.
impl<'a> Serialize for HeaderProp<'a> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        match *self {
            HeaderProp::Array(ref x) => {
                let mut state = try!(serializer.serialize_seq(Some(x.len())));
                for inner in x {
                    // Look for a better way to do this instead of allocating the intermediate map
                    let mut els = HashMap::new();
                    for &(key, ref val) in inner.iter() {
                        els.insert(key, val);
                    }
                    try!(state.serialize_element(&els));
                }
                state.end()
            }
            HeaderProp::Bool(ref x) => serializer.serialize_bool(*x),
            HeaderProp::Byte => serializer.serialize_u8(0),
            HeaderProp::Float(ref x) => serializer.serialize_f32(*x),
            HeaderProp::Int(ref x) => serializer.serialize_i32(*x),
            HeaderProp::QWord(ref x) => serializer.serialize_i64(*x),
            HeaderProp::Name(ref x) | HeaderProp::Str(ref x) => serializer.serialize_str(x),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde;
    use std;
    use serde_json;
    use std::borrow::Cow;

    fn to_json<T: serde::Serialize>(input: &T) -> std::string::String {
        serde_json::to_string(input).unwrap()
    }

    #[test]
    fn serialize_header_array() {
        let data = vec![
            vec![
                ("frame", HeaderProp::Int(441)),
                (
                    "PlayerName",
                    HeaderProp::Str(Cow::Borrowed("rust is awesome")),
                ),
            ],
            vec![
                ("frame", HeaderProp::Int(1738)),
                ("PlayerName", HeaderProp::Str(Cow::Borrowed("rusty"))),
            ],
        ];
        let actual = to_json(&HeaderProp::Array(data));
        assert!(actual.contains("\"PlayerName\":\"rust is awesome\""));
        assert!(actual.contains("\"PlayerName\":\"rusty\""));
        assert!(actual.contains("\"frame\":441"));
        assert!(actual.contains("\"frame\":1738"));
    }

    #[test]
    fn serialize_header_bool() {
        assert_eq!(to_json(&HeaderProp::Bool(false)), "false");
        assert_eq!(to_json(&HeaderProp::Bool(true)), "true");
    }

    #[test]
    fn serialize_header_numbers() {
        assert_eq!(to_json(&HeaderProp::Byte), "0");
        assert_eq!(to_json(&HeaderProp::QWord(10)), "10");
        assert_eq!(to_json(&HeaderProp::Float(10.2)), "10.2");
        assert_eq!(to_json(&HeaderProp::Int(11)), "11");
    }

    #[test]
    fn serialize_header_str() {
        let val = "hello world";
        assert_eq!(
            to_json(&HeaderProp::Str(Cow::Borrowed(val))),
            "\"hello world\""
        );
        assert_eq!(
            to_json(&HeaderProp::Name(Cow::Borrowed(val))),
            "\"hello world\""
        );
    }
}
<commit_msg>Replace try! with question operator<commit_after>/// # Models
///
/// Here lies the data structures that a rocket league replay is decoded into. All of the models
/// are contained in this one file because of serde.
///
/// For serde, we only care about serialization, JSON serialization. Deserialization is not
/// implemented from our JSON output because it is lossy (JSON isn't the best with different
/// numeric/string types). Asking "why JSON" would be next logical step, and that's due to other
/// rocket league replay parsers (like Octane) using JSON; however, the output of this library is
/// not compatible with that of other rocket league replay parsers.

use serde::{Serialize, Serializer};
use serde::ser::{SerializeMap, SerializeSeq};
use std::collections::HashMap;
use std::borrow::Cow;
use network::Frame;

/// The structure that a rocket league replay is parsed into.
#[derive(Serialize, PartialEq, Debug, Clone)]
pub struct Replay<'a> {
    pub header_size: i32,
    pub header_crc: i32,
    pub major_version: i32,
    pub minor_version: i32,
    pub net_version: Option<i32>,
    pub game_type: Cow<'a, str>,

    /// Could use a map to represent properties but I don't want to assume that duplicate keys
    /// can't exist, so to be safe, use a traditional vector.
    #[serde(serialize_with = "pair_vec")]
    pub properties: Vec<(&'a str, HeaderProp<'a>)>,
    pub content_size: i32,
    pub content_crc: i32,
    pub network_frames: Option<NetworkFrames>,
    pub levels: Vec<Cow<'a, str>>,
    pub keyframes: Vec<KeyFrame>,
    pub debug_info: Vec<DebugInfo<'a>>,
    pub tick_marks: Vec<TickMark<'a>>,
    pub packages: Vec<Cow<'a, str>>,
    pub objects: Vec<Cow<'a, str>>,
    pub names: Vec<Cow<'a, str>>,
    pub class_indices: Vec<ClassIndex<'a>>,
    pub net_cache: Vec<ClassNetCache>,
}

/// The frames decoded from the network data
#[derive(Serialize, PartialEq, Debug, Clone)]
pub struct NetworkFrames {
    pub frames: Vec<Frame>,
}

/// In Rocket league replays, there are tickmarks that typically represent a significant event in
/// the game (eg. a goal). The tick mark is placed before the event happens so there is a ramp-up
/// time. For instance, a tickmark could be at frame 396 for a goal at frame 441. At 30 fps, this
/// would be 1.5 seconds of ramp up time.
#[derive(Serialize, PartialEq, Debug, Clone)]
pub struct TickMark<'a> {
    pub description: Cow<'a, str>,
    pub frame: i32,
}

/// Keyframes as defined by the video compression section in the [wikipedia][] article, are the
/// main frames that are derived from in the following frame data. The key frames decoded will
/// match up with the frames decoded from the network data.
///
/// [wikipedia]: https://en.wikipedia.org/wiki/Key_frame#Video_compression
#[derive(Serialize, PartialEq, Debug, Clone, Copy)]
pub struct KeyFrame {
    pub time: f32,
    pub frame: i32,
    pub position: i32,
}

/// All the interesting data are stored as properties in the header, properties such as:
///
/// - When and who scored a goal
/// - Player stats (goals, assists, score, etc).
/// - Date and level played on
///
/// A property can be a number, string, or a more complex object such as an array containing
/// additional properties.
#[derive(PartialEq, Debug, Clone)]
pub enum HeaderProp<'a> {
    Array(Vec<Vec<(&'a str, HeaderProp<'a>)>>),
    Bool(bool),
    Byte,
    Float(f32),
    Int(i32),
    Name(Cow<'a, str>),
    QWord(i64),
    Str(Cow<'a, str>),
}

/// Debugging info stored in the replay if debugging is enabled.
#[derive(Serialize, PartialEq, Debug, Clone)]
pub struct DebugInfo<'a> {
    pub frame: i32,
    pub user: Cow<'a, str>,
    pub text: Cow<'a, str>,
}

/// A mapping between an object's name and its index. Largely redundant
#[derive(Serialize, PartialEq, Debug, Clone)]
pub struct ClassIndex<'a> {
    /// Should be equivalent to `Replay::objects(self.index)`
    pub class: &'a str,

    /// The index that the object appears in the `Replay::objects`
    pub index: i32,
}

/// A mapping between an object (that's an attribute)'s index and what its id will be when encoded
/// in the network data
#[derive(Serialize, PartialEq, Debug, Clone, Copy)]
pub struct CacheProp {
    /// The index that the object appears in the `Replay::objects`
    pub object_ind: i32,

    /// An attribute / property id that appears in the network data. Stream ids are often re-used
    /// between multiple different properties
    pub stream_id: i32,
}

/// Contains useful information when decoding the network stream, which we aren't
#[derive(Serialize, PartialEq, Debug, Clone)]
pub struct ClassNetCache {
    /// The index that the object appears in the `Replay::objects`
    pub object_ind: i32,

    /// The cache id of the parent. The child class inherits all the parent's properties.
    pub parent_id: i32,

    /// The cache id of the object
    pub cache_id: i32,

    /// List of properties that is on the object.
    pub properties: Vec<CacheProp>,
}

/// Serialize a vector of key value tuples into a map. This is useful when the data we're ingesting
/// (rocket league replay data) doesn't have a defined spec, so it may be assuming too much to
/// store it into an associative array, so it's stored as a normal sequence. Here we serialize as a
/// map structure because most replay parser do this, so we should be compliant and the data format
/// doesn't dictate that the keys in a sequence of key value pairs must be distinct. It's true,
/// JSON doesn't need the keys to be unique: <http://stackoverflow.com/q/21832701/433785>
fn pair_vec<K, V, S>(inp: &[(K, V)], serializer: S) -> Result<S::Ok, S::Error>
where
    K: Serialize,
    V: Serialize,
    S: Serializer,
{
    let mut state = serializer.serialize_map(Some(inp.len()))?;
    for &(ref key, ref val) in inp.iter() {
        state.serialize_key(key)?;
        state.serialize_value(val)?;
    }
    state.end()
}

/// By default serde will generate a serialization method that writes out the enum as well as the
/// enum value. Since header values are self describing in JSON, we do not need to serialize the
/// enum type. This is slightly lossy as in the serialized format it will be ambiguous if a value
/// is a `Name` or `Str`, as well as `Byte`, `Float`, `Int`, or `QWord`.
impl<'a> Serialize for HeaderProp<'a> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        match *self {
            HeaderProp::Array(ref x) => {
                let mut state = serializer.serialize_seq(Some(x.len()))?;
                for inner in x {
                    // Look for a better way to do this instead of allocating the intermediate map
                    let mut els = HashMap::new();
                    for &(key, ref val) in inner.iter() {
                        els.insert(key, val);
                    }
                    state.serialize_element(&els)?;
                }
                state.end()
            }
            HeaderProp::Bool(ref x) => serializer.serialize_bool(*x),
            HeaderProp::Byte => serializer.serialize_u8(0),
            HeaderProp::Float(ref x) => serializer.serialize_f32(*x),
            HeaderProp::Int(ref x) => serializer.serialize_i32(*x),
            HeaderProp::QWord(ref x) => serializer.serialize_i64(*x),
            HeaderProp::Name(ref x) | HeaderProp::Str(ref x) => serializer.serialize_str(x),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde;
    use std;
    use serde_json;
    use std::borrow::Cow;

    fn to_json<T: serde::Serialize>(input: &T) -> std::string::String {
        serde_json::to_string(input).unwrap()
    }

    #[test]
    fn serialize_header_array() {
        let data = vec![
            vec![
                ("frame", HeaderProp::Int(441)),
                (
                    "PlayerName",
                    HeaderProp::Str(Cow::Borrowed("rust is awesome")),
                ),
            ],
            vec![
                ("frame", HeaderProp::Int(1738)),
                ("PlayerName", HeaderProp::Str(Cow::Borrowed("rusty"))),
            ],
        ];
        let actual = to_json(&HeaderProp::Array(data));
        assert!(actual.contains("\"PlayerName\":\"rust is awesome\""));
        assert!(actual.contains("\"PlayerName\":\"rusty\""));
        assert!(actual.contains("\"frame\":441"));
        assert!(actual.contains("\"frame\":1738"));
    }

    #[test]
    fn serialize_header_bool() {
        assert_eq!(to_json(&HeaderProp::Bool(false)), "false");
        assert_eq!(to_json(&HeaderProp::Bool(true)), "true");
    }

    #[test]
    fn serialize_header_numbers() {
        assert_eq!(to_json(&HeaderProp::Byte), "0");
        assert_eq!(to_json(&HeaderProp::QWord(10)), "10");
        assert_eq!(to_json(&HeaderProp::Float(10.2)), "10.2");
        assert_eq!(to_json(&HeaderProp::Int(11)), "11");
    }

    #[test]
    fn serialize_header_str() {
        let val = "hello world";
        assert_eq!(
            to_json(&HeaderProp::Str(Cow::Borrowed(val))),
            "\"hello world\""
        );
        assert_eq!(
            to_json(&HeaderProp::Name(Cow::Borrowed(val))),
            "\"hello world\""
        );
    }
}
<|endoftext|>


<commit_before>//! `cargo add`
#![warn(
    missing_docs,
    missing_debug_implementations,
    missing_copy_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unsafe_code,
    unstable_features,
    unused_import_braces,
    unused_qualifications
)]

#[macro_use]
extern crate error_chain;

use crate::args::{Args, Command, UnstableOptions};
use cargo_edit::{
    colorize_stderr, find, manifest_from_pkgid, registry_url, update_registry_index, Dependency,
    LocalManifest,
};
use clap::Parser;
use std::collections::BTreeSet;
use std::io::Write;
use std::path::Path;
use std::process;
use termcolor::{Color, ColorSpec, StandardStream, WriteColor};
use toml_edit::Item as TomlItem;

mod args;

mod errors {
    error_chain! {
        errors {
            /// Specified a dependency with both a git URL and a version.
            GitUrlWithVersion(git: String, version: String) {
                description("Specified git URL with version")
                display("Cannot specify a git URL (`{}`) with a version (`{}`).", git, version)
            }
            /// Specified multiple crates with path or git or vers
            MultipleCratesWithGitOrPathOrVers {
                description("Specified multiple crates with path or git or vers")
                display("Cannot specify multiple crates with path or git or vers")
            }
            /// Specified multiple crates with renaming.
            MultipleCratesWithRename {
                description("Specified multiple crates with rename")
                display("Cannot specify multiple crates with rename")
            }
            /// Specified multiple crates with features.
            MultipleCratesWithFeatures {
                description("Specified multiple crates with features")
                display("Cannot specify multiple crates with features")
            }
            AddingSelf(crate_: String) {
                description("Adding crate to itself")
                display("Cannot add `{}` as a dependency to itself", crate_)
            }
        }
        links {
            CargoEditLib(::cargo_edit::Error, ::cargo_edit::ErrorKind);
        }
        foreign_links {
            CargoMetadata(::cargo_metadata::Error)#[doc = "An error from the cargo_metadata crate"];
            Io(::std::io::Error);
        }
    }
}

use crate::errors::*;

fn print_msg(dep: &Dependency, section: &[String], optional: bool) -> Result<()> {
    let colorchoice = colorize_stderr();
    let mut output = StandardStream::stderr(colorchoice);
    output.set_color(ColorSpec::new().set_fg(Some(Color::Green)).set_bold(true))?;
    write!(output, "{:>12}", "Adding")?;
    output.reset()?;
    write!(output, " {}", dep.name)?;
    if dep.path().is_some() {
        write!(output, " (local)")?;
    } else if let Some(version) = dep.version() {
        if version.chars().next().unwrap_or('0').is_ascii_digit() {
            write!(output, " v{}", version)?;
        } else {
            write!(output, " {}", version)?;
        }
    }
    write!(output, " to")?;
    if optional {
        write!(output, " optional")?;
    }
    let section = if section.len() == 1 {
        section[0].clone()
    } else {
        format!("{} for target `{}`", &section[2], &section[1])
    };
    write!(output, " {}", section)?;
    if let Some(f) = &dep.features {
        if !f.is_empty() {
            write!(output, " with features: {}", f.join(", "))?;
        }
    }
    writeln!(output, ".")?;

    if !&dep.available_features.is_empty() {
        writeln!(output, "{:>13}Available features:", " ")?;
        for feat in dep.available_features.iter() {
            writeln!(output, "{:>13}- {}", " ", feat)?;
        }
    }
    Ok(())
}

// Based on Iterator::is_sorted from nightly std; remove in favor of that when stabilized.
fn is_sorted(mut it: impl Iterator<Item = impl PartialOrd>) -> bool {
    let mut last = match it.next() {
        Some(e) => e,
        None => return true,
    };

    for curr in it {
        if curr < last {
            return false;
        }
        last = curr;
    }

    true
}

fn unrecognized_features_message(message: &str) -> Result<()> {
    let colorchoice = colorize_stderr();
    let mut output = StandardStream::stderr(colorchoice);
    output.set_color(ColorSpec::new().set_fg(Some(Color::Yellow)).set_bold(true))?;
    write!(output, "{:>12}", "Warning:")?;
    output.reset()?;
    writeln!(output, " {}", message)
        .chain_err(|| "Failed to write unrecognized features message")?;
    Ok(())
}

fn handle_add(mut args: Args) -> Result<()> {
    if args.git.is_some() && !args.unstable_features.contains(&UnstableOptions::Git) {
        return Err("`--git` is unstable and requires `-Z git`".into());
    }

    if let Some(ref pkgid) = args.pkgid {
        let pkg = manifest_from_pkgid(args.manifest_path.as_deref(), pkgid)?;
        args.manifest_path = Some(pkg.manifest_path.into_std_path_buf());
    }
    let mut manifest = LocalManifest::find(&args.manifest_path)?;

    if !args.offline && std::env::var("CARGO_IS_TEST").is_err() {
        let url = registry_url(
            &find(&args.manifest_path)?,
            args.registry.as_ref().map(String::as_ref),
        )?;
        update_registry_index(&url, args.quiet)?;
    }
    let requested_features: Option<BTreeSet<&str>> = args.features.as_ref().map(|v| {
        v.iter()
            .map(|s| s.split(' '))
            .flatten()
            .filter(|s| !s.is_empty())
            .collect()
    });

    let deps = &args.parse_dependencies(
        requested_features
            .as_ref()
            .map(|s| s.iter().map(|s| s.to_string()).collect()),
    )?;

    if let Some(req_feats) = requested_features {
        assert!(deps.len() == 1);
        let available_features = deps[0]
            .available_features
            .iter()
            .map(|s| s.as_ref())
            .collect::<BTreeSet<&str>>();

        let mut unknown_features: Vec<&&str> = req_feats.difference(&available_features).collect();
        unknown_features.sort();

        if !unknown_features.is_empty() {
            unrecognized_features_message(&format!(
                "Unrecognized features: {:?}",
                unknown_features
            ))?;
        };
    };

    let was_sorted = manifest
        .get_table(&args.get_section())
        .map(TomlItem::as_table_mut)
        .map_or(true, |table_option| {
            table_option.map_or(true, |table| is_sorted(table.iter().map(|(name, _)| name)))
        });
    deps.iter()
        .map(|dep| {
            if !args.quiet {
                print_msg(dep, &args.get_section(), args.optional)?;
            }
            if let Some(path) = dep.path() {
                if path == manifest.path.parent().unwrap_or_else(|| Path::new("")) {
                    return Err(ErrorKind::AddingSelf(manifest.package_name()?.to_owned()).into());
                }
            }
            manifest.insert_into_table(&args.get_section(), dep)?;
            manifest.gc_dep(dep.toml_key());
            Ok(())
        })
        .collect::<Result<Vec<_>>>()
        .map_err(|err| {
            eprintln!("Could not edit `Cargo.toml`.\n\nERROR: {}", err);
            err
        })?;

    if was_sorted {
        if let Some(table) = manifest
            .get_table(&args.get_section())
            .ok()
            .and_then(TomlItem::as_table_like_mut)
        {
            table.sort_values();
        }
    }

    manifest.write()?;

    Ok(())
}

fn main() {
    let args: Command = Command::parse();
    let Command::Add(args) = args;

    if let Err(err) = handle_add(args) {
        eprintln!("Command failed due to unhandled error: {}", err);

        let mut gap = false;
        for e in err.iter().skip(1) {
            if !gap {
                eprintln!();
                gap = true;
            }
            eprintln!("Caused by: {}", e);
        }

        if let Some(backtrace) = err.backtrace() {
            eprintln!();
            eprintln!("Backtrace: {:?}", backtrace);
        }

        process::exit(1);
    }
}
<commit_msg>fix(add): Allow ',' to separate features<commit_after>//! `cargo add`
#![warn(
    missing_docs,
    missing_debug_implementations,
    missing_copy_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unsafe_code,
    unstable_features,
    unused_import_braces,
    unused_qualifications
)]

#[macro_use]
extern crate error_chain;

use crate::args::{Args, Command, UnstableOptions};
use cargo_edit::{
    colorize_stderr, find, manifest_from_pkgid, registry_url, update_registry_index, Dependency,
    LocalManifest,
};
use clap::Parser;
use std::collections::BTreeSet;
use std::io::Write;
use std::path::Path;
use std::process;
use termcolor::{Color, ColorSpec, StandardStream, WriteColor};
use toml_edit::Item as TomlItem;

mod args;

mod errors {
    error_chain! {
        errors {
            /// Specified a dependency with both a git URL and a version.
            GitUrlWithVersion(git: String, version: String) {
                description("Specified git URL with version")
                display("Cannot specify a git URL (`{}`) with a version (`{}`).", git, version)
            }
            /// Specified multiple crates with path or git or vers
            MultipleCratesWithGitOrPathOrVers {
                description("Specified multiple crates with path or git or vers")
                display("Cannot specify multiple crates with path or git or vers")
            }
            /// Specified multiple crates with renaming.
            MultipleCratesWithRename {
                description("Specified multiple crates with rename")
                display("Cannot specify multiple crates with rename")
            }
            /// Specified multiple crates with features.
            MultipleCratesWithFeatures {
                description("Specified multiple crates with features")
                display("Cannot specify multiple crates with features")
            }
            AddingSelf(crate_: String) {
                description("Adding crate to itself")
                display("Cannot add `{}` as a dependency to itself", crate_)
            }
        }
        links {
            CargoEditLib(::cargo_edit::Error, ::cargo_edit::ErrorKind);
        }
        foreign_links {
            CargoMetadata(::cargo_metadata::Error)#[doc = "An error from the cargo_metadata crate"];
            Io(::std::io::Error);
        }
    }
}

use crate::errors::*;

fn print_msg(dep: &Dependency, section: &[String], optional: bool) -> Result<()> {
    let colorchoice = colorize_stderr();
    let mut output = StandardStream::stderr(colorchoice);
    output.set_color(ColorSpec::new().set_fg(Some(Color::Green)).set_bold(true))?;
    write!(output, "{:>12}", "Adding")?;
    output.reset()?;
    write!(output, " {}", dep.name)?;
    if dep.path().is_some() {
        write!(output, " (local)")?;
    } else if let Some(version) = dep.version() {
        if version.chars().next().unwrap_or('0').is_ascii_digit() {
            write!(output, " v{}", version)?;
        } else {
            write!(output, " {}", version)?;
        }
    }
    write!(output, " to")?;
    if optional {
        write!(output, " optional")?;
    }
    let section = if section.len() == 1 {
        section[0].clone()
    } else {
        format!("{} for target `{}`", &section[2], &section[1])
    };
    write!(output, " {}", section)?;
    if let Some(f) = &dep.features {
        if !f.is_empty() {
            write!(output, " with features: {}", f.join(", "))?;
        }
    }
    writeln!(output, ".")?;

    if !&dep.available_features.is_empty() {
        writeln!(output, "{:>13}Available features:", " ")?;
        for feat in dep.available_features.iter() {
            writeln!(output, "{:>13}- {}", " ", feat)?;
        }
    }
    Ok(())
}

// Based on Iterator::is_sorted from nightly std; remove in favor of that when stabilized.
fn is_sorted(mut it: impl Iterator<Item = impl PartialOrd>) -> bool {
    let mut last = match it.next() {
        Some(e) => e,
        None => return true,
    };

    for curr in it {
        if curr < last {
            return false;
        }
        last = curr;
    }

    true
}

fn unrecognized_features_message(message: &str) -> Result<()> {
    let colorchoice = colorize_stderr();
    let mut output = StandardStream::stderr(colorchoice);
    output.set_color(ColorSpec::new().set_fg(Some(Color::Yellow)).set_bold(true))?;
    write!(output, "{:>12}", "Warning:")?;
    output.reset()?;
    writeln!(output, " {}", message)
        .chain_err(|| "Failed to write unrecognized features message")?;
    Ok(())
}

fn handle_add(mut args: Args) -> Result<()> {
    if args.git.is_some() && !args.unstable_features.contains(&UnstableOptions::Git) {
        return Err("`--git` is unstable and requires `-Z git`".into());
    }

    if let Some(ref pkgid) = args.pkgid {
        let pkg = manifest_from_pkgid(args.manifest_path.as_deref(), pkgid)?;
        args.manifest_path = Some(pkg.manifest_path.into_std_path_buf());
    }
    let mut manifest = LocalManifest::find(&args.manifest_path)?;

    if !args.offline && std::env::var("CARGO_IS_TEST").is_err() {
        let url = registry_url(
            &find(&args.manifest_path)?,
            args.registry.as_ref().map(String::as_ref),
        )?;
        update_registry_index(&url, args.quiet)?;
    }
    let requested_features: Option<BTreeSet<&str>> = args.features.as_ref().map(|v| {
        v.iter()
            .flat_map(|s| s.split(' '))
            .flat_map(|s| s.split(','))
            .filter(|s| !s.is_empty())
            .collect()
    });

    let deps = &args.parse_dependencies(
        requested_features
            .as_ref()
            .map(|s| s.iter().map(|s| s.to_string()).collect()),
    )?;

    if let Some(req_feats) = requested_features {
        assert!(deps.len() == 1);
        let available_features = deps[0]
            .available_features
            .iter()
            .map(|s| s.as_ref())
            .collect::<BTreeSet<&str>>();

        let mut unknown_features: Vec<&&str> = req_feats.difference(&available_features).collect();
        unknown_features.sort();

        if !unknown_features.is_empty() {
            unrecognized_features_message(&format!(
                "Unrecognized features: {:?}",
                unknown_features
            ))?;
        };
    };

    let was_sorted = manifest
        .get_table(&args.get_section())
        .map(TomlItem::as_table_mut)
        .map_or(true, |table_option| {
            table_option.map_or(true, |table| is_sorted(table.iter().map(|(name, _)| name)))
        });
    deps.iter()
        .map(|dep| {
            if !args.quiet {
                print_msg(dep, &args.get_section(), args.optional)?;
            }
            if let Some(path) = dep.path() {
                if path == manifest.path.parent().unwrap_or_else(|| Path::new("")) {
                    return Err(ErrorKind::AddingSelf(manifest.package_name()?.to_owned()).into());
                }
            }
            manifest.insert_into_table(&args.get_section(), dep)?;
            manifest.gc_dep(dep.toml_key());
            Ok(())
        })
        .collect::<Result<Vec<_>>>()
        .map_err(|err| {
            eprintln!("Could not edit `Cargo.toml`.\n\nERROR: {}", err);
            err
        })?;

    if was_sorted {
        if let Some(table) = manifest
            .get_table(&args.get_section())
            .ok()
            .and_then(TomlItem::as_table_like_mut)
        {
            table.sort_values();
        }
    }

    manifest.write()?;

    Ok(())
}

fn main() {
    let args: Command = Command::parse();
    let Command::Add(args) = args;

    if let Err(err) = handle_add(args) {
        eprintln!("Command failed due to unhandled error: {}", err);

        let mut gap = false;
        for e in err.iter().skip(1) {
            if !gap {
                eprintln!();
                gap = true;
            }
            eprintln!("Caused by: {}", e);
        }

        if let Some(backtrace) = err.backtrace() {
            eprintln!();
            eprintln!("Backtrace: {:?}", backtrace);
        }

        process::exit(1);
    }
}
<|endoftext|>


<commit_before>//! A parser for lambda expressions

use 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();

    while let Some((i, c)) = chars.next() {
        match c {
            '\\' | 'λ' => {
                let mut name = String::new();
                while let Some((i, c)) = chars.next() {
                    if c == '.' {
                        break
                    } else if "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".contains(c) {
                        name.push(c)
                    } else {
                        return Err(InvalidCharacter((i + 1, c)))
                    }
                }
                tokens.push(CLambda(name))
            },
            '(' => { tokens.push(CLparen) },
            ')' => { tokens.push(CRparen) },
             _  => {
                if c.is_whitespace() {
                    ()
                } else if "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".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::new();
    let mut inner_stack_count = 0;

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

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

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

    Ok(Sequence(expr))
}

/// 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::arithmetic::{succ, pred};
///
/// assert_eq!(parse(&"λn. λf. λx. n (λg. λh. h (g f)) (λu. x) (λu. u)", Classic), Ok(pred()));
/// assert_eq!(parse(&"λn.λf.λx.n(λg.λh.h(g f))(λu.x)(λu.u)", Classic), Ok(pred()));
///
/// assert_eq!(parse(  &"λλλ2(321)",  DeBruijn), Ok(succ()));
/// assert_eq!(parse(&r#"\\\2(321)"#, DeBruijn), Ok(succ()));
/// ```
pub fn parse(input: &str, notation: Notation) -> Result<Term, Error> {
    let tokens = if notation == DeBruijn {
        try!(tokenize_dbr(input))
    } else {
        convert_classic_tokens(&try!(tokenize_cla(input)))
    };
    let ast = try!(get_ast(&tokens));

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

    fold_exprs(&exprs, &mut Vec::new(), &mut Vec::new())
}

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

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

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

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

    Ok(ret)
}

fn fold_terms(mut terms: Vec<Term>) -> Result<Term, Error> {
    if terms.len() > 1 {
        let fst = terms.remove(0);
        Ok( terms.into_iter().fold(fst, 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).expect("parsing Y failed!"),
            abs(
                app(
                    abs(app(Var(2), app(Var(1), Var(1)))),
                    abs(app(Var(2), app(Var(1), Var(1))))
                )
            )
        );
    }

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

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

use 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();

    while let Some((i, c)) = chars.next() {
        match c {
            '\\' | 'λ' => {
                let mut name = String::new();
                while let Some((i, c)) = chars.next() {
                    if c == '.' {
                        break
                    } else if "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".contains(c) {
                        name.push(c)
                    } else {
                        return Err(InvalidCharacter((i + 1, c)))
                    }
                }
                tokens.push(CLambda(name))
            },
            '(' => { tokens.push(CLparen) },
            ')' => { tokens.push(CRparen) },
             _  => {
                if c.is_whitespace() {
                    ()
                } else if "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".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::new();
    let mut inner_stack_count = 0;

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

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

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

    Ok(Sequence(expr))
}

/// 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::arithmetic::{succ, pred};
///
/// assert_eq!(parse(&"λn. λf. λx. n (λg. λh. h (g f)) (λu. x) (λu. u)", Classic), Ok(pred()));
/// assert_eq!(parse(&"λn.λf.λx.n(λg.λh.h(g f))(λu.x)(λu.u)", Classic), Ok(pred()));
///
/// assert_eq!(parse(  &"λλλ2(321)",  DeBruijn), Ok(succ()));
/// assert_eq!(parse(&r#"\\\2(321)"#, DeBruijn), Ok(succ()));
/// ```
pub fn parse(input: &str, notation: Notation) -> Result<Term, Error> {
    let tokens = if notation == DeBruijn {
        try!(tokenize_dbr(input))
    } else {
        convert_classic_tokens(&try!(tokenize_cla(input)))
    };
    let ast = try!(get_ast(&tokens));

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

    fold_exprs(&exprs, &mut Vec::new(), &mut Vec::new())
}

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

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

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

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

    Ok(ret)
}

fn fold_terms(mut terms: Vec<Term>) -> Result<Term, Error> {
    if terms.len() > 1 {
        let fst = terms.remove(0);
        Ok( terms.into_iter().fold(fst, 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)))))))
        );
    }
}
<|endoftext|>


<commit_before>use std::mem;

use num::bigint::{self, ToBigInt};
use num::traits::{Zero, One};

use encoding::{Encoding, DecoderTrap};
use encoding::all::ISO_8859_1;

use bertterm::BertTerm;
use error::{Result, BertError};

const BERT_MAGIC_NUMBER: u8 = 131;
const SMALL_INTEGER_EXT: u8 = 97;
const INTEGER_EXT: u8 = 98;
const FLOAT_EXT: u8 = 99;
const ATOM_EXT: u8 = 100;
const SMALL_ATOM_EXT: u8 = 115;
const SMALL_TUPLE_EXT: u8 = 104;
const LARGE_TUPLE_EXT: u8 = 105;
const NIL_EXT: u8 = 106;
const STRING_EXT: u8 = 107;
const LIST_EXT: u8 = 108;
const BINARY_EXT: u8 = 109;
const SMALL_BIG_EXT: u8 = 110;
const LARGE_BIG_EXT: u8 = 111;
const ATOM_UTF8_EXT: u8 = 118;
const SMALL_ATOM_UTF8_EXT: u8 = 119;
const NEW_FLOAT_EXT: u8 = 70;

#[derive(Debug)]
pub struct Parser {
    contents: Vec<u8>,
    pos: usize,
}

impl Parser {
    pub fn new(contents: Vec<u8>) -> Parser {
        Parser { contents: contents, pos: 0 }
    }

    pub fn parse(&mut self) -> Result<BertTerm> {
        let () = self.magic_number()?;
        let term = self.bert_term()?;
        if self.eof() {
            return Ok(term);
        } else {
            return Err(BertError::ExtraData(self.pos));
        }
    }

    // Parsers
    fn magic_number(&mut self) -> Result<()> {
        let offset = self.pos;
        let magic = self.eat_u8()?;
        if magic != BERT_MAGIC_NUMBER {
            return Err(BertError::InvalidMagicNumber(offset));
        } else {
            return Ok(());
        }
    }

    fn bert_term(&mut self) -> Result<BertTerm> {
        let offset = self.pos;
        match self.eat_u8()? {
            SMALL_INTEGER_EXT => { self.small_integer() }
            INTEGER_EXT => { self.integer() }
            FLOAT_EXT => { self.old_float() }
            NEW_FLOAT_EXT => { self.new_float() }
            ATOM_EXT => {
                let len = self.eat_u16_be()? as usize;
                self.atom(len)
            }
            SMALL_ATOM_EXT => {
                let len = self.eat_u8()? as usize;
                self.atom(len)
            }
            ATOM_UTF8_EXT => {
                let len = self.eat_u16_be()? as usize;
                self.atom_utf8(len)
            }
            SMALL_ATOM_UTF8_EXT => {
                let len = self.eat_u8()? as usize;
                self.atom_utf8(len)
            }
            SMALL_TUPLE_EXT => {
                let len = self.eat_u8()? as usize;
                self.tuple(len)
            }
            LARGE_TUPLE_EXT => {
                let len = self.eat_u32_be()? as usize;
                self.tuple(len)
            }
            NIL_EXT => { Ok(BertTerm::List(vec![])) }
            LIST_EXT => { self.list() }
            STRING_EXT => { self.string() }
            BINARY_EXT => { self.binary() }
            SMALL_BIG_EXT => {
                let len = self.eat_u8()?;
                self.bigint(len as usize)
            }
            LARGE_BIG_EXT => {
                let len = self.eat_u32_be()?;
                self.bigint(len as usize)
            }
            tag => { Err(BertError::InvalidTag(offset, tag)) }
        }
    }

    fn small_integer(&mut self) -> Result<BertTerm> {
        let b = self.eat_u8()?;
        Ok(BertTerm::Int(b as i32))
    }

    fn integer(&mut self) -> Result<BertTerm> {
        let n = self.eat_i32_be()?;
        Ok(BertTerm::Int(n))
    }

    fn old_float(&mut self) -> Result<BertTerm> {
        let offset = self.pos;
        let mut s = String::new();
        while !self.eof() && self.peek()? != 0 {
            s.push(self.eat_char()?);
        }

        while !self.eof() && self.peek()? == 0 {
            let _ = self.eat_u8()?;
        }

        s.parse::<f64>()
            .map_err(|_| BertError::InvalidFloat(offset))
            .map(|f| BertTerm::Float(f))
    }

    fn new_float(&mut self) -> Result<BertTerm> {
        let raw_bytes = self.eat_u64_be()?;
        let f: f64 = unsafe { mem::transmute(raw_bytes) };
        Ok(BertTerm::Float(f))
    }

    fn atom(&mut self, len: usize) -> Result<BertTerm> {
        let offset = self.pos;
        let mut bytes: Vec<u8> = Vec::with_capacity(len);
        for _ in 0 .. len {
            bytes.push(self.eat_u8()?);
        }
        ISO_8859_1.decode(&bytes, DecoderTrap::Strict)
            .map(|s| BertTerm::Atom(s))
            .map_err(|_| BertError::InvalidLatin1Atom(offset))
    }

    fn atom_utf8(&mut self, len: usize) -> Result<BertTerm> {
        let offset = self.pos;
        let mut buf = Vec::with_capacity(len);
        for _ in 0 .. len {
            buf.push(self.eat_u8()?);
        }
        String::from_utf8(buf)
            .map(|s| BertTerm::Atom(s))
            .map_err(|_| BertError::InvalidUTF8Atom(offset))
    }

    fn tuple(&mut self, len: usize) -> Result<BertTerm> {
        let mut terms = Vec::with_capacity(len);
        for _ in 0 .. len {
            terms.push(self.bert_term()?);
        }
        Ok(BertTerm::Tuple(terms))
    }

    fn string(&mut self) -> Result<BertTerm> {
        let len = self.eat_u16_be()?;
        let mut bytes = Vec::with_capacity(len as usize);
        for _ in 0 .. len {
            bytes.push(self.eat_u8()?);
        }
        Ok(BertTerm::String(bytes))
    }

    fn binary(&mut self) -> Result<BertTerm> {
        let len = self.eat_u32_be()?;
        let mut bytes = Vec::with_capacity(len as usize);
        for _ in 0 .. len {
            bytes.push(self.eat_u8()?);
        }
        Ok(BertTerm::Binary(bytes))
    }

    fn list(&mut self) -> Result<BertTerm> {
        let len = self.eat_u32_be()?;
        let mut terms = Vec::with_capacity(len as usize + 1);
        for _ in 0 .. len {
            terms.push(self.bert_term()?);
        }
        let tail = self.bert_term()?;
        match tail {
            BertTerm::List(_) => (),
            last_term => { terms.push(last_term); }
        };
        Ok(BertTerm::List(terms))
    }

    fn bigint(&mut self, len: usize) -> Result<BertTerm> {
        let sign = self.eat_u8()?;
        let mut sum: bigint::BigInt = Zero::zero();
        let mut pos: bigint::BigInt = One::one();
        for _ in 0 .. len {
            let d = self.eat_u8()?;
            let t = &pos * &(d.to_bigint().unwrap());
            sum = sum + &t;
            pos = pos * (256).to_bigint().unwrap();
        }
        if sign == 1 {
            sum = -sum;
        }
        Ok(BertTerm::BigInt(sum))
    }

    // Low-level parsing methods
    fn eof(&self) -> bool {
        self.pos >= self.contents.len()
    }

    fn peek(&self) -> Result<u8> {
        self.peek_at(self.pos)
    }

    fn peek_at(&self, offset: usize) -> Result<u8> {
        if self.eof() {
            return Err(BertError::EOF(offset));
        } else {
            return Ok(self.contents[offset]);
        }
    }

    fn eat_u8(&mut self) -> Result<u8> {
        let b = self.peek()?;
        self.pos += 1;
        return Ok(b);
    }

    fn eat_char(&mut self) -> Result<char> {
        let b = self.eat_u8()?;
        return Ok(b as char);
    }

    fn eat_u16_be(&mut self) -> Result<u16> {
        let b0 = self.eat_u8()? as u16;
        let b1 = self.eat_u8()? as u16;
        return Ok((b0 << 8) + b1)
    }

    fn eat_i32_be(&mut self) -> Result<i32> {
        let b0 = self.eat_u8()? as i32;
        let b1 = self.eat_u8()? as i32;
        let b2 = self.eat_u8()? as i32;
        let b3 = self.eat_u8()? as i32;
        return Ok((b0 << 24) + (b1 << 16) + (b2 << 8) + b3)
    }

    fn eat_u32_be(&mut self) -> Result<u32> {
        let b0 = self.eat_u8()? as u32;
        let b1 = self.eat_u8()? as u32;
        let b2 = self.eat_u8()? as u32;
        let b3 = self.eat_u8()? as u32;
        return Ok((b0 << 24) + (b1 << 16) + (b2 << 8) + b3)
    }

    fn eat_u64_be(&mut self) -> Result<u64> {
        let mut n: u64 = 0;
        n += (self.eat_u8()? as u64) << 56;
        n += (self.eat_u8()? as u64) << 48;
        n += (self.eat_u8()? as u64) << 40;
        n += (self.eat_u8()? as u64) << 32;
        n += (self.eat_u8()? as u64) << 24;
        n += (self.eat_u8()? as u64) << 16;
        n += (self.eat_u8()? as u64) << 8;
        n += self.eat_u8()? as u64;
        return Ok(n);
    }
}
<commit_msg>Remove unnecessary peek_at()<commit_after>use std::mem;

use num::bigint::{self, ToBigInt};
use num::traits::{Zero, One};

use encoding::{Encoding, DecoderTrap};
use encoding::all::ISO_8859_1;

use bertterm::BertTerm;
use error::{Result, BertError};

const BERT_MAGIC_NUMBER: u8 = 131;
const SMALL_INTEGER_EXT: u8 = 97;
const INTEGER_EXT: u8 = 98;
const FLOAT_EXT: u8 = 99;
const ATOM_EXT: u8 = 100;
const SMALL_ATOM_EXT: u8 = 115;
const SMALL_TUPLE_EXT: u8 = 104;
const LARGE_TUPLE_EXT: u8 = 105;
const NIL_EXT: u8 = 106;
const STRING_EXT: u8 = 107;
const LIST_EXT: u8 = 108;
const BINARY_EXT: u8 = 109;
const SMALL_BIG_EXT: u8 = 110;
const LARGE_BIG_EXT: u8 = 111;
const ATOM_UTF8_EXT: u8 = 118;
const SMALL_ATOM_UTF8_EXT: u8 = 119;
const NEW_FLOAT_EXT: u8 = 70;

#[derive(Debug)]
pub struct Parser {
    contents: Vec<u8>,
    pos: usize,
}

impl Parser {
    pub fn new(contents: Vec<u8>) -> Parser {
        Parser { contents: contents, pos: 0 }
    }

    pub fn parse(&mut self) -> Result<BertTerm> {
        let () = self.magic_number()?;
        let term = self.bert_term()?;
        if self.eof() {
            return Ok(term);
        } else {
            return Err(BertError::ExtraData(self.pos));
        }
    }

    // Parsers
    fn magic_number(&mut self) -> Result<()> {
        let offset = self.pos;
        let magic = self.eat_u8()?;
        if magic != BERT_MAGIC_NUMBER {
            return Err(BertError::InvalidMagicNumber(offset));
        } else {
            return Ok(());
        }
    }

    fn bert_term(&mut self) -> Result<BertTerm> {
        let offset = self.pos;
        match self.eat_u8()? {
            SMALL_INTEGER_EXT => { self.small_integer() }
            INTEGER_EXT => { self.integer() }
            FLOAT_EXT => { self.old_float() }
            NEW_FLOAT_EXT => { self.new_float() }
            ATOM_EXT => {
                let len = self.eat_u16_be()? as usize;
                self.atom(len)
            }
            SMALL_ATOM_EXT => {
                let len = self.eat_u8()? as usize;
                self.atom(len)
            }
            ATOM_UTF8_EXT => {
                let len = self.eat_u16_be()? as usize;
                self.atom_utf8(len)
            }
            SMALL_ATOM_UTF8_EXT => {
                let len = self.eat_u8()? as usize;
                self.atom_utf8(len)
            }
            SMALL_TUPLE_EXT => {
                let len = self.eat_u8()? as usize;
                self.tuple(len)
            }
            LARGE_TUPLE_EXT => {
                let len = self.eat_u32_be()? as usize;
                self.tuple(len)
            }
            NIL_EXT => { Ok(BertTerm::List(vec![])) }
            LIST_EXT => { self.list() }
            STRING_EXT => { self.string() }
            BINARY_EXT => { self.binary() }
            SMALL_BIG_EXT => {
                let len = self.eat_u8()?;
                self.bigint(len as usize)
            }
            LARGE_BIG_EXT => {
                let len = self.eat_u32_be()?;
                self.bigint(len as usize)
            }
            tag => { Err(BertError::InvalidTag(offset, tag)) }
        }
    }

    fn small_integer(&mut self) -> Result<BertTerm> {
        let b = self.eat_u8()?;
        Ok(BertTerm::Int(b as i32))
    }

    fn integer(&mut self) -> Result<BertTerm> {
        let n = self.eat_i32_be()?;
        Ok(BertTerm::Int(n))
    }

    fn old_float(&mut self) -> Result<BertTerm> {
        let offset = self.pos;
        let mut s = String::new();
        while !self.eof() && self.peek()? != 0 {
            s.push(self.eat_char()?);
        }

        while !self.eof() && self.peek()? == 0 {
            let _ = self.eat_u8()?;
        }

        s.parse::<f64>()
            .map_err(|_| BertError::InvalidFloat(offset))
            .map(|f| BertTerm::Float(f))
    }

    fn new_float(&mut self) -> Result<BertTerm> {
        let raw_bytes = self.eat_u64_be()?;
        let f: f64 = unsafe { mem::transmute(raw_bytes) };
        Ok(BertTerm::Float(f))
    }

    fn atom(&mut self, len: usize) -> Result<BertTerm> {
        let offset = self.pos;
        let mut bytes: Vec<u8> = Vec::with_capacity(len);
        for _ in 0 .. len {
            bytes.push(self.eat_u8()?);
        }
        ISO_8859_1.decode(&bytes, DecoderTrap::Strict)
            .map(|s| BertTerm::Atom(s))
            .map_err(|_| BertError::InvalidLatin1Atom(offset))
    }

    fn atom_utf8(&mut self, len: usize) -> Result<BertTerm> {
        let offset = self.pos;
        let mut buf = Vec::with_capacity(len);
        for _ in 0 .. len {
            buf.push(self.eat_u8()?);
        }
        String::from_utf8(buf)
            .map(|s| BertTerm::Atom(s))
            .map_err(|_| BertError::InvalidUTF8Atom(offset))
    }

    fn tuple(&mut self, len: usize) -> Result<BertTerm> {
        let mut terms = Vec::with_capacity(len);
        for _ in 0 .. len {
            terms.push(self.bert_term()?);
        }
        Ok(BertTerm::Tuple(terms))
    }

    fn string(&mut self) -> Result<BertTerm> {
        let len = self.eat_u16_be()?;
        let mut bytes = Vec::with_capacity(len as usize);
        for _ in 0 .. len {
            bytes.push(self.eat_u8()?);
        }
        Ok(BertTerm::String(bytes))
    }

    fn binary(&mut self) -> Result<BertTerm> {
        let len = self.eat_u32_be()?;
        let mut bytes = Vec::with_capacity(len as usize);
        for _ in 0 .. len {
            bytes.push(self.eat_u8()?);
        }
        Ok(BertTerm::Binary(bytes))
    }

    fn list(&mut self) -> Result<BertTerm> {
        let len = self.eat_u32_be()?;
        let mut terms = Vec::with_capacity(len as usize + 1);
        for _ in 0 .. len {
            terms.push(self.bert_term()?);
        }
        let tail = self.bert_term()?;
        match tail {
            BertTerm::List(_) => (),
            last_term => { terms.push(last_term); }
        };
        Ok(BertTerm::List(terms))
    }

    fn bigint(&mut self, len: usize) -> Result<BertTerm> {
        let sign = self.eat_u8()?;
        let mut sum: bigint::BigInt = Zero::zero();
        let mut pos: bigint::BigInt = One::one();
        for _ in 0 .. len {
            let d = self.eat_u8()?;
            let t = &pos * &(d.to_bigint().unwrap());
            sum = sum + &t;
            pos = pos * (256).to_bigint().unwrap();
        }
        if sign == 1 {
            sum = -sum;
        }
        Ok(BertTerm::BigInt(sum))
    }

    // Low-level parsing methods
    fn eof(&self) -> bool {
        self.pos >= self.contents.len()
    }

    fn peek(&self) -> Result<u8> {
        if self.eof() {
            return Err(BertError::EOF(self.pos));
        } else {
            return Ok(self.contents[self.pos]);
        }
    }

    fn eat_u8(&mut self) -> Result<u8> {
        let b = self.peek()?;
        self.pos += 1;
        return Ok(b);
    }

    fn eat_char(&mut self) -> Result<char> {
        let b = self.eat_u8()?;
        return Ok(b as char);
    }

    fn eat_u16_be(&mut self) -> Result<u16> {
        let b0 = self.eat_u8()? as u16;
        let b1 = self.eat_u8()? as u16;
        return Ok((b0 << 8) + b1)
    }

    fn eat_i32_be(&mut self) -> Result<i32> {
        let b0 = self.eat_u8()? as i32;
        let b1 = self.eat_u8()? as i32;
        let b2 = self.eat_u8()? as i32;
        let b3 = self.eat_u8()? as i32;
        return Ok((b0 << 24) + (b1 << 16) + (b2 << 8) + b3)
    }

    fn eat_u32_be(&mut self) -> Result<u32> {
        let b0 = self.eat_u8()? as u32;
        let b1 = self.eat_u8()? as u32;
        let b2 = self.eat_u8()? as u32;
        let b3 = self.eat_u8()? as u32;
        return Ok((b0 << 24) + (b1 << 16) + (b2 << 8) + b3)
    }

    fn eat_u64_be(&mut self) -> Result<u64> {
        let mut n: u64 = 0;
        n += (self.eat_u8()? as u64) << 56;
        n += (self.eat_u8()? as u64) << 48;
        n += (self.eat_u8()? as u64) << 40;
        n += (self.eat_u8()? as u64) << 32;
        n += (self.eat_u8()? as u64) << 24;
        n += (self.eat_u8()? as u64) << 16;
        n += (self.eat_u8()? as u64) << 8;
        n += self.eat_u8()? as u64;
        return Ok(n);
    }
}
<|endoftext|>


<commit_before>use lexer::{LexedToken,Lexer,Token};

pub struct Parser {
    tokens: Vec<LexedToken>,
    current_index: usize
}

impl Parser {
    pub fn new(source: &str) -> Parser {
        let lexer = Lexer::new(source);
        Parser { tokens: lexer.tokens().collect(), current_index: 0 }
    }

    pub fn jump(&mut self, n: isize) {
        match self.index_with_offset(n) {
            Some(index) => self.current_index = index,
            None => panic!("Attempted to jump too far back")
        }
    }

    pub fn consume(&mut self, token: Token) -> Option<String> {
        self.token_at(self.current_index)
            .and_then(|&(ref token_type, ref value)| {
                if *token_type != token { return None; }
                Some(value.clone().into())
            })
            .and_then(|string| {
                self.current_index += 1;
                Some(string)
            })
    }

    pub fn expression(&mut self) -> Option<String> {
        self.type_at(self.current_index)
            .and_then(|token_type| {
                match token_type {
                    Token::Identifier => self.variable(),
                    Token::OpenRound => self.range(),
                    Token::String | Token::Number => self.consume(token_type),
                    _ => panic!("Syntax Error")
                }
            })
    }

    pub fn is_current(&self, token: Token) -> bool {
        self.is_current_offset(token, 0)
    }

    pub fn is_current_offset(&self, token: Token, offset: isize) -> bool {
        self.index_with_offset(offset)
            .and_then(|index| self.is_token(index, token))
            .or_else(|| Some(false))
            .unwrap()
    }

    fn token_at(&self, index: usize) -> Option<&LexedToken> {
        self.tokens.get(index)
    }

    fn type_at(&self, index: usize) -> Option<Token> {
        self.token_at(index)
            .and_then(|&(ref token, _)| Some(token.clone()))
    }

    fn is_token(&self, index: usize, token: Token) -> Option<bool> {
        self.token_at(index)
            .and_then(|&(ref token_type, _)| Some(*token_type == token))
            .or_else(|| Some(false))
    }

    fn index_with_offset(&self, offset: isize) -> Option<usize> {
        let index = (self.current_index as isize).wrapping_add(offset);
        if index < 0 { return None; }

        Some(index as usize)
    }

    fn variable(&mut self) -> Option<String> {
        self.consume(Token::Identifier)
            .and_then(|mut value| {
                while self.is_current(Token::OpenSquare) {
                    value.push_str(&self.consume(Token::OpenSquare).unwrap());
                    value.push_str(&self.expression().unwrap());
                    value.push_str(&self.consume(Token::CloseSquare).unwrap());
                }

                if self.is_current(Token::Dot) {
                    value.push_str(&self.consume(Token::Dot).unwrap());
                    value.push_str(&self.variable().unwrap());
                }

                Some(value)
            })
    }

    fn range(&mut self) -> Option<String> {
        self.consume(Token::OpenRound)
            .and_then(|mut value| {
                value.push_str(&self.expression().unwrap());
                value.push_str(&self.consume(Token::Range).unwrap());
                value.push_str(&self.expression().unwrap());
                value.push_str(&self.consume(Token::CloseRound).unwrap());
                Some(value)
            })
    }
}

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

    #[test]
    fn jump_moves_the_current_index() {
        let mut parser = Parser::new("wat: 7");
        parser.jump(2);

        assert!(parser.is_current(Token::Number));
    }

    #[test]
    fn jump_can_move_backwards() {
        let mut parser = Parser::new("wat: 7");
        parser.jump(2);
        parser.jump(-1);

        assert!(parser.is_current(Token::Colon));
    }

    #[test]
    #[should_panic(expected="Attempted to jump too far back")]
    fn jump_panics_when_index_goes_below_zero() {
        let mut parser = Parser::new("wat: 7");
        parser.jump(-1)
    }

    #[test]
    fn consume_things() {
        let mut parser = Parser::new("wat: 7");
        assert_eq!("wat", parser.consume(Token::Identifier).unwrap());
        assert_eq!(":", parser.consume(Token::Colon).unwrap());
        assert_eq!("7", parser.consume(Token::Number).unwrap());
    }

    #[test]
    fn consume_returns_none_when_token_doesnt_match() {
        let mut parser = Parser::new("wat: 7");
        assert_eq!(None, parser.consume(Token::Number));
        assert_eq!(None, parser.consume(Token::Colon));
        assert!(parser.consume(Token::Identifier).is_some());
    }

    #[test]
    fn is_current_checks_token_type() {
        let mut parser = Parser::new("wat 6 Peter Hegemon");

        assert!(parser.is_current(Token::Identifier));
        parser.consume(Token::Identifier);

        assert_eq!(false, parser.is_current(Token::Comparison));
        assert!(parser.is_current(Token::Number));
        assert!(parser.is_current_offset(Token::Identifier, 1));
        assert_eq!(false, parser.is_current_offset(Token::Number, 1));
    }

    #[test]
    fn is_current_offset_returns_false_when_offset_is_not_valid() {
        let mut parser = Parser::new("wat 6 Peter Hegemon");
        parser.jump(1);

        assert!(parser.is_current_offset(Token::Number, 0));
        assert!(parser.is_current_offset(Token::Identifier, -1));
        assert_eq!(false, parser.is_current_offset(Token::Identifier, -2));
    }

    #[test]
    fn expression_parsing_identifiers_strings_and_numbers() {
        let mut parser = Parser::new("hi.there hi?[5].there? hi.there.bob");
        assert_eq!("hi.there", parser.expression().unwrap());
        assert_eq!("hi?[5].there?", parser.expression().unwrap());
        assert_eq!("hi.there.bob", parser.expression().unwrap());

        let mut parser = Parser::new("567 6.0 'lol' \"wut\"");
        assert_eq!("567", parser.expression().unwrap());
        assert_eq!("6.0", parser.expression().unwrap());
        assert_eq!("'lol'", parser.expression().unwrap());
        assert_eq!("\"wut\"", parser.expression().unwrap());
    }

    #[test]
    fn expression_parsing_ranges() {
        let mut parser = Parser::new("(5..7) (1.5..9.6) (young..old) (hi[5].wat..old)");
        assert_eq!("(5..7)", parser.expression().unwrap());
        assert_eq!("(1.5..9.6)", parser.expression().unwrap());
        assert_eq!("(young..old)", parser.expression().unwrap());
        assert_eq!("(hi[5].wat..old)", parser.expression().unwrap());
    }
}
<commit_msg>parsing normal and keyword arguments<commit_after>use lexer::{LexedToken,Lexer,Token};

pub struct Parser {
    tokens: Vec<LexedToken>,
    current_index: usize
}

impl Parser {
    pub fn new(source: &str) -> Parser {
        let lexer = Lexer::new(source);
        Parser { tokens: lexer.tokens().collect(), current_index: 0 }
    }

    pub fn jump(&mut self, n: isize) {
        match self.index_with_offset(n) {
            Some(index) => self.current_index = index,
            None => panic!("Attempted to jump too far back")
        }
    }

    pub fn consume(&mut self, token: Token) -> Option<String> {
        self.token_at(self.current_index)
            .and_then(|&(ref token_type, ref value)| {
                if *token_type != token { return None; }
                Some(value.clone().into())
            })
            .and_then(|string| {
                self.current_index += 1;
                Some(string)
            })
    }

    pub fn expression(&mut self) -> Option<String> {
        self.type_at(self.current_index)
            .and_then(|token_type| {
                match token_type {
                    Token::Identifier => self.variable(),
                    Token::OpenRound => self.range(),
                    Token::String | Token::Number => self.consume(token_type),
                    _ => panic!("Syntax Error")
                }
            })
    }

    pub fn argument(&mut self) -> Option<String> {
        if self.is_current(Token::Identifier) && self.is_current_offset(Token::Colon, 1) {
            let mut result = String::new();
            result.push_str(&self.consume(Token::Identifier).unwrap());
            result.push_str(&self.consume(Token::Colon).unwrap());

            return self.expression().and_then(|value| {
                result.push_str(&value);
                Some(result)
            });
        }

        self.expression()
    }

    pub fn is_current(&self, token: Token) -> bool {
        self.is_current_offset(token, 0)
    }

    pub fn is_current_offset(&self, token: Token, offset: isize) -> bool {
        self.index_with_offset(offset)
            .and_then(|index| self.is_token(index, token))
            .or_else(|| Some(false))
            .unwrap()
    }

    fn token_at(&self, index: usize) -> Option<&LexedToken> {
        self.tokens.get(index)
    }

    fn type_at(&self, index: usize) -> Option<Token> {
        self.token_at(index)
            .and_then(|&(ref token, _)| Some(token.clone()))
    }

    fn is_token(&self, index: usize, token: Token) -> Option<bool> {
        self.token_at(index)
            .and_then(|&(ref token_type, _)| Some(*token_type == token))
            .or_else(|| Some(false))
    }

    fn index_with_offset(&self, offset: isize) -> Option<usize> {
        let index = (self.current_index as isize).wrapping_add(offset);
        if index < 0 { return None; }

        Some(index as usize)
    }

    fn variable(&mut self) -> Option<String> {
        self.consume(Token::Identifier)
            .and_then(|mut value| {
                while self.is_current(Token::OpenSquare) {
                    value.push_str(&self.consume(Token::OpenSquare).unwrap());
                    value.push_str(&self.expression().unwrap());
                    value.push_str(&self.consume(Token::CloseSquare).unwrap());
                }

                if self.is_current(Token::Dot) {
                    value.push_str(&self.consume(Token::Dot).unwrap());
                    value.push_str(&self.variable().unwrap());
                }

                Some(value)
            })
    }

    fn range(&mut self) -> Option<String> {
        self.consume(Token::OpenRound)
            .and_then(|mut value| {
                value.push_str(&self.expression().unwrap());
                value.push_str(&self.consume(Token::Range).unwrap());
                value.push_str(&self.expression().unwrap());
                value.push_str(&self.consume(Token::CloseRound).unwrap());
                Some(value)
            })
    }
}

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

    #[test]
    fn jump_moves_the_current_index() {
        let mut parser = Parser::new("wat: 7");
        parser.jump(2);

        assert!(parser.is_current(Token::Number));
    }

    #[test]
    fn jump_can_move_backwards() {
        let mut parser = Parser::new("wat: 7");
        parser.jump(2);
        parser.jump(-1);

        assert!(parser.is_current(Token::Colon));
    }

    #[test]
    #[should_panic(expected="Attempted to jump too far back")]
    fn jump_panics_when_index_goes_below_zero() {
        let mut parser = Parser::new("wat: 7");
        parser.jump(-1)
    }

    #[test]
    fn consume_things() {
        let mut parser = Parser::new("wat: 7");
        assert_eq!("wat", parser.consume(Token::Identifier).unwrap());
        assert_eq!(":", parser.consume(Token::Colon).unwrap());
        assert_eq!("7", parser.consume(Token::Number).unwrap());
    }

    #[test]
    fn consume_returns_none_when_token_doesnt_match() {
        let mut parser = Parser::new("wat: 7");
        assert_eq!(None, parser.consume(Token::Number));
        assert_eq!(None, parser.consume(Token::Colon));
        assert!(parser.consume(Token::Identifier).is_some());
    }

    #[test]
    fn is_current_checks_token_type() {
        let mut parser = Parser::new("wat 6 Peter Hegemon");

        assert!(parser.is_current(Token::Identifier));
        parser.consume(Token::Identifier);

        assert_eq!(false, parser.is_current(Token::Comparison));
        assert!(parser.is_current(Token::Number));
        assert!(parser.is_current_offset(Token::Identifier, 1));
        assert_eq!(false, parser.is_current_offset(Token::Number, 1));
    }

    #[test]
    fn is_current_offset_returns_false_when_offset_is_not_valid() {
        let mut parser = Parser::new("wat 6 Peter Hegemon");
        parser.jump(1);

        assert!(parser.is_current_offset(Token::Number, 0));
        assert!(parser.is_current_offset(Token::Identifier, -1));
        assert_eq!(false, parser.is_current_offset(Token::Identifier, -2));
    }

    #[test]
    fn expression_parsing_identifiers_strings_and_numbers() {
        let mut parser = Parser::new("hi.there hi?[5].there? hi.there.bob");
        assert_eq!("hi.there", parser.expression().unwrap());
        assert_eq!("hi?[5].there?", parser.expression().unwrap());
        assert_eq!("hi.there.bob", parser.expression().unwrap());

        let mut parser = Parser::new("567 6.0 'lol' \"wut\"");
        assert_eq!("567", parser.expression().unwrap());
        assert_eq!("6.0", parser.expression().unwrap());
        assert_eq!("'lol'", parser.expression().unwrap());
        assert_eq!("\"wut\"", parser.expression().unwrap());
    }

    #[test]
    fn expression_parsing_ranges() {
        let mut parser = Parser::new("(5..7) (1.5..9.6) (young..old) (hi[5].wat..old)");
        assert_eq!("(5..7)", parser.expression().unwrap());
        assert_eq!("(1.5..9.6)", parser.expression().unwrap());
        assert_eq!("(young..old)", parser.expression().unwrap());
        assert_eq!("(hi[5].wat..old)", parser.expression().unwrap());
    }

    #[test]
    fn argument_parses_simple_arguments() {
        let mut parser = Parser::new("filter: hi?.there[5]");
        parser.consume(Token::Identifier);
        parser.consume(Token::Colon);

        assert_eq!("hi?.there[5]", parser.argument().unwrap());
    }

    #[test]
    fn argument_can_handle_keyword_arguments() {
        let mut parser = Parser::new("filter: hi?.there[5], type: 7");

        parser.consume(Token::Identifier);
        parser.consume(Token::Colon);
        assert_eq!("hi?.there[5]", parser.argument().unwrap());

        parser.consume(Token::Comma);
        assert_eq!("type:7", parser.argument().unwrap());
    }
}
<|endoftext|>