<commit_before>//! Utility macros

/// Expands into a series of for loops with the given block of code which should
/// treat each type uniformly.
///
/// This is to avoid dynamic dispatch when chaining iterators over generic
/// collections when the types are known.
#[macro_export]
macro_rules! for_sequence {
  (
    $pattern:pat in $($iter:expr),* $do:block
  ) => {
    $(for $pattern in $iter $do)+
  }
}

/// Print the stringified expression followed by its debug formatting
#[macro_export]
macro_rules! show {
  ($e:expr) => {
    println!("{}: {:?}", stringify!($e), $e);
  }
}

/// Print the stringified expression followed by its pretty debug formatting
#[macro_export]
macro_rules! pretty {
  ($e:expr) => {
    println!("{}: {:#?}", stringify!($e), $e);
  }
}

/// Print the stringified expression followed by its display formatting
#[macro_export]
macro_rules! display {
  ($e:expr) => {
    println!("{}: {}", stringify!($e), $e);
  }
}

/// Print the stringified expression followed by its bitstring formatting
#[macro_export]
macro_rules! bits {
  ($e:expr) => {
    println!("{}: {:b}", stringify!($e), $e);
  }
}

/// Print the stringified expression followed by its hexadecimal formatting
#[macro_export]
macro_rules! hex {
  ($e:expr) => {
    println!("{}: {:x}", stringify!($e), $e);
  }
}

/// Print the stringified expression followed by its pointer formatting
#[macro_export]
macro_rules! address {
  ($e:expr) => {
    println!("{}: {:p}", stringify!($e), $e);
  }
}
<commit_msg>fix for_sequence! macro<commit_after>//! Utility macros

/// Expands into a series of for loops with the given block of code which should
/// treat each type uniformly.
///
/// This is to avoid dynamic dispatch when chaining iterators over generic
/// collections when the types are known.
#[macro_export]
macro_rules! for_sequence {
  (
    $pattern:pat in ($($iter:expr),+) $do:block
  ) => {
    $(for $pattern in $iter $do)+
  }
}

/// Print the stringified expression followed by its debug formatting
#[macro_export]
macro_rules! show {
  ($e:expr) => {
    println!("{}: {:?}", stringify!($e), $e);
  }
}

/// Print the stringified expression followed by its pretty debug formatting
#[macro_export]
macro_rules! pretty {
  ($e:expr) => {
    println!("{}: {:#?}", stringify!($e), $e);
  }
}

/// Print the stringified expression followed by its display formatting
#[macro_export]
macro_rules! display {
  ($e:expr) => {
    println!("{}: {}", stringify!($e), $e);
  }
}

/// Print the stringified expression followed by its bitstring formatting
#[macro_export]
macro_rules! bits {
  ($e:expr) => {
    println!("{}: {:b}", stringify!($e), $e);
  }
}

/// Print the stringified expression followed by its hexadecimal formatting
#[macro_export]
macro_rules! hex {
  ($e:expr) => {
    println!("{}: {:x}", stringify!($e), $e);
  }
}

/// Print the stringified expression followed by its pointer formatting
#[macro_export]
macro_rules! address {
  ($e:expr) => {
    println!("{}: {:p}", stringify!($e), $e);
  }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust-Windows Project Developers. See the
// COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[macro_export]
macro_rules! wnd_proc_thunk(
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_CREATE) => (
        if $msg == 0x0001 { // WM_CREATE
            let cs = unsafe {
                let pcs = ::std::mem::transmute::<::windows::ll::types::LPARAM,
                                                   *const ::windows::ll::all::CREATESTRUCT>($l);
                &(*pcs)
            };
            let ret = $self_.on_create(cs);
            if ret {
                return 0 as ::windows::ll::types::LRESULT;
            } else {
                return -1 as ::windows::ll::types::LRESULT;
            }
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_DESTROY) => (
        if $msg == 0x0002 { // WM_DESTROY
            $self_.on_destroy();
            return 0 as ::windows::ll::types::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_SIZE) => (
        if $msg == 0x0005 { // WM_SIZE
            let l = $l as u32;
            let width = (l & 0xFFFF) as isize;
            let height = (l >> 16) as isize;
            $self_.on_size(width, height);
            return 0 as ::windows::ll::types::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_SETFOCUS) => (
        if $msg == 0x0007 { // WM_SETFOCUS
            let w = ::windows::window::Window { wnd: $w as ::windows::ll::types::HWND };
            $self_.on_focus(w);
            return 0 as ::windows::ll::types::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_PAINT) => (
        if $msg == 0x000F { // WM_PAINT
            $self_.on_paint();
            return 0 as ::windows::ll::types::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_LBUTTONDOWN) => (
        if $msg == 0x0201 { // WM_LBUTTONDOWN
            let l = $l as u32;
            let x = (l & 0xFFFF) as isize;
            let y = (l >> 16) as isize;
            let flags = $w as u32;
            $self_.on_left_button_down(x, y, flags);
            return 0 as ::windows::ll::types::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_LBUTTONUP) => (
        if $msg == 0x0202 { // WM_LBUTTONUP
            let l = $l as u32;
            let x = (l & 0xFFFF) as isize;
            let y = (l >> 16) as isize;
            let flags = $w as u32;
            $self_.on_left_button_up(x, y, flags);
            return 0 as ::windows::ll::types::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_KEYDOWN) => (
        if $msg == 0x0100 { // WM_KEYDOWN
            return $self_.on_key_down($w as u8, $l as u32) as ::windows::ll::types::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_KEYUP) => (
        if $msg == 0x0101 { // WM_KEYUP
            return $self_.on_key_up($w as u8, $l as u32) as ::windows::ll::types::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_ERASEBKGND) => (
        if $msg == 0x0014 { // WM_ERASEBKGND
            // Returning 1 means that the background no longer needs erasing.
            return $self_.on_erase_background() as ::windows::ll::types::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, ANY) => (
        if let Some(result) = $self_.on_message($msg, $w, $l) {
            return result;
        }
    );
);

#[macro_export]
macro_rules! wnd_proc(
    ($wnd:ident, $win:ident, $($msg:ident),+) => (

    impl ::windows::window::WindowImpl for $wnd {
        fn wnd<'a>(&'a self) -> &'a ::windows::window::Window {
            &self.$win
        }

        fn wnd_mut<'a>(&'a mut self) -> &'a mut ::windows::window::Window {
            &mut self.$win
        }

        fn wnd_proc(&self, msg: ::windows::ll::types::UINT, w: ::windows::ll::types::WPARAM,
                    l: ::windows::ll::types::LPARAM) -> ::windows::ll::types::LRESULT {
            $(
                wnd_proc_thunk!(self, msg, w, l, $msg);
            )+
            ::windows::def_window_proc(self.wnd().wnd, msg, w, l)
        }
    }

    )
);
<commit_msg>fix macros.rs to use winapi crate instead from windows::ll<commit_after>// Copyright 2015 The Rust-Windows Project Developers. See the
// COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[macro_export]
macro_rules! wnd_proc_thunk(
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_CREATE) => (
        if $msg == 0x0001 { // WM_CREATE
            let cs = unsafe {
                let pcs = ::std::mem::transmute::<::winapi::LPARAM,
                                                   *const ::winapi::CREATESTRUCTW>($l);
                &(*pcs)
            };
            let ret = $self_.on_create(cs);
            if ret {
                return 0 as ::winapi::LRESULT;
            } else {
                return -1 as ::winapi::LRESULT;
            }
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_DESTROY) => (
        if $msg == 0x0002 { // WM_DESTROY
            $self_.on_destroy();
            return 0 as ::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_SIZE) => (
        if $msg == 0x0005 { // WM_SIZE
            let l = $l as u32;
            let width = (l & 0xFFFF) as isize;
            let height = (l >> 16) as isize;
            $self_.on_size(width, height);
            return 0 as ::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_SETFOCUS) => (
        if $msg == 0x0007 { // WM_SETFOCUS
            let w = ::windows::window::Window { wnd: $w as ::winapi::HWND };
            $self_.on_focus(w);
            return 0 as ::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_PAINT) => (
        if $msg == 0x000F { // WM_PAINT
            $self_.on_paint();
            return 0 as ::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_LBUTTONDOWN) => (
        if $msg == 0x0201 { // WM_LBUTTONDOWN
            let l = $l as u32;
            let x = (l & 0xFFFF) as isize;
            let y = (l >> 16) as isize;
            let flags = $w as u32;
            $self_.on_left_button_down(x, y, flags);
            return 0 as ::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_LBUTTONUP) => (
        if $msg == 0x0202 { // WM_LBUTTONUP
            let l = $l as u32;
            let x = (l & 0xFFFF) as isize;
            let y = (l >> 16) as isize;
            let flags = $w as u32;
            $self_.on_left_button_up(x, y, flags);
            return 0 as ::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_KEYDOWN) => (
        if $msg == 0x0100 { // WM_KEYDOWN
            return $self_.on_key_down($w as u8, $l as u32) as ::winapi::::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_KEYUP) => (
        if $msg == 0x0101 { // WM_KEYUP
            return $self_.on_key_up($w as u8, $l as u32) as ::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_ERASEBKGND) => (
        if $msg == 0x0014 { // WM_ERASEBKGND
            // Returning 1 means that the background no longer needs erasing.
            return $self_.on_erase_background() as ::winapi::LRESULT;
        }
    );
    ($self_:ident, $msg:ident, $w:ident, $l:ident, ANY) => (
        if let Some(result) = $self_.on_message($msg, $w, $l) {
            return result;
        }
    );
);

#[macro_export]
macro_rules! wnd_proc(
    ($wnd:ident, $win:ident, $($msg:ident),+) => (

    impl ::windows::window::WindowImpl for $wnd {
        fn wnd<'a>(&'a self) -> &'a ::windows::window::Window {
            &self.$win
        }

        fn wnd_mut<'a>(&'a mut self) -> &'a mut ::windows::window::Window {
            &mut self.$win
        }

        fn wnd_proc(&self, msg: ::winapi::UINT, w: ::winapi::WPARAM,
                    l: ::winapi::LPARAM) -> ::winapi::LRESULT {
            $(
                wnd_proc_thunk!(self, msg, w, l, $msg);
            )+
            ::windows::def_window_proc(self.wnd().wnd, msg, w, l)
        }
    }

    )
);
<|endoftext|>


<commit_before>pub mod responses {

    use std::fmt;

    use serde::Deserialize;
    use serde_json as json;

    #[derive(Deserialize, Debug)]
    pub struct AuthResponse {
        pub session: SessionResponse,
    }

    #[derive(Deserialize, Debug, Clone)]
    pub struct SessionResponse {
        pub key: String,
        pub subscriber: i64,
        pub name: String,
    }

    #[derive(Deserialize)]
    pub struct NowPlayingResponseWrapper {
        pub nowplaying: NowPlayingResponse,
    }

    #[derive(Deserialize, Debug)]
    pub struct NowPlayingResponse {
        pub artist: CorrectableString,
        pub album: CorrectableString,
        #[serde(rename = "albumArtist")]
        pub album_artist: CorrectableString,
        pub track: CorrectableString,
    }

    #[derive(Deserialize)]
    pub struct ScrobbleResponseWrapper {
        pub scrobbles: SingleScrobble,
    }

    #[derive(Deserialize)]
    pub struct SingleScrobble {
        pub scrobble: ScrobbleResponse,
    }

    #[derive(Deserialize, Debug, WrappedVec)]
    #[CollectionName = "ScrobbleList"]
    #[CollectionDerives = "Debug, Deserialize"]
    pub struct ScrobbleResponse {
        pub artist: CorrectableString,
        pub album: CorrectableString,
        #[serde(rename = "albumArtist")]
        pub album_artist: CorrectableString,
        pub track: CorrectableString,
        pub timestamp: String,
        //  TODO: Ignored field here? (#20)
    }

    #[derive(Debug)]
    pub struct BatchScrobbleResponse {
        pub scrobbles: ScrobbleList,
    }

    #[derive(Deserialize, Debug)]
    pub struct BatchScrobbleResponseWrapper {
        pub scrobbles: BatchScrobbles,
    }

    #[derive(Deserialize, Debug)]
    pub struct BatchScrobbles {
        #[serde(rename = "scrobble")]
        pub scrobbles: ScrobbleList,
    }

    #[derive(Deserialize, Debug)]
    pub struct CorrectableString {
        #[serde(deserialize_with = "CorrectableString::deserialize_corrected_field")]
        pub corrected: bool,
        #[serde(rename = "#text", default)]
        pub text: String,
    }

    impl CorrectableString {
        fn deserialize_corrected_field<'de, D>(de: D) -> Result<bool, D::Error>
        where
            D: serde::Deserializer<'de>,
        {
            let deser_result: json::Value = serde::Deserialize::deserialize(de)?;
            match deser_result {
                json::Value::String(ref s) if &*s == "1" => Ok(true),
                json::Value::String(ref s) if &*s == "0" => Ok(false),
                _ => Err(serde::de::Error::custom("Unexpected value")),
            }
        }
    }

    impl fmt::Display for CorrectableString {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            write!(f, "{}", self.text)
        }
    }
}

pub mod metadata {

    use std::collections::HashMap;

    /// Repesents a single track play (aka a "scrobble")
    #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, WrappedVec)]
    #[CollectionName = "ScrobbleBatch"]
    #[CollectionDoc = "A batch of Scrobbles to be submitted to Last.fm together."]
    #[CollectionDerives = "Clone, Debug"]
    pub struct Scrobble {
        artist: String,
        track: String,
        album: String,

        timestamp: Option<u64>,
    }

    impl Scrobble {
        /// Constructs a new Scrobble instance, representing a music track
        /// played in the past.
        pub fn new(artist: &str, track: &str, album: &str) -> Self {
            Self {
                artist: artist.to_owned(),
                track: track.to_owned(),
                album: album.to_owned(),
                timestamp: None,
            }
        }

        /// Sets the timestamp (date/time of play) of a Scrobble. Used in a builder-style pattern, typically after
        /// [`Scrobble::new`].
        ///
        /// **Note:**  Scrobbles without timestamps are automatically assigned a timestamp of the current time when
        /// submitted via [`Scrobbler::scrobble`] or [`Scrobbler::scrobble_batch`]. Timestamps only need to be
        /// explicitly set when you are submitting a Scrobble at a point in the past, or in the future.
        ///
        /// # Example
        /// ```
        /// let mut scrobble = Scrobble::new(...).with_timestamp(12345)
        /// ```
        ///
        /// [`Scrobble::new`]: struct.Scrobble.html#method.new
        /// [`Scrobbler::scrobble`]: struct.Scrobbler.html#method.scrobble
        /// [`Scrobbler::scrobble_batch`]: struct.Scrobbler.html#method.scrobble_batch
        pub fn with_timestamp(&mut self, timestamp: u64) -> &mut Self {
            self.timestamp = Some(timestamp);
            self
        }

        /// Converts the Scrobble metadata (track name, artist & album name) into a [`HashMap`]. Map keys are
        /// `"track"`, `"artist"` and `"album"`. If a timestamp is set, it will be present in the map under key
        /// `"timestamp"`.
        ///
        /// # Example
        /// ```
        /// let scrobble = Scrobble::new("Example Artist", ...);
        /// let scrobble_map = scrobble.as_map();
        /// assert_eq!(scrobble_map.get("artist"), "Example Artist");
        /// ```
        ///
        /// [`HashMap`]: struct.HashMap.html
        pub fn as_map(&self) -> HashMap<String, String> {
            let mut params = HashMap::new();
            params.insert("track".to_string(), self.track.clone());
            params.insert("artist".to_string(), self.artist.clone());
            params.insert("album".to_string(), self.album.clone());

            if let Some(timestamp) = self.timestamp {
                params.insert("timestamp".to_string(), timestamp.to_string());
            }

            params
        }

        pub fn artist(&self) -> &str {
            &self.artist
        }

        pub fn track(&self) -> &str {
            &self.track
        }

        pub fn album(&self) -> &str {
            &self.album
        }
    }

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

        #[test]
        fn make_scrobble() {
            let mut scrobble = Scrobble::new(
                "foo floyd and the fruit flies",
                "old bananas",
                "old bananas",
            );
            scrobble.with_timestamp(1337);
            assert_eq!(scrobble.artist(), "foo floyd and the fruit flies");
            assert_eq!(scrobble.track(), "old bananas");
            assert_eq!(scrobble.album(), "old bananas");
            assert_eq!(scrobble.timestamp, Some(1337));
        }

        #[test]
        fn make_scrobble_check_map() {
            let scrobble = Scrobble::new(
                "foo floyd and the fruit flies",
                "old bananas",
                "old bananas",
            );

            let params = scrobble.as_map();
            assert_eq!(params["artist"], "foo floyd and the fruit flies");
            assert_eq!(params["track"], "old bananas");
            assert_eq!(params["album"], "old bananas");
        }
    }
}
<commit_msg>More Scrobble documentation<commit_after>pub mod responses {

    use std::fmt;

    use serde::Deserialize;
    use serde_json as json;

    #[derive(Deserialize, Debug)]
    pub struct AuthResponse {
        pub session: SessionResponse,
    }

    #[derive(Deserialize, Debug, Clone)]
    pub struct SessionResponse {
        pub key: String,
        pub subscriber: i64,
        pub name: String,
    }

    #[derive(Deserialize)]
    pub struct NowPlayingResponseWrapper {
        pub nowplaying: NowPlayingResponse,
    }

    #[derive(Deserialize, Debug)]
    pub struct NowPlayingResponse {
        pub artist: CorrectableString,
        pub album: CorrectableString,
        #[serde(rename = "albumArtist")]
        pub album_artist: CorrectableString,
        pub track: CorrectableString,
    }

    #[derive(Deserialize)]
    pub struct ScrobbleResponseWrapper {
        pub scrobbles: SingleScrobble,
    }

    #[derive(Deserialize)]
    pub struct SingleScrobble {
        pub scrobble: ScrobbleResponse,
    }

    #[derive(Deserialize, Debug, WrappedVec)]
    #[CollectionName = "ScrobbleList"]
    #[CollectionDerives = "Debug, Deserialize"]
    pub struct ScrobbleResponse {
        pub artist: CorrectableString,
        pub album: CorrectableString,
        #[serde(rename = "albumArtist")]
        pub album_artist: CorrectableString,
        pub track: CorrectableString,
        pub timestamp: String,
        //  TODO: Ignored field here? (#20)
    }

    #[derive(Debug)]
    pub struct BatchScrobbleResponse {
        pub scrobbles: ScrobbleList,
    }

    #[derive(Deserialize, Debug)]
    pub struct BatchScrobbleResponseWrapper {
        pub scrobbles: BatchScrobbles,
    }

    #[derive(Deserialize, Debug)]
    pub struct BatchScrobbles {
        #[serde(rename = "scrobble")]
        pub scrobbles: ScrobbleList,
    }

    #[derive(Deserialize, Debug)]
    pub struct CorrectableString {
        #[serde(deserialize_with = "CorrectableString::deserialize_corrected_field")]
        pub corrected: bool,
        #[serde(rename = "#text", default)]
        pub text: String,
    }

    impl CorrectableString {
        fn deserialize_corrected_field<'de, D>(de: D) -> Result<bool, D::Error>
        where
            D: serde::Deserializer<'de>,
        {
            let deser_result: json::Value = serde::Deserialize::deserialize(de)?;
            match deser_result {
                json::Value::String(ref s) if &*s == "1" => Ok(true),
                json::Value::String(ref s) if &*s == "0" => Ok(false),
                _ => Err(serde::de::Error::custom("Unexpected value")),
            }
        }
    }

    impl fmt::Display for CorrectableString {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            write!(f, "{}", self.text)
        }
    }
}

pub mod metadata {

    use std::collections::HashMap;

    /// Repesents a single music track played at a point in time. In the Last.fm universe, this is known as a
    /// "scrobble".
    ///
    /// Takes an artist, track and album name. Can hold a timestamp indicating when the track was listened to.
    /// `Scrobble` objects are submitted via [`Scrobbler::now_playing`], [`Scrobbler::scrobble`] and batches of
    /// Scrobbles are sent via [`Scrobbler::scrobble_batch`].
    ///
    /// [`Scrobbler::now_playing`]: struct.Scrobbler.html#method.now_playing
    /// [`Scrobbler::scrobble`]: struct.Scrobbler.html#method.scrobble
    /// [`Scrobbler::scrobble_batch`]: struct.Scrobbler.html#method.scrobble_batch
    #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, WrappedVec)]
    #[CollectionName = "ScrobbleBatch"]
    #[CollectionDoc = "A batch of Scrobbles to be submitted to Last.fm together."]
    #[CollectionDerives = "Clone, Debug"]
    pub struct Scrobble {
        artist: String,
        track: String,
        album: String,

        timestamp: Option<u64>,
    }

    impl Scrobble {

        /// Constructs a new Scrobble instance, representing a single playthrough of a music track. Scrobble's are
        /// submitted to Last.fm via an instance of [`Scrobbler`]. A new Scrobble requires an artist name, song/track
        /// name, and an album name.
        ///
        /// # Example
        /// ```
        /// let scrobble = Scrobble::new("Example Artist", "Example Track", "Example Album")
        /// ```
        ///
        /// [`Scrobbler`]: struct.Scrobbler.html
        pub fn new(artist: &str, track: &str, album: &str) -> Self {
            Self {
                artist: artist.to_owned(),
                track: track.to_owned(),
                album: album.to_owned(),
                timestamp: None,
            }
        }

        /// Sets the timestamp (date/time of play) of a Scrobble. Used in a builder-style pattern, typically after
        /// [`Scrobble::new`].
        ///
        /// # Example
        /// ```
        /// let mut scrobble = Scrobble::new(...).with_timestamp(12345);
        /// ```
        ///
        /// # Note on Timestamps
        /// Scrobbles without timestamps are automatically assigned a timestamp of the current time when
        /// submitted via [`Scrobbler::scrobble`] or [`Scrobbler::scrobble_batch`]. Timestamps only need to be
        /// explicitly set when you are submitting a Scrobble at a point in the past, or in the future.
        ///
        /// [`Scrobble::new`]: struct.Scrobble.html#method.new
        /// [`Scrobbler::scrobble`]: struct.Scrobbler.html#method.scrobble
        /// [`Scrobbler::scrobble_batch`]: struct.Scrobbler.html#method.scrobble_batch
        pub fn with_timestamp(&mut self, timestamp: u64) -> &mut Self {
            self.timestamp = Some(timestamp);
            self
        }

        /// Converts the Scrobble metadata (track name, artist & album name) into a [`HashMap`]. Map keys are
        /// `"track"`, `"artist"` and `"album"`. If a timestamp is set, it will be present in the map under key
        /// `"timestamp"`.
        ///
        /// # Example
        /// ```
        /// let scrobble = Scrobble::new("Example Artist", ...);
        /// let scrobble_map = scrobble.as_map();
        /// assert_eq!(scrobble_map.get("artist"), "Example Artist");
        /// ```
        ///
        /// [`HashMap`]: struct.HashMap.html // TODO: This doesn't work
        pub fn as_map(&self) -> HashMap<String, String> {
            let mut params = HashMap::new();
            params.insert("track".to_string(), self.track.clone());
            params.insert("artist".to_string(), self.artist.clone());
            params.insert("album".to_string(), self.album.clone());

            if let Some(timestamp) = self.timestamp {
                params.insert("timestamp".to_string(), timestamp.to_string());
            }

            params
        }

        /// Returns the `Scrobble`'s artist name
        pub fn artist(&self) -> &str {
            &self.artist
        }

        /// Returns the `Scrobble`'s track name
        pub fn track(&self) -> &str {
            &self.track
        }

        /// Returns the `Scrobble`'s album name
        pub fn album(&self) -> &str {
            &self.album
        }

    }

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

        #[test]
        fn make_scrobble() {
            let mut scrobble = Scrobble::new(
                "foo floyd and the fruit flies",
                "old bananas",
                "old bananas",
            );
            scrobble.with_timestamp(1337);
            assert_eq!(scrobble.artist(), "foo floyd and the fruit flies");
            assert_eq!(scrobble.track(), "old bananas");
            assert_eq!(scrobble.album(), "old bananas");
            assert_eq!(scrobble.timestamp, Some(1337));
        }

        #[test]
        fn make_scrobble_check_map() {
            let scrobble = Scrobble::new(
                "foo floyd and the fruit flies",
                "old bananas",
                "old bananas",
            );

            let params = scrobble.as_map();
            assert_eq!(params["artist"], "foo floyd and the fruit flies");
            assert_eq!(params["track"], "old bananas");
            assert_eq!(params["album"], "old bananas");
        }
    }
}
<|endoftext|>


<commit_before>use hyper::client::Client;
use nickel::{Request, Response, MiddlewareResult, QueryString};
use common;
use nickel::status::StatusCode;
use mustache::MapBuilder;

pub fn nearby_handler<'a, D>(request: &mut Request<D>,
                             mut response: Response<'a, D>)
                             -> MiddlewareResult<'a, D> {
    let client = Client::new();
    let query = request.query();
    let latitude = query.get("latitude").expect("Missing latitude");
    let longitude = query.get("longitude").expect("Missing longitude");
    let url = &format!("https://api.tfl.gov.\
                        uk/StopPoint?lat={}&lon={}\
                        &stopTypes=NaptanOnstreetBusCoachStopPair&radius=300",
                       latitude,
                       longitude);
    let obj = match common::json_for_request(client.get(url)) {
        Ok(val) => val,
        Err(val) => {
            response.set(StatusCode::BadGateway);
            return response.send(val);
        }
    };

    let data = MapBuilder::new()
        .insert_vec("stops", |vecbuilder| {
            let mut vecb = vecbuilder;
            for stopgroup in obj["stopPoints"].members() {
                for stop in stopgroup["children"].members() {
                    vecb = vecb.push_map(|mapbuilder| {
                        let letter = match stop["stopLetter"].as_str() {
                            Some(val) => format!(" ({})", val),
                            None => "".to_string(),
                        };
                        mapbuilder.insert_str("id", stop["naptanId"].as_str().unwrap())
                            .insert_str("stop", letter)
                            .insert_str("name", stop["commonName"].as_str().unwrap())
                    });
                }
            }
            vecb
        })
        .insert_str("query", "Nearby stops")
        .build();
    common::render_to_response(response, "resources/templates/search.mustache", &data)
}
<commit_msg>Expand range of nearby stops (fixes #5)<commit_after>use hyper::client::Client;
use nickel::{Request, Response, MiddlewareResult, QueryString};
use common;
use nickel::status::StatusCode;
use mustache::MapBuilder;

pub fn nearby_handler<'a, D>(request: &mut Request<D>,
                             mut response: Response<'a, D>)
                             -> MiddlewareResult<'a, D> {
    let client = Client::new();
    let query = request.query();
    let latitude = query.get("latitude").expect("Missing latitude");
    let longitude = query.get("longitude").expect("Missing longitude");
    let url = &format!("https://api.tfl.gov.\
                        uk/StopPoint?lat={}&lon={}\
                        &stopTypes=NaptanOnstreetBusCoachStopPair&radius=500",
                       latitude,
                       longitude);
    let obj = match common::json_for_request(client.get(url)) {
        Ok(val) => val,
        Err(val) => {
            response.set(StatusCode::BadGateway);
            return response.send(val);
        }
    };

    let data = MapBuilder::new()
        .insert_vec("stops", |vecbuilder| {
            let mut vecb = vecbuilder;
            for stopgroup in obj["stopPoints"].members() {
                for stop in stopgroup["children"].members() {
                    vecb = vecb.push_map(|mapbuilder| {
                        let letter = match stop["stopLetter"].as_str() {
                            Some(val) => format!(" ({})", val),
                            None => "".to_string(),
                        };
                        mapbuilder.insert_str("id", stop["naptanId"].as_str().unwrap())
                            .insert_str("stop", letter)
                            .insert_str("name", stop["commonName"].as_str().unwrap())
                    });
                }
            }
            vecb
        })
        .insert_str("query", "Nearby stops")
        .build();
    common::render_to_response(response, "resources/templates/search.mustache", &data)
}
<|endoftext|>


<commit_before>use cursor::XCursorImage;
use std::ffi::CStr;
use wlroots_sys::{list_t, wlr_output, wlr_output__bindgen_ty_1, wlr_output_layout,
                  wlr_output_layout_add_auto, wlr_output_layout_create, wlr_output_layout_destroy,
                  wlr_output_make_current, wlr_output_set_cursor, wlr_output_swap_buffers};

/// A wrapper around a wlr_output.
#[derive(Debug)]
pub struct Output {
    output: *mut wlr_output
}

// TODO Call it Layout, use as output::Layout?
#[derive(Debug)]
pub struct OutputLayout {
    layout: *mut wlr_output_layout
}

// TODO We are assuming the output is live in these functions,
// but we need some way to ensure that.
// E.g we need to control access to the "Output",
// probably only in certain methods.

impl Output {
    pub fn set_cursor<'cursor>(&mut self, image: &'cursor XCursorImage<'cursor>) -> Result<(), ()> {
        unsafe {
            match wlr_output_set_cursor(self.output,
                                        image.buffer.as_ptr(),
                                        image.width as i32,
                                        image.width,
                                        image.height,
                                        image.hotspot_x as i32,
                                        image.hotspot_y as i32) {
                true => Ok(()),
                false => Err(()),
            }
        }
    }

    /// Gets the name of the output in UTF-8.
    pub fn name(&self) -> String {
        unsafe {
            CStr::from_ptr((*self.output).name.as_ptr())
                .to_string_lossy()
                .into_owned()
        }
    }

    /// Gets the make of the output in UTF-8.
    pub fn make(&self) -> String {
        unsafe {
            CStr::from_ptr((*self.output).make.as_ptr())
                .to_string_lossy()
                .into_owned()
        }
    }

    /// Gets the model of the output in UTF-8.
    pub fn model(&self) -> String {
        unsafe {
            CStr::from_ptr((*self.output).model.as_ptr())
                .to_string_lossy()
                .into_owned()
        }
    }

    pub fn make_current(&self) {
        unsafe { wlr_output_make_current(self.output) }
    }

    pub fn swap_buffers(&self) {
        unsafe { wlr_output_swap_buffers(self.output) }
    }

    /// Get the dimensions of the output as (width, height).
    pub fn dimensions(&self) -> (i32, i32) {
        unsafe { ((*self.output).width, (*self.output).height) }
    }

    /// Get the physical dimensions of the output as (width, height).
    pub fn physical_dimensions(&self) -> (i32, i32) {
        unsafe { ((*self.output).phys_width, (*self.output).phys_height) }
    }

    // TODO Wrap this somehow? Hmm
    pub unsafe fn modes(&self) -> *mut list_t {
        (*self.output).modes
    }

    // FIXME Really need to change the name of this type
    pub unsafe fn events(&self) -> wlr_output__bindgen_ty_1 {
        (*self.output).events
    }

    pub unsafe fn from_ptr(output: *mut wlr_output) -> Self {
        Output { output }
    }

    pub unsafe fn to_ptr(&self) -> *mut wlr_output {
        self.output
    }
}

impl OutputLayout {
    pub fn new() -> Self {
        unsafe { OutputLayout { layout: wlr_output_layout_create() } }
    }

    pub fn add_auto(&mut self, output: &mut Output) {
        unsafe { wlr_output_layout_add_auto(self.layout, output.to_ptr()) }
    }

    pub unsafe fn as_ptr(&self) -> *mut wlr_output_layout {
        self.layout
    }
}

impl Drop for OutputLayout {
    fn drop(&mut self) {
        unsafe { wlr_output_layout_destroy(self.layout) }
    }
}
<commit_msg>Output buffer functions made &mut<commit_after>use cursor::XCursorImage;
use std::ffi::CStr;
use wlroots_sys::{list_t, wlr_output, wlr_output__bindgen_ty_1, wlr_output_layout,
                  wlr_output_layout_add_auto, wlr_output_layout_create, wlr_output_layout_destroy,
                  wlr_output_make_current, wlr_output_set_cursor, wlr_output_swap_buffers};

/// A wrapper around a wlr_output.
#[derive(Debug)]
pub struct Output {
    output: *mut wlr_output
}

// TODO Call it Layout, use as output::Layout?
#[derive(Debug)]
pub struct OutputLayout {
    layout: *mut wlr_output_layout
}

// TODO We are assuming the output is live in these functions,
// but we need some way to ensure that.
// E.g we need to control access to the "Output",
// probably only in certain methods.

impl Output {
    pub fn set_cursor<'cursor>(&mut self, image: &'cursor XCursorImage<'cursor>) -> Result<(), ()> {
        unsafe {
            match wlr_output_set_cursor(self.output,
                                        image.buffer.as_ptr(),
                                        image.width as i32,
                                        image.width,
                                        image.height,
                                        image.hotspot_x as i32,
                                        image.hotspot_y as i32) {
                true => Ok(()),
                false => Err(()),
            }
        }
    }

    /// Gets the name of the output in UTF-8.
    pub fn name(&self) -> String {
        unsafe {
            CStr::from_ptr((*self.output).name.as_ptr())
                .to_string_lossy()
                .into_owned()
        }
    }

    /// Gets the make of the output in UTF-8.
    pub fn make(&self) -> String {
        unsafe {
            CStr::from_ptr((*self.output).make.as_ptr())
                .to_string_lossy()
                .into_owned()
        }
    }

    /// Gets the model of the output in UTF-8.
    pub fn model(&self) -> String {
        unsafe {
            CStr::from_ptr((*self.output).model.as_ptr())
                .to_string_lossy()
                .into_owned()
        }
    }

    pub fn make_current(&mut self) {
        unsafe { wlr_output_make_current(self.output) }
    }

    pub fn swap_buffers(&mut self) {
        unsafe { wlr_output_swap_buffers(self.output) }
    }

    /// Get the dimensions of the output as (width, height).
    pub fn dimensions(&self) -> (i32, i32) {
        unsafe { ((*self.output).width, (*self.output).height) }
    }

    /// Get the physical dimensions of the output as (width, height).
    pub fn physical_dimensions(&self) -> (i32, i32) {
        unsafe { ((*self.output).phys_width, (*self.output).phys_height) }
    }

    // TODO Wrap this somehow? Hmm
    pub unsafe fn modes(&self) -> *mut list_t {
        (*self.output).modes
    }

    // FIXME Really need to change the name of this type
    pub unsafe fn events(&self) -> wlr_output__bindgen_ty_1 {
        (*self.output).events
    }

    pub unsafe fn from_ptr(output: *mut wlr_output) -> Self {
        Output { output }
    }

    pub unsafe fn to_ptr(&self) -> *mut wlr_output {
        self.output
    }
}

impl OutputLayout {
    pub fn new() -> Self {
        unsafe { OutputLayout { layout: wlr_output_layout_create() } }
    }

    pub fn add_auto(&mut self, output: &mut Output) {
        unsafe { wlr_output_layout_add_auto(self.layout, output.to_ptr()) }
    }

    pub unsafe fn as_ptr(&self) -> *mut wlr_output_layout {
        self.layout
    }
}

impl Drop for OutputLayout {
    fn drop(&mut self) {
        unsafe { wlr_output_layout_destroy(self.layout) }
    }
}
<|endoftext|>


<commit_before>use machine;

const PAGE_TABLE_ENTRIES: usize = 1024;
const PAGE_TABLE_SIZE: usize = 4096;

type PageTable = [u32; PAGE_TABLE_ENTRIES];

// Overallocate. We'll loop through it to get a page-aligned piece of memory
static mut initial_table_area: [u32; PAGE_TABLE_ENTRIES * 3] = [0; PAGE_TABLE_ENTRIES * 3];

static mut next_frame: u32 = 0x100;

fn page_table_for(vaddr: u32) -> *mut PageTable {
    let pd_index = vaddr >> 22;

    unsafe {
        // PD[1023] -> pd_addr. pd_addr[1023] -> pd_addr
        let pd = 0xFFFFF_000 as *mut PageTable;
        if (*pd)[pd_index as usize] & 1 == 0 {
            (*pd)[pd_index as usize] = (next_frame << 12) | 0b11;
            next_frame += 1;
        }
        (0xFFC00_000 + 0x1_000 * pd_index) as *mut PageTable
    }
}

pub fn make_present(addr: u32) {
    let page_number = (addr >> 12) & 0x3ff;
    unsafe {
        let pt = page_table_for(addr);
        (*pt)[page_number as usize] = next_frame << 12 | 0b11;
        next_frame += 1;
    }
}

pub fn init() {
    unsafe {
        let unalligned_pd_addr = &initial_table_area[0] as *const u32 as usize;
        let alligned_pd_addr = unalligned_pd_addr +
            (PAGE_TABLE_SIZE -
             (unalligned_pd_addr % PAGE_TABLE_SIZE));
        let pd = alligned_pd_addr as *mut PageTable;

        let first_pt: *mut PageTable = pd.offset(1);
        (*pd)[0] = (first_pt as u32) | 0b11; // Read-write, present

        for frame_num in 0..next_frame {
            (*first_pt)[frame_num as usize] = (frame_num << 12) | 0b11;
        }

        (*pd)[1023] = (alligned_pd_addr as u32) | 0b11; // The "recursive paging trick"
        machine::enable_paging(alligned_pd_addr as *const u32);
    }
}
<commit_msg>Slightly more type-safe paging<commit_after>use machine;

const PAGE_TABLE_ENTRIES: usize = 1024;
const PAGE_TABLE_SIZE: usize = 4096;

type PageTable = [u32; PAGE_TABLE_ENTRIES];

// Overallocate. We'll loop through it to get a page-aligned piece of memory
static mut initial_table_area: [u32; PAGE_TABLE_ENTRIES * 3] = [0; PAGE_TABLE_ENTRIES * 3];

static mut next_frame: u32 = 0x100;

fn page_table_for(vaddr: u32) -> &'static mut PageTable {
    let pd_index = vaddr >> 22;

    unsafe {
        // PD[1023] -> pd_addr. pd_addr[1023] -> pd_addr
        let pd = 0xFFFFF_000 as *mut PageTable;
        if (*pd)[pd_index as usize] & 1 == 0 {
            (*pd)[pd_index as usize] = (next_frame << 12) | 0b11;
            next_frame += 1;
        }
        &mut *((0xFFC00_000 + 0x1_000 * pd_index) as *mut PageTable)
    }
}

pub fn make_present(addr: u32) {
    let page_number = (addr >> 12) & 0x3ff;
    unsafe {
        let pt = page_table_for(addr);
        pt[page_number as usize] = next_frame << 12 | 0b11;
        next_frame += 1;
    }
}

pub fn init() {
    unsafe {
        let unalligned_pd_addr = &initial_table_area[0] as *const u32 as usize;
        let alligned_pd_addr = unalligned_pd_addr +
            (PAGE_TABLE_SIZE -
             (unalligned_pd_addr % PAGE_TABLE_SIZE));
        let pd = alligned_pd_addr as *mut PageTable;

        let first_pt: *mut PageTable = pd.offset(1);
        (*pd)[0] = (first_pt as u32) | 0b11; // Read-write, present

        for frame_num in 0..next_frame {
            (*first_pt)[frame_num as usize] = (frame_num << 12) | 0b11;
        }

        (*pd)[1023] = (alligned_pd_addr as u32) | 0b11; // The "recursive paging trick"
        machine::enable_paging(alligned_pd_addr as *const u32);
    }
}
<|endoftext|>


<commit_before>
use std::str;

#[derive(Debug)]
pub enum Message {
    Settings(SettingsValue),
    SetupMap{name: &'static str, value: Vec<u64>},
    PickStartingRegion{time_left: u64, ids: Vec<u64>},
    UpdateMap,
    GoPlaceArmies,
    GoAttackTranser,
}

#[derive(Debug)]
pub enum SettingsValue {
    Timebank(u64),
    TimePerMove(u64),
    MaxRounds(u64),
    YourBot(&'static str),
    OpponentBot(&'static str),
    StartingRegions(Vec<u64>),
    StartingPickAmount(u64),
    StartingArmies(u64)
}

pub fn parse(line: &'static str) -> Result<Message, String> {
    let mut words = line.split(' ');
    match words.next().unwrap() {
        "settings" => parse_settings(words),
        "update_map" => {
            Ok(Message::UpdateMap)
        }
        _ => Err("unknown command".to_string())
    }
}

fn parse_settings(mut parts: str::Split<char>) -> Result<Message, String> {
    let command = try!(parts.next().ok_or("no command given to setting"));

    match command {
        "timebank" => {
            let raw_value = try!(parts.next().ok_or("got timebank setting with no value"));
            let value = try!(u64::from_str_radix(raw_value, 10).map_err(|e| e.to_string()));
            Ok(Message::Settings(SettingsValue::Timebank(value)))
        }
        "starting_regions" => {
            let mut peeker = parts.peekable();
            try!(peeker.peek().ok_or("got starting_regions setting with no value"));
            let mut value = Vec::new();
            for word in peeker {
                value.push(try!(u64::from_str_radix(word, 10).map_err(|e| e.to_string())));
            }
            Ok(Message::Settings(SettingsValue::StartingRegions(value)))
        }
        _ => Err("unknown setting".to_string())
    }
}

#[test]
fn blank() {
    match parse("") {
        Ok(_) => panic!("should return error because it is malformed"),
        Err(e) => assert_eq!(e, "unknown command".to_string())
    }
}

#[test]
fn setting_blank() {
    match parse("settings") {
        Ok(_) => panic!("should return error because it is malformed"),
        Err(e) => assert_eq!(e, "no command given to setting".to_string())
    }
}

#[test]
fn setting_timebank_blank() {
    match parse("settings timebank") {
        Ok(_) => panic!("got a setting back when expecting an error"),
        Err(e) => assert_eq!(e, "got timebank setting with no value".to_string())
    }
}

#[test]
fn setting_timebank_bad_value() {
    match parse("settings timebank five") {
        Ok(_) => panic!("got a setting back when expecting an error"),
        Err(e) => assert_eq!(e, "invalid digit found in string".to_string())
    }
}

#[test]
fn setting_timebank_proper() {
    match parse("settings timebank 10000").unwrap() {
        Message::Settings(setting) => match setting {
            SettingsValue::Timebank(value) => assert_eq!(value, 10000),
            _ => panic!("got a setting that wasn't a timebank")
        },
        _ => panic!("didn't get a settings object")
    }
}

#[test]
fn setting_starting_regions_blank() {
    match parse("settings starting_regions") {
        Ok(_) => panic!("got a setting back when expecting an error"),
        Err(e) => assert_eq!(e, "got starting_regions setting with no value".to_string())
    }
}

#[test]
fn setting_starting_regions_bad_value() {
    match parse("settings starting_regions five 50") {
        Ok(a) => panic!("got a setting back when expecting an error, {:?}", a),
        Err(e) => assert_eq!(e, "invalid digit found in string".to_string())
    }
}

#[test]
fn setting_starting_regions_proper() {
    match parse("settings starting_regions 4 7 11").unwrap() {
        Message::Settings(setting) => match setting {
            SettingsValue::StartingRegions(value) => assert_eq!(value, vec![4, 7, 11]),
            _ => panic!("got a setting that wasn't a starting_regions")
        },
        _ => panic!("didn't get a settings object")
    }
}
<commit_msg>flesh out all settings<commit_after>use std::str;

#[derive(Debug)]
pub enum Message {
    Settings(SettingsValue),
    SetupMap{name: &'static str, value: Vec<u64>},
    PickStartingRegion{time_left: u64, ids: Vec<u64>},
    UpdateMap,
    GoPlaceArmies,
    GoAttackTranser,
}

#[derive(Debug)]
pub enum SettingsValue {
    Timebank(u64),
    TimePerMove(u64),
    MaxRounds(u64),
    YourBot(String),
    OpponentBot(String),
    StartingRegions(Vec<u64>),
    StartingPickAmount(u64),
    StartingArmies(u64)
}

pub fn parse(line: &'static str) -> Result<Message, String> {
    let mut words = line.split(' ');
    match words.next().unwrap() {
        "settings" => parse_settings(words),
        "update_map" => {
            Ok(Message::UpdateMap)
        }
        _ => Err("unknown command".to_string())
    }
}

fn parse_settings(mut parts: str::Split<char>) -> Result<Message, String> {
    let command = try!(parts.next().ok_or("no command given to setting"));

    match command {
        "timebank" => Ok(Message::Settings(SettingsValue::Timebank(try!(parts_to_u64(parts, command.to_owned()))))),
        "time_per_move" => Ok(Message::Settings(SettingsValue::TimePerMove(try!(parts_to_u64(parts, command.to_owned()))))),
        "max_rounds" => Ok(Message::Settings(SettingsValue::MaxRounds(try!(parts_to_u64(parts, command.to_owned()))))),
        "starting_pick_amount" => Ok(Message::Settings(SettingsValue::StartingPickAmount(try!(parts_to_u64(parts, command.to_owned()))))),
        "starting_armies" => Ok(Message::Settings(SettingsValue::StartingArmies(try!(parts_to_u64(parts, command.to_owned()))))),
        "starting_regions" => {
            let mut peeker = parts.peekable();
            try!(peeker.peek().ok_or("got starting_regions setting with no value"));
            let mut value = Vec::new();
            for word in peeker {
                value.push(try!(u64::from_str_radix(word, 10).map_err(|e| e.to_string())));
            }
            Ok(Message::Settings(SettingsValue::StartingRegions(value)))
        }
        "your_bot" => {
            let raw_value = try!(parts.next().ok_or("got your_bot setting with no value"));
            Ok(Message::Settings(SettingsValue::YourBot(raw_value.to_owned())))
        }
        "opponent_bot" => {
            let raw_value = try!(parts.next().ok_or("got opponent_bot setting with no value"));
            Ok(Message::Settings(SettingsValue::OpponentBot(raw_value.to_owned())))
        }
        _ => Err(format!("unknown setting {}", command).to_string())
    }
}

fn parts_to_u64(mut parts: str::Split<char>, command: String) -> Result<u64, String> {
    let raw_value = try!(parts.next().ok_or(format!("got {} setting with no value", command)));
    Ok(try!(u64::from_str_radix(raw_value, 10).map_err(|e| e.to_string())))
}

#[test]
fn blank() {
    match parse("") {
        Ok(_) => panic!("should return error because it is malformed"),
        Err(e) => assert_eq!(e, "unknown command".to_string())
    }
}

#[test]
fn setting_blank() {
    match parse("settings") {
        Ok(_) => panic!("should return error because it is malformed"),
        Err(e) => assert_eq!(e, "no command given to setting".to_string())
    }
}

#[test]
fn setting_timebank_blank() {
    match parse("settings timebank") {
        Ok(_) => panic!("got a setting back when expecting an error"),
        Err(e) => assert_eq!(e, "got timebank setting with no value".to_string())
    }
}

#[test]
fn setting_timebank_bad_value() {
    match parse("settings timebank five") {
        Ok(_) => panic!("got a setting back when expecting an error"),
        Err(e) => assert_eq!(e, "invalid digit found in string".to_string())
    }
}

#[test]
fn setting_timebank_proper() {
    match parse("settings timebank 10000").unwrap() {
        Message::Settings(setting) => match setting {
            SettingsValue::Timebank(value) => assert_eq!(value, 10000),
            _ => panic!("got a setting that wasn't a timebank")
        },
        _ => panic!("didn't get a settings object")
    }
}

#[test]
fn setting_time_per_move_blank() {
    match parse("settings time_per_move") {
        Ok(_) => panic!("got a setting back when expecting an error"),
        Err(e) => assert_eq!(e, "got time_per_move setting with no value".to_string())
    }
}

#[test]
fn setting_time_per_move_bad_value() {
    match parse("settings time_per_move five") {
        Ok(_) => panic!("got a setting back when expecting an error"),
        Err(e) => assert_eq!(e, "invalid digit found in string".to_string())
    }
}

#[test]
fn setting_time_per_move_proper() {
    match parse("settings time_per_move 10000").unwrap() {
        Message::Settings(setting) => match setting {
            SettingsValue::TimePerMove(value) => assert_eq!(value, 10000),
            _ => panic!("got a setting that wasn't a time_per_move")
        },
        _ => panic!("didn't get a settings object")
    }
}

#[test]
fn setting_max_rounds_blank() {
    match parse("settings max_rounds") {
        Ok(_) => panic!("got a setting back when expecting an error"),
        Err(e) => assert_eq!(e, "got max_rounds setting with no value".to_string())
    }
}

#[test]
fn setting_max_rounds_bad_value() {
    match parse("settings max_rounds five") {
        Ok(_) => panic!("got a setting back when expecting an error"),
        Err(e) => assert_eq!(e, "invalid digit found in string".to_string())
    }
}

#[test]
fn setting_max_rounds_proper() {
    match parse("settings max_rounds 10000").unwrap() {
        Message::Settings(setting) => match setting {
            SettingsValue::MaxRounds(value) => assert_eq!(value, 10000),
            _ => panic!("got a setting that wasn't a max_rounds")
        },
        _ => panic!("didn't get a settings object")
    }
}

#[test]
fn setting_starting_pick_amount_blank() {
    match parse("settings starting_pick_amount") {
        Ok(_) => panic!("got a setting back when expecting an error"),
        Err(e) => assert_eq!(e, "got starting_pick_amount setting with no value".to_string())
    }
}

#[test]
fn setting_starting_pick_amount_bad_value() {
    match parse("settings starting_pick_amount five") {
        Ok(_) => panic!("got a setting back when expecting an error"),
        Err(e) => assert_eq!(e, "invalid digit found in string".to_string())
    }
}

#[test]
fn setting_starting_pick_amount_proper() {
    match parse("settings starting_pick_amount 10000").unwrap() {
        Message::Settings(setting) => match setting {
            SettingsValue::StartingPickAmount(value) => assert_eq!(value, 10000),
            _ => panic!("got a setting that wasn't a starting_pick_amount")
        },
        _ => panic!("didn't get a settings object")
    }
}

#[test]
fn setting_starting_armies_blank() {
    match parse("settings starting_armies") {
        Ok(_) => panic!("got a setting back when expecting an error"),
        Err(e) => assert_eq!(e, "got starting_armies setting with no value".to_string())
    }
}

#[test]
fn setting_starting_armies_bad_value() {
    match parse("settings starting_armies five") {
        Ok(_) => panic!("got a setting back when expecting an error"),
        Err(e) => assert_eq!(e, "invalid digit found in string".to_string())
    }
}

#[test]
fn setting_starting_armies_proper() {
    match parse("settings starting_armies 10000").unwrap() {
        Message::Settings(setting) => match setting {
            SettingsValue::StartingArmies(value) => assert_eq!(value, 10000),
            _ => panic!("got a setting that wasn't a starting_armies")
        },
        _ => panic!("didn't get a settings object")
    }
}

#[test]
fn setting_starting_regions_blank() {
    match parse("settings starting_regions") {
        Ok(_) => panic!("got a setting back when expecting an error"),
        Err(e) => assert_eq!(e, "got starting_regions setting with no value".to_string())
    }
}

#[test]
fn setting_starting_regions_bad_value() {
    match parse("settings starting_regions five 50") {
        Ok(a) => panic!("got a setting back when expecting an error, {:?}", a),
        Err(e) => assert_eq!(e, "invalid digit found in string".to_string())
    }
}

#[test]
fn setting_starting_regions_proper() {
    match parse("settings starting_regions 4 7 11").unwrap() {
        Message::Settings(setting) => match setting {
            SettingsValue::StartingRegions(value) => assert_eq!(value, vec![4, 7, 11]),
            _ => panic!("got a setting that wasn't a starting_regions")
        },
        _ => panic!("didn't get a settings object")
    }
}

#[test]
fn setting_your_bot_blank() {
    match parse("settings your_bot") {
        Ok(a) => panic!("got a setting back when expecting an error, {:?}", a),
        Err(e) => assert_eq!(e, "got your_bot setting with no value".to_string())
    }
}

#[test]
fn setting_your_bot_proper() {
    match parse("settings your_bot fig").unwrap() {
        Message::Settings(setting) => match setting {
            SettingsValue::YourBot(value) => assert_eq!(value, "fig".to_string()),
            _ => panic!("got a setting that wasn't a your_bot")
        },
        _ => panic!("didn't get a settings object")
    }
}

#[test]
fn setting_opponent_bot_blank() {
    match parse("settings opponent_bot") {
        Ok(a) => panic!("got a setting back when expecting an error, {:?}", a),
        Err(e) => assert_eq!(e, "got opponent_bot setting with no value".to_string())
    }
}

#[test]
fn setting_opponent_bot_proper() {
    match parse("settings opponent_bot fig").unwrap() {
        Message::Settings(setting) => match setting {
            SettingsValue::OpponentBot(value) => assert_eq!(value, "fig".to_string()),
            _ => panic!("got a setting that wasn't a opponent_bot")
        },
        _ => panic!("didn't get a settings object")
    }
}
<|endoftext|>


<commit_before>use token::{Token, TokenType};
use ast::*;
use pos::Pos;
use error::{Result, Error};
use types::Type;

pub struct Parser {
    tokens: Vec<Token>,
    index: usize,
}

impl Parser {
    pub fn new(tokens: Vec<Token>) -> Self {
        Parser {
            tokens: tokens,
            index: 0,
        }
    }

    fn peek(&self, t: TokenType) -> bool {
        let token = &self.tokens[self.index];
        token.typ == t
    }

    fn curr_token(&self) -> Token {
        self.tokens[self.index].clone()
    }

    fn token_pos(&self) -> Pos {
        self.tokens[self.index].pos
    }

    fn eat(&mut self, t: TokenType) -> Result<()> {
        let b = self.peek(t);
        if b {
            self.index += 1;
            Ok(())
        } else {
            Err(Error::UnexpectedToken(self.curr_token(), vec![t]))
        }
    }

    fn eat_lexeme(&mut self, t: TokenType) -> Result<String> {
        let token = &self.tokens[self.index];
        if token.typ == t {
            match token.lexeme {
                Some(ref lexeme) => {
                    self.index += 1;
                    Ok(lexeme.clone())
                }
                None => Err(Error::UnexpectedToken(self.curr_token(), vec![t]))
            }
        } else {
            Err(Error::UnexpectedToken(self.curr_token(), vec![t]))
        }
    }

    fn eat_type(&mut self) -> Result<Type> {
        if self.peek(TokenType::TypeInt) {
            self.index += 1;
            Ok(Type::Int)
        } else if self.peek(TokenType::TypeFloat) {
            self.index += 1;
            Ok(Type::Float)
        } else if self.peek(TokenType::TypeVoid) {
            self.index += 1;
            Ok(Type::Void)
        } else {
            Err(Error::UnexpectedToken(self.curr_token(), vec![TokenType::TypeInt, TokenType::TypeFloat]))
        }
    }

    /*
     * program = { decl } .
     */
    pub fn parse_program(&mut self) -> Result<Program> {
        let decls = try!(self.parse_decls());
        try!(self.eat(TokenType::Eof));

        Ok(Program {
            decls: decls,
        })
    }

    fn parse_decls(&mut self) -> Result<Vec<Decl>> {
        let mut decls: Vec<Decl> = Vec::new();
        while self.peek(TokenType::Var) || self.peek(TokenType::Function) {
            let decl = try!(self.parse_decl());
            decls.push(decl);
        }
        Ok(decls)
    }

    /*
     * decl = var_decl
     *      | fun_decl
     */
    fn parse_decl(&mut self) -> Result<Decl> {
        if self.peek(TokenType::Var) {
            let vd = try!(self.parse_var_decl());
            Ok(Decl::Var(vd))
        } else if self.peek(TokenType::Function) {
            let fd = try!(self.parse_func_decl());
            Ok(Decl::Fun(fd))
        } else {
            Err(Error::UnexpectedToken(
                self.curr_token(),
                vec![TokenType::Var, TokenType::Function]))
        }
    }

    fn parse_var_decls(&mut self) -> Result<Vec<VarDecl>> {
        let mut vds = Vec::new();
        while self.peek(TokenType::Var) {
            let vd = try!(self.parse_var_decl());
            vds.push(vd);
        }
        Ok(vds)
    }

    /*
     * var_decl = "var" id ":" type ";"
     */
    fn parse_var_decl(&mut self) -> Result<VarDecl> {
        let pos = self.token_pos();
        try!(self.eat(TokenType::Var));
        let id = try!(self.eat_lexeme(TokenType::Id));
        try!(self.eat(TokenType::Colon));
        let ty = try!(self.eat_type());
        try!(self.eat(TokenType::Semicolon));
        Ok(VarDecl { pos: pos, id: id, ty: ty })
    }

    /*
     * fun_decl   = "function" id "(" param_list ")" ":" type { stmt } "end"
     */
    fn parse_func_decl(&mut self) -> Result<FunDecl> {
        let pos = self.token_pos();
        try!(self.eat(TokenType::Function));
        let id = try!(self.eat_lexeme(TokenType::Id));
        try!(self.eat(TokenType::LParen));
        let params = try!(self.parse_params());
        try!(self.eat(TokenType::RParen));
        try!(self.eat(TokenType::Colon));
        let ty = try!(self.eat_type());
        let decls = try!(self.parse_var_decls());
        let stmts = try!(self.parse_stmts());
        try!(self.eat(TokenType::End));

        Ok(FunDecl {
            pos: pos,
            id: id,
            params: params,
            ty: ty,
            decls: decls,
            stmts: stmts,
        })
    }

    /*
     * params = ε
     *        | id ":" type
     *        | id ":" type "," params
     */
    fn parse_params(&mut self) -> Result<Vec<(String, Type)>> {
        let mut params = Vec::new();
        while self.peek(TokenType::Id) {
            let id = try!(self.eat_lexeme(TokenType::Id));
            try!(self.eat(TokenType::Colon));
            let ty = try!(self.eat_type());
            params.push((id, ty));

            if self.peek(TokenType::Comma) {
                try!(self.eat(TokenType::Comma));
            } else {
                break;
            }
        }
        Ok(params)
    }

    fn parse_stmts(&mut self) -> Result<Vec<Stmt>> {
        let mut stmts: Vec<Stmt> = Vec::new();
        while self.is_stmt_start() {
            let stmt = try!(self.parse_stmt());
            stmts.push(stmt);
        }
        Ok(stmts)
    }

    /*
     * stmt = read_stmt
     *      | print_stmt
     *      | assign_stmt
     *      | if_stmt
     *      | while_stmt
     *      | return_stmt
     */
    fn parse_stmt(&mut self) -> Result<Stmt> {
        if self.peek(TokenType::Read) {
            self.parse_read()
        } else if self.peek(TokenType::Print) {
            self.parse_print()
        } else if self.peek(TokenType::Id) {
            self.parse_assign()
        } else if self.peek(TokenType::If) {
            self.parse_if()
        } else if self.peek(TokenType::While) {
            self.parse_while()
        } else if self.peek(TokenType::Return) {
            self.parse_return()
        } else {
            Err(Error::UnexpectedToken(
                self.curr_token(),
                vec![TokenType::Read, TokenType::Print,
                     TokenType::Id, TokenType::If, TokenType::While]))
        }
    }

    /*
     * read_stmt = "read" id ";"
     */
    fn parse_read(&mut self) -> Result<Stmt> {
        let pos = self.token_pos();
        try!(self.eat(TokenType::Read));
        let id = try!(self.eat_lexeme(TokenType::Id));
        try!(self.eat(TokenType::Semicolon));
        Ok(Stmt::Read(StmtRead { pos: pos, id: id }))
    }

    /*
     * print_stmt = "print" expr ";"
     */
    fn parse_print(&mut self) -> Result<Stmt> {
        let pos = self.token_pos();
        try!(self.eat(TokenType::Print));
        let e = try!(self.parse_expr());
        try!(self.eat(TokenType::Semicolon));
        Ok(Stmt::Print(StmtPrint { pos: pos, expr: e }))
    }

    /*
     * assign_stmt = id "=" expr ";"
     */
    fn parse_assign(&mut self) -> Result<Stmt> {
        let pos = self.token_pos();
        let id = try!(self.eat_lexeme(TokenType::Id));
        try!(self.eat(TokenType::Equal));
        let e = try!(self.parse_expr());
        try!(self.eat(TokenType::Semicolon));
        Ok(Stmt::Assign(StmtAssign { pos: pos, id: id, expr: e }))
    }

    /*
     * if_stmt = "if" expr "then" { stmt } [ "else" { stmt } ] "end"
     */
    fn parse_if(&mut self) -> Result<Stmt> {
        let pos = self.token_pos();
        try!(self.eat(TokenType::If));
        let e = try!(self.parse_expr());
        try!(self.eat(TokenType::Then));
        let then_stmts = try!(self.parse_stmts());
        try!(self.eat(TokenType::Else));
        let else_stmts = try!(self.parse_stmts());
        try!(self.eat(TokenType::End));
        Ok(Stmt::If(StmtIf {
            pos: pos,
            expr: e,
            then_stmts: then_stmts,
            else_stmts: else_stmts,
        }))
    }

    /*
     * while_stmt = "while" expr "do" { stmt } "done"
     */
    fn parse_while(&mut self) -> Result<Stmt> {
        let pos = self.token_pos();
        try!(self.eat(TokenType::While));
        let e = try!(self.parse_expr());
        try!(self.eat(TokenType::Do));
        let stmts = try!(self.parse_stmts());
        try!(self.eat(TokenType::Done));
        Ok(Stmt::While(StmtWhile {
            pos: pos,
            expr: e,
            stmts: stmts,
        }))
    }

    /*
     * return_stmt = "return" [ expr ] ";"
     */
    fn parse_return(&mut self) -> Result<Stmt> {
        let pos = self.token_pos();
        try!(self.eat(TokenType::Return));

        let expr =
            if self.peek(TokenType::Semicolon) {
                None
            } else {
                Some(try!(self.parse_expr()))
            };
        try!(self.eat(TokenType::Semicolon));

        Ok(Stmt::Return(StmtReturn {
            pos: pos,
            expr: expr,
        }))
    }

    /*
     * expr = expr "+" term
     *      | expr "-" term
     *      | term
     */
    fn parse_expr(&mut self) -> Result<Expr> {
        let pos = self.token_pos();
        let mut term = try!(self.parse_term());
        while self.next_is_add() {
            if self.peek(TokenType::Plus) {
                try!(self.eat(TokenType::Plus));
                let t2 = try!(self.parse_term());
                term = Expr::Binop(ExprBinop {
                    pos: pos,
                    op: Binop::Add,
                    expr1: Box::new(term),
                    expr2: Box::new(t2)
                });
            } else if self.peek(TokenType::Minus) {
                try!(self.eat(TokenType::Minus));
                let t2 = try!(self.parse_term());
                term = Expr::Binop(ExprBinop {
                    pos: pos,
                    op: Binop::Sub,
                    expr1: Box::new(term),
                    expr2: Box::new(t2)
                });
            } else {
                return Err(Error::UnexpectedToken(
                    self.curr_token(),
                    vec![TokenType::Plus, TokenType::Minus]));
            }
        }
        Ok(term)
    }

    /*
     * term = term "+" factor
     *      | term "-" factor
     *      | factor
     */
    fn parse_term(&mut self) -> Result<Expr> {
        let pos = self.token_pos();
        let mut fact = try!(self.parse_factor());
        while self.next_is_mul() {
            if self.peek(TokenType::Star) {
                try!(self.eat(TokenType::Star));
                let f2 = try!(self.parse_factor());
                fact = Expr::Binop(ExprBinop {
                    pos: pos,
                    op: Binop::Mul,
                    expr1: Box::new(fact),
                    expr2: Box::new(f2),
                });
            } else if self.peek(TokenType::Slash) {
                try!(self.eat(TokenType::Slash));
                let f2 = try!(self.parse_factor());
                fact = Expr::Binop(ExprBinop {
                    pos: pos,
                    op: Binop::Div,
                    expr1: Box::new(fact),
                    expr2: Box::new(f2),
                });
            } else {
                return Err(Error::UnexpectedToken(
                    self.curr_token(),
                    vec![TokenType::Star, TokenType::Slash]));
            }
        }
        Ok(fact)
    }

    /*
     * factor = id
     *        | int_literal
     *        | float_literal
     *        | "(" expr ")"
     *        | "-" expr
     */
    fn parse_factor(&mut self) -> Result<Expr> {
        let pos = self.token_pos();
        if self.peek(TokenType::Int) {
            self.parse_int()
        } else if self.peek(TokenType::Float) {
            self.parse_float()
        } else if self.peek(TokenType::Id) {
            self.parse_id()
        } else if self.peek(TokenType::LParen) {
            try!(self.eat(TokenType::LParen));
            let e = try!(self.parse_expr());
            try!(self.eat(TokenType::RParen));
            Ok(e)
        } else if self.peek(TokenType::Minus) {
            try!(self.eat(TokenType::Minus));
            let e = try!(self.parse_expr());
            Ok(Expr::Negate(ExprNegate { pos: pos, expr: Box::new(e) }))
        } else {
            Err(Error::UnexpectedToken(
                self.curr_token(),
                vec![TokenType::Int, TokenType::Float, TokenType::Id,
                     TokenType::Minus, TokenType::LParen]))
        }
    }

    fn parse_int(&mut self) -> Result<Expr> {
        let pos = self.token_pos();
        let lexeme = try!(self.eat_lexeme(TokenType::Int));
        match lexeme.parse::<i64>() {
            Ok(n) => Ok(Expr::Int (ExprInt { pos: pos, value: n })),
            Err(_) => Err(Error::InvalidIntLiteral(pos, lexeme))
        }
    }

    fn parse_float(&mut self) -> Result<Expr> {
        let pos = self.token_pos();
        let lexeme = try!(self.eat_lexeme(TokenType::Float));
        match lexeme.parse::<f64>() {
            Ok(n) => Ok(Expr::Float(ExprFloat { pos: pos, value: Float(n) })),
            Err(_) => Err(Error::InvalidFloatLiteral(pos, lexeme))
        }
    }

    fn parse_id(&mut self) -> Result<Expr> {
        let pos = self.token_pos();
        let lexeme = try!(self.eat_lexeme(TokenType::Id));
        Ok(Expr::Id(ExprId { pos: pos, id: lexeme }))
    }

    fn is_stmt_start(&self) -> bool {
        self.peek(TokenType::Id) ||
            self.peek(TokenType::If) ||
            self.peek(TokenType::While) ||
            self.peek(TokenType::Read) ||
            self.peek(TokenType::Print) ||
            self.peek(TokenType::Return)
    }

    fn next_is_add(&self) -> bool {
        self.peek(TokenType::Plus) || self.peek(TokenType::Minus)
    }

    fn next_is_mul(&self) -> bool {
        self.peek(TokenType::Star) || self.peek(TokenType::Slash)
    }
}
<commit_msg>Better variable names.<commit_after>use token::{Token, TokenType};
use ast::*;
use pos::Pos;
use error::{Result, Error};
use types::Type;

pub struct Parser {
    tokens: Vec<Token>,
    index: usize,
}

impl Parser {
    pub fn new(tokens: Vec<Token>) -> Self {
        Parser {
            tokens: tokens,
            index: 0,
        }
    }

    fn peek(&self, t: TokenType) -> bool {
        let token = &self.tokens[self.index];
        token.typ == t
    }

    fn curr_token(&self) -> Token {
        self.tokens[self.index].clone()
    }

    fn token_pos(&self) -> Pos {
        self.tokens[self.index].pos
    }

    fn eat(&mut self, t: TokenType) -> Result<()> {
        let b = self.peek(t);
        if b {
            self.index += 1;
            Ok(())
        } else {
            Err(Error::UnexpectedToken(self.curr_token(), vec![t]))
        }
    }

    fn eat_lexeme(&mut self, t: TokenType) -> Result<String> {
        let token = &self.tokens[self.index];
        if token.typ == t {
            match token.lexeme {
                Some(ref lexeme) => {
                    self.index += 1;
                    Ok(lexeme.clone())
                }
                None => Err(Error::UnexpectedToken(self.curr_token(), vec![t]))
            }
        } else {
            Err(Error::UnexpectedToken(self.curr_token(), vec![t]))
        }
    }

    fn eat_type(&mut self) -> Result<Type> {
        if self.peek(TokenType::TypeInt) {
            self.index += 1;
            Ok(Type::Int)
        } else if self.peek(TokenType::TypeFloat) {
            self.index += 1;
            Ok(Type::Float)
        } else if self.peek(TokenType::TypeVoid) {
            self.index += 1;
            Ok(Type::Void)
        } else {
            Err(Error::UnexpectedToken(self.curr_token(), vec![TokenType::TypeInt, TokenType::TypeFloat]))
        }
    }

    /*
     * program = { decl } .
     */
    pub fn parse_program(&mut self) -> Result<Program> {
        let decls = try!(self.parse_decls());
        try!(self.eat(TokenType::Eof));

        Ok(Program {
            decls: decls,
        })
    }

    fn parse_decls(&mut self) -> Result<Vec<Decl>> {
        let mut decls: Vec<Decl> = Vec::new();
        while self.peek(TokenType::Var) || self.peek(TokenType::Function) {
            let decl = try!(self.parse_decl());
            decls.push(decl);
        }
        Ok(decls)
    }

    /*
     * decl = var_decl
     *      | fun_decl
     */
    fn parse_decl(&mut self) -> Result<Decl> {
        if self.peek(TokenType::Var) {
            let vd = try!(self.parse_var_decl());
            Ok(Decl::Var(vd))
        } else if self.peek(TokenType::Function) {
            let fd = try!(self.parse_func_decl());
            Ok(Decl::Fun(fd))
        } else {
            Err(Error::UnexpectedToken(
                self.curr_token(),
                vec![TokenType::Var, TokenType::Function]))
        }
    }

    fn parse_var_decls(&mut self) -> Result<Vec<VarDecl>> {
        let mut vds = Vec::new();
        while self.peek(TokenType::Var) {
            let vd = try!(self.parse_var_decl());
            vds.push(vd);
        }
        Ok(vds)
    }

    /*
     * var_decl = "var" id ":" type ";"
     */
    fn parse_var_decl(&mut self) -> Result<VarDecl> {
        let pos = self.token_pos();
        try!(self.eat(TokenType::Var));
        let id = try!(self.eat_lexeme(TokenType::Id));
        try!(self.eat(TokenType::Colon));
        let ty = try!(self.eat_type());
        try!(self.eat(TokenType::Semicolon));
        Ok(VarDecl { pos: pos, id: id, ty: ty })
    }

    /*
     * fun_decl   = "function" id "(" param_list ")" ":" type { stmt } "end"
     */
    fn parse_func_decl(&mut self) -> Result<FunDecl> {
        let pos = self.token_pos();
        try!(self.eat(TokenType::Function));
        let id = try!(self.eat_lexeme(TokenType::Id));
        try!(self.eat(TokenType::LParen));
        let params = try!(self.parse_params());
        try!(self.eat(TokenType::RParen));
        try!(self.eat(TokenType::Colon));
        let ty = try!(self.eat_type());
        let decls = try!(self.parse_var_decls());
        let stmts = try!(self.parse_stmts());
        try!(self.eat(TokenType::End));

        Ok(FunDecl {
            pos: pos,
            id: id,
            params: params,
            ty: ty,
            decls: decls,
            stmts: stmts,
        })
    }

    /*
     * params = ε
     *        | id ":" type
     *        | id ":" type "," params
     */
    fn parse_params(&mut self) -> Result<Vec<(String, Type)>> {
        let mut params = Vec::new();
        while self.peek(TokenType::Id) {
            let id = try!(self.eat_lexeme(TokenType::Id));
            try!(self.eat(TokenType::Colon));
            let ty = try!(self.eat_type());
            params.push((id, ty));

            if self.peek(TokenType::Comma) {
                try!(self.eat(TokenType::Comma));
            } else {
                break;
            }
        }
        Ok(params)
    }

    fn parse_stmts(&mut self) -> Result<Vec<Stmt>> {
        let mut stmts: Vec<Stmt> = Vec::new();
        while self.is_stmt_start() {
            let stmt = try!(self.parse_stmt());
            stmts.push(stmt);
        }
        Ok(stmts)
    }

    /*
     * stmt = read_stmt
     *      | print_stmt
     *      | assign_stmt
     *      | if_stmt
     *      | while_stmt
     *      | return_stmt
     */
    fn parse_stmt(&mut self) -> Result<Stmt> {
        if self.peek(TokenType::Read) {
            self.parse_read()
        } else if self.peek(TokenType::Print) {
            self.parse_print()
        } else if self.peek(TokenType::Id) {
            self.parse_assign()
        } else if self.peek(TokenType::If) {
            self.parse_if()
        } else if self.peek(TokenType::While) {
            self.parse_while()
        } else if self.peek(TokenType::Return) {
            self.parse_return()
        } else {
            Err(Error::UnexpectedToken(
                self.curr_token(),
                vec![TokenType::Read, TokenType::Print,
                     TokenType::Id, TokenType::If, TokenType::While]))
        }
    }

    /*
     * read_stmt = "read" id ";"
     */
    fn parse_read(&mut self) -> Result<Stmt> {
        let pos = self.token_pos();
        try!(self.eat(TokenType::Read));
        let id = try!(self.eat_lexeme(TokenType::Id));
        try!(self.eat(TokenType::Semicolon));
        Ok(Stmt::Read(StmtRead { pos: pos, id: id }))
    }

    /*
     * print_stmt = "print" expr ";"
     */
    fn parse_print(&mut self) -> Result<Stmt> {
        let pos = self.token_pos();
        try!(self.eat(TokenType::Print));
        let e = try!(self.parse_expr());
        try!(self.eat(TokenType::Semicolon));
        Ok(Stmt::Print(StmtPrint { pos: pos, expr: e }))
    }

    /*
     * assign_stmt = id "=" expr ";"
     */
    fn parse_assign(&mut self) -> Result<Stmt> {
        let pos = self.token_pos();
        let id = try!(self.eat_lexeme(TokenType::Id));
        try!(self.eat(TokenType::Equal));
        let e = try!(self.parse_expr());
        try!(self.eat(TokenType::Semicolon));
        Ok(Stmt::Assign(StmtAssign { pos: pos, id: id, expr: e }))
    }

    /*
     * if_stmt = "if" expr "then" { stmt } [ "else" { stmt } ] "end"
     */
    fn parse_if(&mut self) -> Result<Stmt> {
        let pos = self.token_pos();
        try!(self.eat(TokenType::If));
        let e = try!(self.parse_expr());
        try!(self.eat(TokenType::Then));
        let then_stmts = try!(self.parse_stmts());
        try!(self.eat(TokenType::Else));
        let else_stmts = try!(self.parse_stmts());
        try!(self.eat(TokenType::End));
        Ok(Stmt::If(StmtIf {
            pos: pos,
            expr: e,
            then_stmts: then_stmts,
            else_stmts: else_stmts,
        }))
    }

    /*
     * while_stmt = "while" expr "do" { stmt } "done"
     */
    fn parse_while(&mut self) -> Result<Stmt> {
        let pos = self.token_pos();
        try!(self.eat(TokenType::While));
        let e = try!(self.parse_expr());
        try!(self.eat(TokenType::Do));
        let stmts = try!(self.parse_stmts());
        try!(self.eat(TokenType::Done));
        Ok(Stmt::While(StmtWhile {
            pos: pos,
            expr: e,
            stmts: stmts,
        }))
    }

    /*
     * return_stmt = "return" [ expr ] ";"
     */
    fn parse_return(&mut self) -> Result<Stmt> {
        let pos = self.token_pos();
        try!(self.eat(TokenType::Return));

        let expr =
            if self.peek(TokenType::Semicolon) {
                None
            } else {
                Some(try!(self.parse_expr()))
            };
        try!(self.eat(TokenType::Semicolon));

        Ok(Stmt::Return(StmtReturn {
            pos: pos,
            expr: expr,
        }))
    }

    /*
     * expr = expr "+" term
     *      | expr "-" term
     *      | term
     */
    fn parse_expr(&mut self) -> Result<Expr> {
        let pos = self.token_pos();
        let mut expr = try!(self.parse_term());
        while self.next_is_add() {
            if self.peek(TokenType::Plus) {
                try!(self.eat(TokenType::Plus));
                let term = try!(self.parse_term());
                expr = Expr::Binop(ExprBinop {
                    pos: pos,
                    op: Binop::Add,
                    expr1: Box::new(expr),
                    expr2: Box::new(term)
                });
            } else if self.peek(TokenType::Minus) {
                try!(self.eat(TokenType::Minus));
                let term = try!(self.parse_term());
                expr = Expr::Binop(ExprBinop {
                    pos: pos,
                    op: Binop::Sub,
                    expr1: Box::new(expr),
                    expr2: Box::new(term)
                });
            } else {
                return Err(Error::UnexpectedToken(
                    self.curr_token(),
                    vec![TokenType::Plus, TokenType::Minus]));
            }
        }
        Ok(expr)
    }

    /*
     * term = term "+" factor
     *      | term "-" factor
     *      | factor
     */
    fn parse_term(&mut self) -> Result<Expr> {
        let pos = self.token_pos();
        let mut fact = try!(self.parse_factor());
        while self.next_is_mul() {
            if self.peek(TokenType::Star) {
                try!(self.eat(TokenType::Star));
                let f2 = try!(self.parse_factor());
                fact = Expr::Binop(ExprBinop {
                    pos: pos,
                    op: Binop::Mul,
                    expr1: Box::new(fact),
                    expr2: Box::new(f2),
                });
            } else if self.peek(TokenType::Slash) {
                try!(self.eat(TokenType::Slash));
                let f2 = try!(self.parse_factor());
                fact = Expr::Binop(ExprBinop {
                    pos: pos,
                    op: Binop::Div,
                    expr1: Box::new(fact),
                    expr2: Box::new(f2),
                });
            } else {
                return Err(Error::UnexpectedToken(
                    self.curr_token(),
                    vec![TokenType::Star, TokenType::Slash]));
            }
        }
        Ok(term)
    }

    /*
     * factor = id
     *        | id "(" expr* ")"
     *        | int_literal
     *        | float_literal
     *        | "(" expr ")"
     *        | "-" expr
     */
    fn parse_factor(&mut self) -> Result<Expr> {
        let pos = self.token_pos();
        if self.peek(TokenType::Int) {
            self.parse_int()
        } else if self.peek(TokenType::Float) {
            self.parse_float()
        } else if self.peek(TokenType::Id) {
            self.parse_id()
        } else if self.peek(TokenType::LParen) {
            try!(self.eat(TokenType::LParen));
            let e = try!(self.parse_expr());
            try!(self.eat(TokenType::RParen));
            Ok(e)
        } else if self.peek(TokenType::Minus) {
            try!(self.eat(TokenType::Minus));
            let e = try!(self.parse_expr());
            Ok(Expr::Negate(ExprNegate { pos: pos, expr: Box::new(e) }))
        } else {
            Err(Error::UnexpectedToken(
                self.curr_token(),
                vec![TokenType::Int, TokenType::Float, TokenType::Id,
                     TokenType::Minus, TokenType::LParen]))
        }
    }

    fn parse_int(&mut self) -> Result<Expr> {
        let pos = self.token_pos();
        let lexeme = try!(self.eat_lexeme(TokenType::Int));
        match lexeme.parse::<i64>() {
            Ok(n) => Ok(Expr::Int (ExprInt { pos: pos, value: n })),
            Err(_) => Err(Error::InvalidIntLiteral(pos, lexeme))
        }
    }

    fn parse_float(&mut self) -> Result<Expr> {
        let pos = self.token_pos();
        let lexeme = try!(self.eat_lexeme(TokenType::Float));
        match lexeme.parse::<f64>() {
            Ok(n) => Ok(Expr::Float(ExprFloat { pos: pos, value: Float(n) })),
            Err(_) => Err(Error::InvalidFloatLiteral(pos, lexeme))
        }
    }

    fn parse_id(&mut self) -> Result<Expr> {
        let pos = self.token_pos();
        let lexeme = try!(self.eat_lexeme(TokenType::Id));
        Ok(Expr::Id(ExprId { pos: pos, id: lexeme }))
    }

    fn is_stmt_start(&self) -> bool {
        self.peek(TokenType::Id) ||
            self.peek(TokenType::If) ||
            self.peek(TokenType::While) ||
            self.peek(TokenType::Read) ||
            self.peek(TokenType::Print) ||
            self.peek(TokenType::Return)
    }

    fn next_is_add(&self) -> bool {
        self.peek(TokenType::Plus) || self.peek(TokenType::Minus)
    }

    fn next_is_mul(&self) -> bool {
        self.peek(TokenType::Star) || self.peek(TokenType::Slash)
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use collections::deque::Deque;
use collections::dlist::DList;

use lexer;
//use token::{String, Whitespace, Operator, AtSymbol};

pub enum SectionType {
    Html(StrBuf),
    Code(StrBuf),
    Directive(StrBuf, StrBuf),
    Print(StrBuf),
    Comment(StrBuf)
}

impl fmt::Show for SectionType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Html(ref s) => write!(f.buf, "Html({})", *s),
            Code(ref s) => write!(f.buf, "Code({})", *s),
            Print(ref s) => write!(f.buf, "Print({})", *s),
            Comment(ref s) => write!(f.buf, "Comment({})", *s),
            Directive(ref s1, ref s2) => write!(f.buf, "Directive({}, {})", *s1, *s2)
        }
    }
}

pub struct Parser<'a> {
    pub sections: DList<SectionType>,
    source: &'a str
}

impl<'a> Parser<'a> {
    pub fn new(source: &'a str) -> Parser<'a> {
        Parser {
            sections: DList::new(),
            source: source
        }
    }

    pub fn parse(&mut self) {
        let sections = self.parse_html(self.source, 1, 1);

        self.sections = sections;
    }

    pub fn parse_html(&self, source: &'a str, line: int, column: int) -> DList<SectionType> {
        let mut sections = DList::new();
        let mut lexer = lexer::HtmlLexer::new(source, line, column);

        match lexer.next_transition() {
            Some(index) => {
                sections.push_back(Html(source.slice_to(index).to_strbuf()));

                if index < source.len() {
                    sections.append(self.parse_code(source.slice_from(index), 1, 1));
                }
            },
            None => {
                sections.push_back(Html(source.to_strbuf()));
            }
        };

        sections
    }

    fn parse_code(&self, source: &'a str, line: int, column: int) -> DList<SectionType> {
        let sections: DList<SectionType> = DList::new();
        //let mut lexer = lexer::CodeLexer::new(source, line, column);

        if source.len() < 2 {
            return sections;
        }

        let first = source.char_at(0);
        match first {
            '@' => (),
            _ => return self.parse_html(source, line, column)
        };

        let next = source.char_at(1);
        match next {
            '{' => self.parse_code_block(source, line, column),
            _ => {
                self.parse_expression_block(source, line, column)
            }
        }
    }

    fn parse_code_block(&self, source: &'a str, line: int, column: int) -> DList<SectionType> {
        let mut sections: DList<SectionType> = DList::new();
        let lexer = lexer::CodeLexer::new(source, line, column);

        match lexer.end_of_code_block() {
            None => fail!("Unterminated code block"),
            Some(index) => {
                // skip the @{ by starting the slice at 2
                sections.push_back(Code(source.slice_chars(2, index).to_strbuf()));

                if index < source.len() {
                    sections.append(self.parse_html(source.slice_from(index + 1), 1, 1));
                }
            }
        };

        sections
    }

    fn parse_expression_block(&self, source: &str, line: int, column: int) -> DList<SectionType> {
        //let mut sections: DList<SectionType> = DList::new();
        let lexer = lexer::CodeLexer::new(source, line, column);

        let next_brace = lexer.next_instance_of('{');
        let next_parenthese = lexer.next_instance_of('(');

        let next_transition = match (next_brace, next_parenthese) {
            (Some(b), Some(p)) => Some(::std::cmp::min(b, p)),
            (Some(b), _) => Some(b),
            (_, Some(p)) => Some(p),
            _ => None
            };

        match next_transition {
            Some(_) => {
                let identifier = lexer.accept_identifier(source.slice_from(1));
                let identifier = identifier.as_slice();

                if lexer.is_keyword(identifier) {
                    return self.parse_keyword(identifier, source.slice_from(1), 1, 1);
                }
            },
            None => ()
        };

        self.parse_expression(source, line, column)
    }

    fn parse_expression(&self, source: &str, line: int, column: int) -> DList<SectionType> {
        let sections: DList<SectionType> = DList::new();
        let lexer = lexer::CodeLexer::new(source, line, column);

        sections
    }

    fn parse_keyword(&self, identifier: &str, source: &str, line: int, column: int) -> DList<SectionType> {
        //let sections: DList<SectionType> = DList::new();
        //let lexer = lexer::CodeLexer::new(source, line, column);

        match identifier {
            "model" => {
                self.parse_model(source.slice_from(identifier.len()), line, column)
            },
            "for" |
            "while" => {
                self.parse_simple_block(source, line, column)
            },
            _ => {
                self.parse_html(source, line, column)
            }
        }
    }

    fn parse_model(&self, source: &str, line: int, column: int) -> DList<SectionType> {
        let mut sections: DList<SectionType> = DList::new();
        let lexer = lexer::CodeLexer::new(source, line, column);

        match lexer.end_of_code_statement() {
            Some(index) => {
                // don't include the `;`
                sections.push_back(Directive(StrBuf::from_str("model"), source.slice_to(index).to_strbuf()));
                // now skip the `;`
                sections.append(self.parse_html(source.slice_from(index + 1), 1, 1));
                return sections
            },
            None => {
                fail!("Unable to find end of `model` directive at {}:{}", line, column)
            }
        };
    }

    fn parse_simple_block(&self, source: &str, line: int, column: int) -> DList<SectionType> {
        let mut sections: DList<SectionType> = DList::new();
        let lexer = lexer::CodeLexer::new(source, line, column);

        match lexer.block_delimiters() {
            (Some(start), Some(end)) => {
                sections.push_back(Code(source.slice_to(start + 1).to_strbuf()));
                sections.append(self.parse_html(source.slice_chars(start+1, end), 1, 1));
                sections.push_back(Code("}".to_strbuf()));
                sections.append(self.parse_html(source.slice_from(end+1), 1, 1));
                sections
            },
            (Some(_), None) => {
                fail!("Missing end `\\}` for code block beginning at {}:{}", line, column);
            },
            (None, Some(_)) => {
                fail!("Missing start `\\{` for code block beginning at {}:{}", line, column);
            },
            (None, None) => {
                fail!("Unable to find start `\\{` and end `\\}` for code block beginning at {}:{}", line, column);
            }
        }
    }
}
<commit_msg>Small cleanup to parser code<commit_after>use collections::deque::Deque;
use collections::dlist::DList;

use lexer::{HtmlLexer, CodeLexer};
//use token::{String, Whitespace, Operator, AtSymbol};

#[deriving(Show)]
pub enum SectionType {
    Html(StrBuf),
    Code(StrBuf),
    Directive(StrBuf, StrBuf),
    Print(StrBuf),
    Comment(StrBuf)
}

pub struct Parser<'a> {
    pub sections: DList<SectionType>,
    source: &'a str
}

impl<'a> Parser<'a> {
    pub fn new(source: &'a str) -> Parser<'a> {
        Parser {
            sections: DList::new(),
            source: source
        }
    }

    pub fn parse(&mut self) {
        let sections = self.parse_html(self.source, 1, 1);

        self.sections = sections;
    }

    pub fn parse_html(&self, source: &'a str, line: int, column: int) -> DList<SectionType> {
        let mut sections = DList::new();
        let mut lexer = HtmlLexer::new(source, line, column);

        match lexer.next_transition() {
            Some(index) => {
                if index > 0 {
                    sections.push_back(Html(source.slice_to(index).to_strbuf()));
                }

                if index < source.len() {
                    sections.append(self.parse_code(source.slice_from(index), 1, 1));
                }
            },
            None => {
                sections.push_back(Html(source.to_strbuf()));
            }
        };

        sections
    }

    fn parse_code(&self, source: &'a str, line: int, column: int) -> DList<SectionType> {
        let sections: DList<SectionType> = DList::new();
        //let mut lexer = CodeLexer::new(source, line, column);

        if source.len() < 2 {
            return sections;
        }

        let first = source.char_at(0);
        match first {
            '@' => (),
            _ => return self.parse_html(source, line, column)
        };

        let next = source.char_at(1);
        match next {
            '{' => self.parse_code_block(source, line, column),
            _ => {
                self.parse_expression_block(source, line, column)
            }
        }
    }

    fn parse_code_block(&self, source: &'a str, line: int, column: int) -> DList<SectionType> {
        let mut sections: DList<SectionType> = DList::new();
        let lexer = CodeLexer::new(source, line, column);

        match lexer.end_of_code_block() {
            None => fail!("Unterminated code block"),
            Some(index) => {
                // skip the @{ by starting the slice at 2
                sections.push_back(Code(source.slice_chars(2, index).to_strbuf()));

                if index < source.len() {
                    sections.append(self.parse_html(source.slice_from(index + 1), 1, 1));
                }
            }
        };

        sections
    }

    fn parse_expression_block(&self, source: &str, line: int, column: int) -> DList<SectionType> {
        //let mut sections: DList<SectionType> = DList::new();
        let lexer = CodeLexer::new(source, line, column);

        let next_brace = lexer.next_instance_of('{');
        let next_parenthese = lexer.next_instance_of('(');

        let next_transition = match (next_brace, next_parenthese) {
            (Some(b), Some(p)) => Some(::std::cmp::min(b, p)),
            (Some(b), _) => Some(b),
            (_, Some(p)) => Some(p),
            _ => None
            };

        match next_transition {
            Some(_) => {
                let identifier = lexer.accept_identifier(source.slice_from(1));
                let identifier = identifier.as_slice();

                if lexer.is_keyword(identifier) {
                    return self.parse_keyword(identifier, source.slice_from(1), 1, 1);
                }
            },
            None => ()
        };

        self.parse_expression(source, line, column)
    }

    fn parse_expression(&self, source: &str, line: int, column: int) -> DList<SectionType> {
        let sections: DList<SectionType> = DList::new();
        let lexer = CodeLexer::new(source, line, column);

        sections
    }

    fn parse_keyword(&self, identifier: &str, source: &str, line: int, column: int) -> DList<SectionType> {
        //let sections: DList<SectionType> = DList::new();
        //let lexer = CodeLexer::new(source, line, column);

        match identifier {
            "model" => {
                self.parse_model(source.slice_from(identifier.len()), line, column)
            },
            "for" |
            "while" => {
                self.parse_simple_block(source, line, column)
            },
            _ => {
                self.parse_html(source, line, column)
            }
        }
    }

    fn parse_model(&self, source: &str, line: int, column: int) -> DList<SectionType> {
        let mut sections: DList<SectionType> = DList::new();
        let lexer = CodeLexer::new(source, line, column);

        match lexer.end_of_code_statement() {
            Some(index) => {
                // don't include the `;`
                sections.push_back(Directive(StrBuf::from_str("model"), source.slice_to(index).to_strbuf()));
                // now skip the `;`
                sections.append(self.parse_html(source.slice_from(index + 1), 1, 1));
                return sections
            },
            None => {
                fail!("Unable to find end of `model` directive at {}:{}", line, column)
            }
        };
    }

    fn parse_simple_block(&self, source: &str, line: int, column: int) -> DList<SectionType> {
        let mut sections: DList<SectionType> = DList::new();
        let lexer = CodeLexer::new(source, line, column);

        match lexer.block_delimiters() {
            (Some(start), Some(end)) => {
                sections.push_back(Code(source.slice_to(start + 1).to_strbuf()));
                sections.append(self.parse_html(source.slice_chars(start+1, end), 1, 1));
                sections.push_back(Code("}".to_strbuf()));
                sections.append(self.parse_html(source.slice_from(end+1), 1, 1));
                sections
            },
            (Some(_), None) => {
                fail!("Missing end `\\}` for code block beginning at {}:{}", line, column);
            },
            (None, Some(_)) => {
                fail!("Missing start `\\{` for code block beginning at {}:{}", line, column);
            },
            (None, None) => {
                fail!("Unable to find start `\\{` and end `\\}` for code block beginning at {}:{}", line, column);
            }
        }
    }
}
<|endoftext|>