<commit_before>// This library is inspired by Rodrigo Palacios's excellent
// explanation of autocompletion that can be found here:
// https://github.com/rodricios/autocomplete

use std::cmp::{Ord,PartialOrd,Ordering};
use std::collections::HashMap;
use std::collections::hash_map::Entry;

// SimpleWordModel uses a HashMap representation to train on word
// frequency. It is fast for looking up words and incrementing their
// count but since HashMap does not keep track of order, searching the
// keys of a hashmap takes a long time. After the model is trained it
// must be converted to a SimpleWordPredictor which stores the words
// in lexical order and has an index of first letters.
#[derive(Debug)]
pub struct SimpleWordModel(HashMap<String, u32>);

// SimpleWordPredictor uses a constant sized vector of entries indexed by
// first letter. Prediction starts from that index and continues until
// the first letter in the vector changes.
#[derive(Debug)]
pub struct SimpleWordPredictor {
    entries: Vec<SimpleWordEntry>,
    ixs: HashMap<char, u32>,
}

#[derive(Debug)]
pub struct SimpleWordEntry {
    pub word: String,
    pub score: u32,
}

impl Clone for SimpleWordEntry {
    fn clone(&self) -> Self {
        SimpleWordEntry {
            word: self.word.clone(),
            score: self.score
        }
    }
}

// Eq, PartialEq, PartialOrd and Ord are necessary to be able to
// .sort() a vec<SimpleWordEntry>.
impl Eq for SimpleWordEntry { }

impl PartialEq for SimpleWordEntry {
    fn eq(&self, other: &Self) -> bool {
        self.word.eq(&other.word)
    }
}

impl PartialOrd for SimpleWordEntry {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.word.partial_cmp(&other.word)
    }
}

impl Ord for SimpleWordEntry {
    fn cmp(&self, other: &Self) -> Ordering {
        self.word.cmp(&other.word)
    }
}

impl SimpleWordPredictor {
    // Given an input string, return the top 10 suggestions based on
    // training data.
    pub fn predict(&self, input: &str) -> Vec<SimpleWordEntry> {
        let mut predictions: Vec<SimpleWordEntry> = Vec::new();
        let iter = self.entries.iter();
        let first_letter = input.char_at(0);
        let skip_n = self.ixs.get(&first_letter);

        match skip_n {
            Some(n) => {
                let iter = iter.skip(*n as usize);
                for entry in iter {
                    let word = entry.word.as_slice();
                    if word.char_at(0) != first_letter {
                        break;
                    }

                    if word.starts_with(input) {
                        predictions.push(entry.clone());
                    }
                }

                predictions.sort_by(|a, b| {
                    b.score.cmp(&a.score)
                });

                predictions.truncate(10);

                predictions
            },
            None => {
                return predictions;
            },
        }
    }
}

impl SimpleWordModel {
    pub fn from_str(input: &str) -> SimpleWordModel {
        let model_hm: HashMap<String, u32> = HashMap::new();
        let mut model = SimpleWordModel(model_hm);
        let v_input = input.split(' ').collect();
        count_words(&mut model, &v_input);

        model
    }

    pub fn from_vec(input: &Vec<&str>) -> SimpleWordModel {
        let model_hm: HashMap<String, u32> = HashMap::new();
        let mut model = SimpleWordModel(model_hm);

        count_words(&mut model, input);

        model
    }

    pub fn new() -> SimpleWordModel {
        let model_hm: HashMap<String, u32> = HashMap::new();

        SimpleWordModel(model_hm)
    }

    pub fn train_str(&mut self, input: &str) {
        let v_input = input.split(' ').collect();
        count_words(self, &v_input);
    }

    pub fn train_vec(&mut self, input: Vec<&str>) {
        count_words(self, &input);
    }

    // Convert the HashMap representation to an indexed vec.
    pub fn finalize(self) -> SimpleWordPredictor {
        let SimpleWordModel(hm) = self;
        let size = hm.len();
        let mut entries = Vec::with_capacity(size);

        for (key, value) in hm {
            entries.push(SimpleWordEntry {word: key, score: value});
        }

        entries.sort();

        let ixs = generate_ixs(&entries);
        SimpleWordPredictor {entries: entries, ixs: ixs}
    }
}

fn generate_ixs(entries: &Vec<SimpleWordEntry>) -> HashMap<char, u32>{
    let mut ixs: HashMap<char, u32> = HashMap::new();

    // There will be no newlines in the input. This is a placeholder
    // until the first time the loop runs.
    let mut last_c = '\n';
    let mut ix = 0;

    for entry in entries {
        let c = entry.word.char_at(0);
        if c != last_c {
            ixs.insert(c, ix);
            last_c = c;
        }
        ix += 1;
    }

    ixs
}

fn count_words(model: &mut SimpleWordModel, input: &Vec<&str>) {
    let &mut SimpleWordModel(ref mut model_hm) = model;
    for word in input {
        if word.len() == 0 {
            continue;
        }
        let string_word = String::from_str(*word);
        let entry = model_hm.entry(string_word);
        match entry {
            Entry::Vacant(vacant_entry) => {
                vacant_entry.insert(1);
            },
            Entry::Occupied(mut occ_entry) => {
                let c = occ_entry.get_mut();
                *c += 1;
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use models::SimpleWordModel;

    #[test]
    fn test_from_str() {
        let model = SimpleWordModel::from_str("world domination is my profession hello hello");

        let SimpleWordModel(hash_map) = model;

        assert_eq!(1, *hash_map.get("world").unwrap());
        assert_eq!(2, *hash_map.get("hello").unwrap());
    }

    #[test]
    fn test_from_vec() {
        let model = SimpleWordModel::from_vec(&vec!["rabbit", "rabbit", "hare"]);

        let SimpleWordModel(hash_map) = model;

        assert_eq!(1, *hash_map.get("hare").unwrap());
        assert_eq!(2, *hash_map.get("rabbit").unwrap());
    }

    #[test]
    fn test_train_str() {
        let mut model = SimpleWordModel::new();

        model.train_str("hello hello hello there there");

        let SimpleWordModel(hash_map) = model;
        assert_eq!(3, *hash_map.get("hello").unwrap());
        assert_eq!(2, *hash_map.get("there").unwrap());
    }

    #[test]
    fn test_train_vec() {
        let mut model = SimpleWordModel::new();

        model.train_vec(vec!["hello", "hello", "hello", "what",
                             "is", "this"]);

        let SimpleWordModel(hash_map) = model;
        assert_eq!(3, *hash_map.get("hello").unwrap());
        assert_eq!(1, *hash_map.get("what").unwrap());
    }

    #[test]
    fn test_finalize() {
        let mut model = SimpleWordModel::new();

        model.train_str(concat!["anybody can become angry that is easy but to be ",
                                "angry with the right person and to the right degree ",
                                "and at the right time and for the right purpose ",
                                "and in the right way that is not within everybody's ",
                                "power and is not easy"]);

        let predictor = model.finalize();

        assert_eq!(predictor.entries[0].word, "and");
        assert_eq!(predictor.entries[0].score, 5);
    }

    #[test]
    fn test_predict() {
        let mut model = SimpleWordModel::new();

        model.train_str(concat!["anybody can become angry that is easy but to be ",
                                "angry with the right person and to the right degree ",
                                "and at the right time and for the right purpose ",
                                "and in the right way that is not within everybody's ",
                                "power and is not easy"]);

        let predictor = model.finalize();
        println!("{:?}", predictor.predict("a"));
    }

}
<commit_msg>Remove models.rs<commit_after><|endoftext|>


<commit_before>#![cfg(target_os = "windows")]

pub mod ffi {
   #![allow(non_snake_case)]

   pub use libc::{
      c_int, c_uint, c_void, uintptr_t, c_long, c_ulong
   };
   pub use libc::types::os::arch::extra::{
      HANDLE, LONG_PTR, LRESULT, HINSTANCE, LPCWSTR, HMODULE, LPVOID, BOOL
   };
   use std::mem;

   pub type HWND = HANDLE;
   pub type HICON = HANDLE;
   pub type HBRUSH = HANDLE;
   pub type HMENU = HANDLE;
   pub type HDC = HANDLE;
   pub type HCURSOR = HICON;

   pub type WPARAM = uintptr_t;
   pub type LPARAM = LONG_PTR;

   pub type ATOM = u16;

   pub type WNDPROC = Option<unsafe extern "system" fn(HWND, c_uint, WPARAM, LPARAM) -> LRESULT>;

   pub const CS_VREDRAW:                 c_ulong = 0x00000001;
   pub const CS_HREDRAW:                 c_ulong = 0x00000002;
   pub const CS_DBLCLKS:                 c_ulong = 0x00000008;
   pub const CS_OWNDC:                   c_ulong = 0x00000020;
   pub const CS_CLASSDC:                 c_ulong = 0x00000040;
   pub const CS_PARENTDC:                c_ulong = 0x00000080;
   pub const CS_NOCLOSE:                 c_ulong = 0x00000200;
   pub const CS_SAVEBITS:                c_ulong = 0x00000800;
   pub const CS_BYTEALIGNCLIENT:         c_ulong = 0x00001000;
   pub const CS_BYTEALIGNWINDOW:         c_ulong = 0x00002000;
   pub const CS_GLOBALCLASS:             c_ulong = 0x00004000;
   pub const CS_IME:                     c_ulong = 0x00010000;
   pub const CS_DROPSHADOW:              c_ulong = 0x00020000;

   pub const WS_OVERLAPPED:              c_ulong = 0x00000000;
   pub const WS_POPUP:                   c_ulong = 0x80000000;
   pub const WS_CHILD:                   c_ulong = 0x40000000;
   pub const WS_MINIMIZE:                c_ulong = 0x20000000;
   pub const WS_VISIBLE:                 c_ulong = 0x10000000;
   pub const WS_DISABLED:                c_ulong = 0x08000000;
   pub const WS_CLIPSIBLINGS:            c_ulong = 0x04000000;
   pub const WS_CLIPCHILDREN:            c_ulong = 0x02000000;
   pub const WS_MAXIMIZE:                c_ulong = 0x01000000;
   pub const WS_CAPTION:                 c_ulong = 0x00C00000;
   pub const WS_BORDER:                  c_ulong = 0x00800000;
   pub const WS_DLGFRAME:                c_ulong = 0x00400000;
   pub const WS_VSCROLL:                 c_ulong = 0x00200000;
   pub const WS_HSCROLL:                 c_ulong = 0x00100000;
   pub const WS_SYSMENU:                 c_ulong = 0x00080000;
   pub const WS_THICKFRAME:              c_ulong = 0x00040000;
   pub const WS_GROUP:                   c_ulong = 0x00020000;
   pub const WS_TABSTOP:                 c_ulong = 0x00010000;
   pub const WS_MINIMIZEBOX:             c_ulong = 0x00020000;
   pub const WS_MAXIMIZEBOX:             c_ulong = 0x00010000;
   pub const WS_TILED:                   c_ulong = WS_OVERLAPPED;
   pub const WS_ICONIC:                  c_ulong = WS_MINIMIZE;
   pub const WS_SIZEBOX:                 c_ulong = WS_THICKFRAME;
   pub const WS_TILEDWINDOW:             c_ulong = WS_OVERLAPPEDWINDOW;
   pub const WS_OVERLAPPEDWINDOW:        c_ulong = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
   pub const WS_POPUPWINDOW:             c_ulong = WS_POPUP | WS_BORDER | WS_SYSMENU;
   pub const WS_CHILDWINDOW:             c_ulong = WS_CHILD;

   pub const WS_EX_DLGMODALFRAME:        c_ulong = 0x00000001;
   pub const WS_EX_NOPARENTNOTIFY:       c_ulong = 0x00000004;
   pub const WS_EX_TOPMOST:              c_ulong = 0x00000008;
   pub const WS_EX_ACCEPTFILES:          c_ulong = 0x00000010;
   pub const WS_EX_TRANSPARENT:          c_ulong = 0x00000020;
   pub const WS_EX_MDICHILD:             c_ulong = 0x00000040;
   pub const WS_EX_TOOLWINDOW:           c_ulong = 0x00000080;
   pub const WS_EX_WINDOWEDGE:           c_ulong = 0x00000100;
   pub const WS_EX_CLIENTEDGE:           c_ulong = 0x00000200;
   pub const WS_EX_CONTEXTHELP:          c_ulong = 0x00000400;
   pub const WS_EX_RIGHT:                c_ulong = 0x00001000;
   pub const WS_EX_LEFT:                 c_ulong = 0x00000000;
   pub const WS_EX_RTLREADING:           c_ulong = 0x00002000;
   pub const WS_EX_LTRREADING:           c_ulong = 0x00000000;
   pub const WS_EX_LEFTSCROLLBAR:        c_ulong = 0x00004000;
   pub const WS_EX_RIGHTSCROLLBAR:       c_ulong = 0x00000000;
   pub const WS_EX_CONTROLPARENT:        c_ulong = 0x00010000;
   pub const WS_EX_STATICEDGE:           c_ulong = 0x00020000;
   pub const WS_EX_APPWINDOW:            c_ulong = 0x00040000;
   pub const WS_EX_OVERLAPPEDWINDOW:     c_ulong = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE;
   pub const WS_EX_PALETTEWINDOW:        c_ulong = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
   pub const WS_EX_LAYERED:              c_ulong = 0x00080000;
   pub const WS_EX_NOINHERITLAYOUT:      c_ulong = 0x00100000;
   pub const WS_EX_NOREDIRECTIONBITMAP:  c_ulong = 0x00200000;
   pub const WS_EX_LAYOUTRTL:            c_ulong = 0x00400000;
   pub const WS_EX_COMPOSITED:           c_ulong = 0x02000000;
   pub const WS_EX_NOACTIVATE:           c_ulong = 0x08000000;

   pub const CW_USEDEFAULT:                c_int = 0x80000000u32 as c_int;

   pub const WM_CLOSE:                    c_uint = 16;

   #[repr(C)]
   #[derive(Copy)]
   pub struct WNDCLASSEXW {
      pub cbSize: c_uint,
      pub style: c_uint,
      pub lpfnWndProc: WNDPROC,
      pub cbClsExtra: c_int,
      pub cbWndExtra: c_int,
      pub hInstance: HINSTANCE,
      pub hIcon: HICON,
      pub hCursor: HCURSOR,
      pub hbrBackground: HBRUSH,
      pub lpszMenuName: LPCWSTR,
      pub lpszClassName: LPCWSTR,
      pub hIconSm: HICON,
   }
   impl Clone for WNDCLASSEXW {
      fn clone(&self) -> Self { *self }
   }
   impl Default for WNDCLASSEXW {
      fn default() -> Self { unsafe { mem::zeroed() } }
   }

   #[repr(C)]
   #[derive(Copy)]
   pub struct POINT {
      pub x: c_long,
      pub y: c_long,
   }
   impl Clone for POINT {
      fn clone(&self) -> Self { *self }
   }
   impl Default for POINT {
      fn default() -> Self { unsafe { mem::zeroed() } }
   }

   #[repr(C)]
   #[derive(Copy)]
   pub struct MSG {
      pub hwnd: HWND,
      pub message: c_uint,
      pub wParam: WPARAM,
      pub lParam: LPARAM,
      pub time: c_ulong,
      pub pt: POINT,
   }
   impl Clone for MSG {
      fn clone(&self) -> Self { *self }
   }
   impl Default for MSG {
      fn default() -> Self { unsafe { mem::zeroed() } }
   }

   extern "system" {
      pub fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE;

      pub fn RegisterClassExW(lpWndClass: *const WNDCLASSEXW) -> ATOM;

      pub fn PostQuitMessage(nExitCode: c_int);

      pub fn TranslateMessage(lpmsg: *const MSG) -> BOOL;

      pub fn DispatchMessageW(lpmsg: *const MSG) -> LRESULT;

      pub fn GetDC(hwnd: HWND) -> HDC;

      pub fn DefWindowProcW(
         hwnd: HWND,
         Msg: c_uint,
         wParam: WPARAM,
         lParam: LPARAM
      ) -> LRESULT;

      pub fn CreateWindowExW(
         dwExStyle: c_ulong,
         lpClassName: LPCWSTR,
         lpWindowName: LPCWSTR,
         dwStyle: c_ulong,
         x: c_int,
         y: c_int,
         nWidth: c_int,
         nHeight: c_int,
         hWndParent: HWND,
         hMenu: HMENU,
         hInstance: HINSTANCE,
         lpParam: LPVOID,
      ) -> HWND;

      pub fn GetMessageW(
         lpMsg: *const MSG,
         hwnd: HWND,
         wMsgFilterMin: c_uint,
         wMsgFilterMax: c_uint
      ) -> BOOL;
   }
}

use std::ptr;
use std::mem;
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;

fn to_utf16_os<S: AsRef<OsStr> + ?Sized>(s: &S) -> Vec<u16> {
   let mut v: Vec<_> = OsStr::new(s).encode_wide().collect();
   v.push(0);
   v
}

pub fn register_window_class<S: AsRef<OsStr> + ?Sized>(class_name: &S) {
   unsafe extern "system" fn wnd_proc(
      hwnd: ffi::HWND,
      msg: ffi::c_uint,
      wparam: ffi::WPARAM,
      lparam: ffi::LPARAM
   ) -> ffi::LRESULT {
      match msg {
         ffi::WM_CLOSE => {
            ffi::PostQuitMessage(0);
         },
         _ => {
            return ffi::DefWindowProcW(hwnd, msg, wparam, lparam);
         }
      }

      return 0;
   }

   unsafe {
      let wnd_class = ffi::WNDCLASSEXW {
         cbSize: mem::size_of::<ffi::WNDCLASSEXW>() as ffi::c_uint,
         style: ffi::CS_HREDRAW | ffi::CS_VREDRAW | ffi::CS_OWNDC,
         lpfnWndProc: Some(wnd_proc),
         cbClsExtra: 0,
         cbWndExtra: 0,
         hInstance: ffi::GetModuleHandleW(ptr::null()),
         hIcon: ptr::null_mut(),
         hCursor: ptr::null_mut(),
         hbrBackground: ptr::null_mut(),
         lpszMenuName: ptr::null(),
         lpszClassName: to_utf16_os(class_name).as_ptr(),
         hIconSm: ptr::null_mut(),
      };

      ffi::RegisterClassExW(&wnd_class);
   }
}

pub struct Window {
   pub hwnd: ffi::HWND
}

impl Window {
   pub fn create<S: AsRef<OsStr> + ?Sized>(width: ffi::c_int, height: ffi::c_int, title: &S, class_name: &S) -> Self {
      let hwnd = unsafe {
         ffi::CreateWindowExW(
            ffi::WS_EX_CLIENTEDGE,
            to_utf16_os(class_name).as_ptr(),
            to_utf16_os(title).as_ptr(),
            ffi::WS_OVERLAPPEDWINDOW | ffi::WS_VISIBLE,
            ffi::CW_USEDEFAULT, ffi::CW_USEDEFAULT,
            width, height,
            ptr::null_mut(),
            ptr::null_mut(),
            ffi::GetModuleHandleW(ptr::null()),
            ptr::null_mut()
         )
      };

      Window {
         hwnd: hwnd
      }
   }

   pub fn dc(&self) -> ffi::HDC {
      {
         unsafe {
            ffi::GetDC(self.hwnd)
         }
      }
   }
}

pub struct Message {
   msg: ffi::MSG
}

impl Message {
   pub fn get() -> Option<Self> {
      let mut msg = unsafe { mem::uninitialized() };

      match unsafe { ffi::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) } {
         0 => None,
         _ => Some(Message {
            msg: msg
         })
      }
   }

   pub fn translate(&self) {
      unsafe {
         ffi::TranslateMessage(&self.msg)
      };
   }

   pub fn dispatch(&self) {
      unsafe {
         ffi::DispatchMessageW(&self.msg)
      };
   }
}
<commit_msg>ShowWindow partial wrapper<commit_after>#![cfg(target_os = "windows")]

pub mod ffi {
   #![allow(non_snake_case)]

   pub use libc::{
      c_int, c_uint, c_void, uintptr_t, c_long, c_ulong
   };
   pub use libc::types::os::arch::extra::{
      HANDLE, LONG_PTR, LRESULT, HINSTANCE, LPCWSTR, HMODULE, LPVOID, BOOL
   };
   use std::mem;

   pub type HWND = HANDLE;
   pub type HICON = HANDLE;
   pub type HBRUSH = HANDLE;
   pub type HMENU = HANDLE;
   pub type HDC = HANDLE;
   pub type HCURSOR = HICON;

   pub type WPARAM = uintptr_t;
   pub type LPARAM = LONG_PTR;

   pub type ATOM = u16;

   pub type WNDPROC = Option<unsafe extern "system" fn(HWND, c_uint, WPARAM, LPARAM) -> LRESULT>;

   pub const CS_VREDRAW:                 c_ulong = 0x00000001;
   pub const CS_HREDRAW:                 c_ulong = 0x00000002;
   pub const CS_DBLCLKS:                 c_ulong = 0x00000008;
   pub const CS_OWNDC:                   c_ulong = 0x00000020;
   pub const CS_CLASSDC:                 c_ulong = 0x00000040;
   pub const CS_PARENTDC:                c_ulong = 0x00000080;
   pub const CS_NOCLOSE:                 c_ulong = 0x00000200;
   pub const CS_SAVEBITS:                c_ulong = 0x00000800;
   pub const CS_BYTEALIGNCLIENT:         c_ulong = 0x00001000;
   pub const CS_BYTEALIGNWINDOW:         c_ulong = 0x00002000;
   pub const CS_GLOBALCLASS:             c_ulong = 0x00004000;
   pub const CS_IME:                     c_ulong = 0x00010000;
   pub const CS_DROPSHADOW:              c_ulong = 0x00020000;

   pub const WS_OVERLAPPED:              c_ulong = 0x00000000;
   pub const WS_POPUP:                   c_ulong = 0x80000000;
   pub const WS_CHILD:                   c_ulong = 0x40000000;
   pub const WS_MINIMIZE:                c_ulong = 0x20000000;
   pub const WS_VISIBLE:                 c_ulong = 0x10000000;
   pub const WS_DISABLED:                c_ulong = 0x08000000;
   pub const WS_CLIPSIBLINGS:            c_ulong = 0x04000000;
   pub const WS_CLIPCHILDREN:            c_ulong = 0x02000000;
   pub const WS_MAXIMIZE:                c_ulong = 0x01000000;
   pub const WS_CAPTION:                 c_ulong = 0x00C00000;
   pub const WS_BORDER:                  c_ulong = 0x00800000;
   pub const WS_DLGFRAME:                c_ulong = 0x00400000;
   pub const WS_VSCROLL:                 c_ulong = 0x00200000;
   pub const WS_HSCROLL:                 c_ulong = 0x00100000;
   pub const WS_SYSMENU:                 c_ulong = 0x00080000;
   pub const WS_THICKFRAME:              c_ulong = 0x00040000;
   pub const WS_GROUP:                   c_ulong = 0x00020000;
   pub const WS_TABSTOP:                 c_ulong = 0x00010000;
   pub const WS_MINIMIZEBOX:             c_ulong = 0x00020000;
   pub const WS_MAXIMIZEBOX:             c_ulong = 0x00010000;
   pub const WS_TILED:                   c_ulong = WS_OVERLAPPED;
   pub const WS_ICONIC:                  c_ulong = WS_MINIMIZE;
   pub const WS_SIZEBOX:                 c_ulong = WS_THICKFRAME;
   pub const WS_TILEDWINDOW:             c_ulong = WS_OVERLAPPEDWINDOW;
   pub const WS_OVERLAPPEDWINDOW:        c_ulong = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
   pub const WS_POPUPWINDOW:             c_ulong = WS_POPUP | WS_BORDER | WS_SYSMENU;
   pub const WS_CHILDWINDOW:             c_ulong = WS_CHILD;

   pub const WS_EX_DLGMODALFRAME:        c_ulong = 0x00000001;
   pub const WS_EX_NOPARENTNOTIFY:       c_ulong = 0x00000004;
   pub const WS_EX_TOPMOST:              c_ulong = 0x00000008;
   pub const WS_EX_ACCEPTFILES:          c_ulong = 0x00000010;
   pub const WS_EX_TRANSPARENT:          c_ulong = 0x00000020;
   pub const WS_EX_MDICHILD:             c_ulong = 0x00000040;
   pub const WS_EX_TOOLWINDOW:           c_ulong = 0x00000080;
   pub const WS_EX_WINDOWEDGE:           c_ulong = 0x00000100;
   pub const WS_EX_CLIENTEDGE:           c_ulong = 0x00000200;
   pub const WS_EX_CONTEXTHELP:          c_ulong = 0x00000400;
   pub const WS_EX_RIGHT:                c_ulong = 0x00001000;
   pub const WS_EX_LEFT:                 c_ulong = 0x00000000;
   pub const WS_EX_RTLREADING:           c_ulong = 0x00002000;
   pub const WS_EX_LTRREADING:           c_ulong = 0x00000000;
   pub const WS_EX_LEFTSCROLLBAR:        c_ulong = 0x00004000;
   pub const WS_EX_RIGHTSCROLLBAR:       c_ulong = 0x00000000;
   pub const WS_EX_CONTROLPARENT:        c_ulong = 0x00010000;
   pub const WS_EX_STATICEDGE:           c_ulong = 0x00020000;
   pub const WS_EX_APPWINDOW:            c_ulong = 0x00040000;
   pub const WS_EX_OVERLAPPEDWINDOW:     c_ulong = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE;
   pub const WS_EX_PALETTEWINDOW:        c_ulong = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
   pub const WS_EX_LAYERED:              c_ulong = 0x00080000;
   pub const WS_EX_NOINHERITLAYOUT:      c_ulong = 0x00100000;
   pub const WS_EX_NOREDIRECTIONBITMAP:  c_ulong = 0x00200000;
   pub const WS_EX_LAYOUTRTL:            c_ulong = 0x00400000;
   pub const WS_EX_COMPOSITED:           c_ulong = 0x02000000;
   pub const WS_EX_NOACTIVATE:           c_ulong = 0x08000000;

   pub const CW_USEDEFAULT:                c_int = 0x80000000u32 as c_int;

   pub const WM_CLOSE:                    c_uint = 16;

   pub const SW_SHOWNORMAL:                c_int = 1;
   pub const SW_SHOWMINIMIZED:             c_int = 2;
   pub const SW_MAXIMIZE:                  c_int = 3;
   pub const SW_SHOWMAXIMIZED:             c_int = 3;
   pub const SW_SHOWNOACTIVATE:            c_int = 4;
   pub const SW_SHOW:                      c_int = 5;
   pub const SW_MINIMIZE:                  c_int = 6;
   pub const SW_SHOWMINNOACTIVE:           c_int = 7;
   pub const SW_SHOWNA:                    c_int = 8;
   pub const SW_RESTORE:                   c_int = 9;
   pub const SW_SHOWDEFAULT:               c_int = 10;
   pub const SW_FORCEMINIMIZE:             c_int = 11;

   #[repr(C)]
   #[derive(Copy)]
   pub struct WNDCLASSEXW {
      pub cbSize: c_uint,
      pub style: c_uint,
      pub lpfnWndProc: WNDPROC,
      pub cbClsExtra: c_int,
      pub cbWndExtra: c_int,
      pub hInstance: HINSTANCE,
      pub hIcon: HICON,
      pub hCursor: HCURSOR,
      pub hbrBackground: HBRUSH,
      pub lpszMenuName: LPCWSTR,
      pub lpszClassName: LPCWSTR,
      pub hIconSm: HICON,
   }
   impl Clone for WNDCLASSEXW {
      fn clone(&self) -> Self { *self }
   }
   impl Default for WNDCLASSEXW {
      fn default() -> Self { unsafe { mem::zeroed() } }
   }

   #[repr(C)]
   #[derive(Copy)]
   pub struct POINT {
      pub x: c_long,
      pub y: c_long,
   }
   impl Clone for POINT {
      fn clone(&self) -> Self { *self }
   }
   impl Default for POINT {
      fn default() -> Self { unsafe { mem::zeroed() } }
   }

   #[repr(C)]
   #[derive(Copy)]
   pub struct MSG {
      pub hwnd: HWND,
      pub message: c_uint,
      pub wParam: WPARAM,
      pub lParam: LPARAM,
      pub time: c_ulong,
      pub pt: POINT,
   }
   impl Clone for MSG {
      fn clone(&self) -> Self { *self }
   }
   impl Default for MSG {
      fn default() -> Self { unsafe { mem::zeroed() } }
   }

   extern "system" {
      pub fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE;

      pub fn RegisterClassExW(lpWndClass: *const WNDCLASSEXW) -> ATOM;

      pub fn ShowWindow(hwnd: HWND, nCmdShow: c_int) -> BOOL;

      pub fn PostQuitMessage(nExitCode: c_int);

      pub fn TranslateMessage(lpmsg: *const MSG) -> BOOL;

      pub fn DispatchMessageW(lpmsg: *const MSG) -> LRESULT;

      pub fn GetDC(hwnd: HWND) -> HDC;

      pub fn DefWindowProcW(
         hwnd: HWND,
         Msg: c_uint,
         wParam: WPARAM,
         lParam: LPARAM
      ) -> LRESULT;

      pub fn CreateWindowExW(
         dwExStyle: c_ulong,
         lpClassName: LPCWSTR,
         lpWindowName: LPCWSTR,
         dwStyle: c_ulong,
         x: c_int,
         y: c_int,
         nWidth: c_int,
         nHeight: c_int,
         hWndParent: HWND,
         hMenu: HMENU,
         hInstance: HINSTANCE,
         lpParam: LPVOID,
      ) -> HWND;

      pub fn GetMessageW(
         lpMsg: *const MSG,
         hwnd: HWND,
         wMsgFilterMin: c_uint,
         wMsgFilterMax: c_uint
      ) -> BOOL;
   }
}

use std::ptr;
use std::mem;
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;

fn to_utf16_os<S: AsRef<OsStr> + ?Sized>(s: &S) -> Vec<u16> {
   let mut v: Vec<_> = OsStr::new(s).encode_wide().collect();
   v.push(0);
   v
}

pub fn register_window_class<S: AsRef<OsStr> + ?Sized>(class_name: &S) {
   unsafe extern "system" fn wnd_proc(
      hwnd: ffi::HWND,
      msg: ffi::c_uint,
      wparam: ffi::WPARAM,
      lparam: ffi::LPARAM
   ) -> ffi::LRESULT {
      match msg {
         ffi::WM_CLOSE => {
            ffi::PostQuitMessage(0);
         },
         _ => {
            return ffi::DefWindowProcW(hwnd, msg, wparam, lparam);
         }
      }

      return 0;
   }

   unsafe {
      let wnd_class = ffi::WNDCLASSEXW {
         cbSize: mem::size_of::<ffi::WNDCLASSEXW>() as ffi::c_uint,
         style: ffi::CS_HREDRAW | ffi::CS_VREDRAW | ffi::CS_OWNDC,
         lpfnWndProc: Some(wnd_proc),
         cbClsExtra: 0,
         cbWndExtra: 0,
         hInstance: ffi::GetModuleHandleW(ptr::null()),
         hIcon: ptr::null_mut(),
         hCursor: ptr::null_mut(),
         hbrBackground: ptr::null_mut(),
         lpszMenuName: ptr::null(),
         lpszClassName: to_utf16_os(class_name).as_ptr(),
         hIconSm: ptr::null_mut(),
      };

      ffi::RegisterClassExW(&wnd_class);
   }
}

pub struct Window {
   pub hwnd: ffi::HWND
}

impl Window {
   pub fn create<S: AsRef<OsStr> + ?Sized>(width: ffi::c_int, height: ffi::c_int, title: &S, class_name: &S) -> Self {
      let hwnd = unsafe {
         ffi::CreateWindowExW(
            ffi::WS_EX_CLIENTEDGE,
            to_utf16_os(class_name).as_ptr(),
            to_utf16_os(title).as_ptr(),
            ffi::WS_OVERLAPPEDWINDOW | ffi::WS_VISIBLE,
            ffi::CW_USEDEFAULT, ffi::CW_USEDEFAULT,
            width, height,
            ptr::null_mut(),
            ptr::null_mut(),
            ffi::GetModuleHandleW(ptr::null()),
            ptr::null_mut()
         )
      };

      Window {
         hwnd: hwnd
      }
   }

   pub fn dc(&self) -> ffi::HDC {
      unsafe {
         ffi::GetDC(self.hwnd)
      }
   }

   pub fn show_normal(&self) {
      unsafe {
         ffi::ShowWindow(self.hwnd, ffi::SW_SHOWNORMAL)
      };
   }
}

pub struct Message {
   msg: ffi::MSG
}

impl Message {
   pub fn get() -> Option<Self> {
      let mut msg = unsafe { mem::uninitialized() };

      match unsafe { ffi::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) } {
         0 => None,
         _ => Some(Message {
            msg: msg
         })
      }
   }

   pub fn translate(&self) {
      unsafe {
         ffi::TranslateMessage(&self.msg)
      };
   }

   pub fn dispatch(&self) {
      unsafe {
         ffi::DispatchMessageW(&self.msg)
      };
   }
}
<|endoftext|>


<commit_before>extern crate time;

//
extern crate termion;
use self::termion::async_stdin;
use std::io::Read;
//

const FRAME_PER_SECOND: i64 = 120;

fn timestamp() -> i64 {
    let current_time = time::get_time();

    current_time.sec*1000 + ( ( current_time.nsec / 1_000_000 ) as i64 )
}

pub struct MainLoop {
    initial_time:        i64,
    time:                i64,
    frame:               i64,
    last_rendered_frame: i64
}

pub trait Gamable {
    fn input_handling( &mut self );
    fn updating( &mut self );
    fn rendering( &self );
}

impl MainLoop {

    pub fn run( game: &mut Gamable ) {
        let mut tmp_main_loop = MainLoop {
            initial_time:        timestamp(),
            time:                0,
            frame:               0,
            last_rendered_frame: 0
        };

        // Здесь!
        let mut stdin = async_stdin().bytes();

        loop {
            let byte = stdin.next();

            if let Some( Ok( b'q' ) ) = byte {
                break;
            }

            game.input_handling();
            tmp_main_loop.update( game );
        }
    }

    #[inline]
    fn update( &mut self, game: &mut Gamable ) {
        self.time = timestamp() - self.initial_time;
        self.frame = self.time*FRAME_PER_SECOND / 1000;

        if self.frame > self.last_rendered_frame {

            //
            game.updating();
            game.rendering();

            //
            self.last_rendered_frame = self.frame;

        }
    }

}<commit_msg>Add termion RawMode<commit_after>extern crate time;

//
extern crate termion;
use self::termion::raw::IntoRawMode;
use self::termion::async_stdin;
use std::io::{Read, stdout};
//

const FRAME_PER_SECOND: i64 = 120;

fn timestamp() -> i64 {
    let current_time = time::get_time();

    current_time.sec*1000 + ( ( current_time.nsec / 1_000_000 ) as i64 )
}

pub struct MainLoop {
    initial_time:        i64,
    time:                i64,
    frame:               i64,
    last_rendered_frame: i64
}

pub trait Gamable {
    fn input_handling( &mut self );
    fn updating( &mut self );
    fn rendering( &self );
}

impl MainLoop {

    pub fn run( game: &mut Gamable ) {
        let mut tmp_main_loop = MainLoop {
            initial_time:        timestamp(),
            time:                0,
            frame:               0,
            last_rendered_frame: 0
        };

        // Здесь!
        let stdout = stdout();
        let mut stdout = stdout.lock().into_raw_mode().unwrap();
        let mut stdin = async_stdin().bytes();

        loop {
            let byte = stdin.next();

            if let Some( Ok( b'q' ) ) = byte {
                break;
            }

            game.input_handling();
            tmp_main_loop.update( game );
        }
    }

    #[inline]
    fn update( &mut self, game: &mut Gamable ) {
        self.time = timestamp() - self.initial_time;
        self.frame = self.time*FRAME_PER_SECOND / 1000;

        if self.frame > self.last_rendered_frame {

            //
            game.updating();
            game.rendering();

            //
            self.last_rendered_frame = self.frame;

        }
    }

}<|endoftext|>


<commit_before>use internal::{FdOptions, PathDisplay, ROOT_DIR};

use std::{fs, process};
use std::io::{self, Write};
use std::ops::Deref;
use std::path::{self, Path, PathBuf, Component};
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;

use ansi_term;

pub fn print_entry(base: &Path, entry: &PathBuf, config: &FdOptions) {
    let path_full = base.join(entry);

    let path_str = entry.to_string_lossy();

    #[cfg(unix)]
    let is_executable = |p: Option<&fs::Metadata>| {
        p.map(|f| f.permissions().mode() & 0o111 != 0).unwrap_or(
            false,
        )
    };

    #[cfg(windows)]
    let is_executable = |_: Option<&fs::Metadata>| false;

    let stdout = io::stdout();
    let mut handle = stdout.lock();

    if let Some(ref ls_colors) = config.ls_colors {
        let default_style = ansi_term::Style::default();

        let mut component_path = base.to_path_buf();

        if config.path_display == PathDisplay::Absolute {
            print!("{}", ls_colors.directory.paint(ROOT_DIR));
        }

        // Traverse the path and colorize each component
        for component in entry.components() {
            let comp_str = component.as_os_str().to_string_lossy();

            component_path.push(Path::new(comp_str.deref()));

            if let Component::RootDir = component {
                // Printing the root dir would result in too many path separators on Windows.
                // Note that a root dir component won't occur on Unix, because `entry` is never an
                // absolute path in that case.
                continue;
            }

            let metadata = component_path.metadata().ok();
            let is_directory = metadata.as_ref().map(|md| md.is_dir()).unwrap_or(false);

            let style = if component_path
                .symlink_metadata()
                .map(|md| md.file_type().is_symlink())
                .unwrap_or(false)
            {
                &ls_colors.symlink
            } else if is_directory {
                &ls_colors.directory
            } else if is_executable(metadata.as_ref()) {
                &ls_colors.executable
            } else {
                // Look up file name
                let o_style = component_path
                    .file_name()
                    .and_then(|n| n.to_str())
                    .and_then(|n| ls_colors.filenames.get(n));

                match o_style {
                        Some(s) => s,
                        None =>
                            // Look up file extension
                            component_path.extension()
                                          .and_then(|e| e.to_str())
                                          .and_then(|e| ls_colors.extensions.get(e))
                                          .unwrap_or(&default_style)
                    }
            };

            write!(handle, "{}", style.paint(comp_str)).ok();

            if is_directory && component_path != path_full {
                let sep = path::MAIN_SEPARATOR.to_string();
                write!(handle, "{}", style.paint(sep)).ok();
            }
        }

        let r = if config.null_separator {
            write!(handle, "\0")
        } else {
            writeln!(handle, "")
        };
        if r.is_err() {
            // Probably a broken pipe. Exit gracefully.
            process::exit(0);
        }
    } else {
        // Uncolorized output

        let prefix = if config.path_display == PathDisplay::Absolute {
            ROOT_DIR
        } else {
            ""
        };
        let separator = if config.null_separator { "\0" } else { "\n" };

        let r = write!(&mut io::stdout(), "{}{}{}", prefix, path_str, separator);

        if r.is_err() {
            // Probably a broken pipe. Exit gracefully.
            process::exit(0);
        }
    }
}
<commit_msg>Split up print_entry in colorized and uncolorized helper functions.<commit_after>use internal::{FdOptions, PathDisplay, ROOT_DIR};
use lscolors::LsColors;

use std::{fs, process};
use std::io::{self, Write};
use std::ops::Deref;
use std::path::{self, Path, PathBuf, Component};
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;

use ansi_term;

pub fn print_entry(base: &Path, entry: &PathBuf, config: &FdOptions) {
    let r = if let Some(ref ls_colors) = config.ls_colors {
        print_entry_colorized(base, entry, config, ls_colors)
    } else {
        print_entry_uncolorized(entry, config)
    };

    if r.is_err() {
        // Probably a broken pipe. Exit gracefully.
        process::exit(0);
    }
}

fn print_entry_colorized(
    base: &Path,
    entry: &PathBuf,
    config: &FdOptions,
    ls_colors: &LsColors,
) -> io::Result<()> {
    let default_style = ansi_term::Style::default();

    let mut component_path = base.to_path_buf();

    let stdout = io::stdout();
    let mut handle = stdout.lock();

    let path_full = base.join(entry);

    if config.path_display == PathDisplay::Absolute {
        write!(handle, "{}", ls_colors.directory.paint(ROOT_DIR))?;
    }

    // Traverse the path and colorize each component
    for component in entry.components() {
        let comp_str = component.as_os_str().to_string_lossy();

        component_path.push(Path::new(comp_str.deref()));

        if let Component::RootDir = component {
            // Printing the root dir would result in too many path separators on Windows.
            // Note that a root dir component won't occur on Unix, because `entry` is never an
            // absolute path in that case.
            continue;
        }

        let metadata = component_path.metadata();
        let is_directory = metadata.as_ref().map(|md| md.is_dir()).unwrap_or(false);

        let style = if component_path
            .symlink_metadata()
            .map(|md| md.file_type().is_symlink())
            .unwrap_or(false)
        {
            &ls_colors.symlink
        } else if is_directory {
            &ls_colors.directory
        } else if metadata.map(|md| is_executable(&md)).unwrap_or(false) {
            &ls_colors.executable
        } else {
            // Look up file name
            let o_style = component_path
                .file_name()
                .and_then(|n| n.to_str())
                .and_then(|n| ls_colors.filenames.get(n));

            match o_style {
                        Some(s) => s,
                        None =>
                            // Look up file extension
                            component_path.extension()
                                          .and_then(|e| e.to_str())
                                          .and_then(|e| ls_colors.extensions.get(e))
                                          .unwrap_or(&default_style)
                    }
        };

        write!(handle, "{}", style.paint(comp_str))?;

        if is_directory && component_path != path_full {
            let sep = path::MAIN_SEPARATOR.to_string();
            write!(handle, "{}", style.paint(sep))?;
        }
    }

    if config.null_separator {
        write!(handle, "\0")
    } else {
        writeln!(handle, "")
    }
}

fn print_entry_uncolorized(entry: &PathBuf, config: &FdOptions) -> io::Result<()> {
    // Uncolorized output
    let prefix = if config.path_display == PathDisplay::Absolute {
        ROOT_DIR
    } else {
        ""
    };
    let separator = if config.null_separator { "\0" } else { "\n" };

    let path_str = entry.to_string_lossy();
    write!(&mut io::stdout(), "{}{}{}", prefix, path_str, separator)
}

#[cfg(unix)]
fn is_executable(md: &fs::Metadata) -> bool {
    md.permissions().mode() & 0o111 != 0
}

#[cfg(windows)]
fn is_executable(_: &fs::Metadata) -> bool {
    false
}
<|endoftext|>


<commit_before>use ast::{Token, Expr};
use ast::{BlockExpr, ThrowExpr, ReturnExpr, CallExpr, ConstructExpr, IfExpr, WhileLoopExpr, SwitchExpr, FunctionDeclExpr, LocalExpr, ArrayDeclExpr, ObjectDeclExpr, GetConstFieldExpr, GetFieldExpr, NumOpExpr, BitOpExpr, ConstExpr};
use ast::{CBool, CNull, CUndefined, CString, CNum};
use ast::{TIdent, TNumber, TString, TSemicolon, TColon, TDot, TOpenParen, TCloseParen, TComma, TOpenBlock, TCloseBlock, TOpenArray, TCloseArray, TQuestion, TNumOp, TBitOp};
use collections::treemap::TreeMap;
use std::fmt;
use std::vec::Vec;
#[deriving(Clone)]
#[deriving(Eq)]
/// An error encountered during parsing an expression
pub enum ParseError {
	/// When it expected a certain kind of token, but got another
	Expected(Vec<Token>, Token),
	/// When it expected a certain expression, but got another
	ExpectedExpr(~str, Expr)
}
impl fmt::Show for ParseError {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		return match *self {
			Expected(ref wanted, ref got) if wanted.len() == 0 => write!(f.buf, "Expected expression, got {}", got),
			Expected(ref wanted, ref got) => {
				try!(write!(f.buf, "Expected "));
				let last = wanted.last().unwrap();
				for wanted_token in wanted.iter() {
					match write!(f.buf, "'{}'{}", wanted_token, if wanted_token == last {""} else {", "}) {
						Err(err) => return Err(err),
						Ok(_) => ()
					}
				}
				write!(f.buf, ", got {}", got)
			},
			ExpectedExpr(ref wanted, ref got) => {
				write!(f.buf, "Expected {}, got {}", wanted, got)
			}
		}
	}
}
/// A result which gives a pretty-printed error if it fails
pub trait VerboseResult<T> {
	/// Unwrap the value if it's Ok and if not pretty-print the error
	fn v_unwrap(&self) -> T;
}
impl<T : Clone, E : fmt::Show> VerboseResult<T> for Result<T, E> {
	fn v_unwrap(&self) -> T {
		match *self {
			Ok(ref val) => val.clone(),
			Err(ref err) => fail!("{}", err)
		}
	}
}
pub type ParseResult = Result<~Expr, ParseError>;
pub type ParseStructResult = Result<Option<~Expr>, ParseError>;
/// A Javascript parser
pub struct Parser {
	/// The tokens being input
	tokens: Vec<Token>,
	/// The current position within the tokens
	pos: uint
}
impl Parser {
	/// Creates a new parser, using [tokens] as input
	pub fn new(tokens: Vec<Token>) -> ~Parser {
		return ~Parser {tokens: tokens, pos: 0};
	}
	/// Parse all expressions in the token array
	pub fn parse_all(&mut self) -> ParseResult {
		let mut exprs = Vec::new();
		while self.pos < self.tokens.len() {
			let result = try!(self.parse());
			exprs.push(result);
		}
		return Ok(~BlockExpr(exprs));
	}
	fn parse_struct(&mut self, name:&str) -> ParseStructResult {
		match name {
			"true" => Ok(Some(~ConstExpr(CBool(true)))),
			"false" => Ok(Some(~ConstExpr(CBool(false)))),
			"null" => Ok(Some(~ConstExpr(CNull))),
			"undefined" => Ok(Some(~ConstExpr(CUndefined))),
			"throw" => {
				let thrown = try!(self.parse());
				Ok(Some(~ThrowExpr(thrown)))
			},
			"return" => Ok(Some(~ReturnExpr(Some(try!(self.parse()))))),
			"new" => {
				let call = try!(self.parse());
				print!("new {}", call);
				match *call {
					CallExpr(ref func, ref args) => Ok(Some(~ConstructExpr(func.clone(), args.clone()))),
					_ => Err(ExpectedExpr(~"constructor", *call))
				}
			}
			"if" => {
				try!(self.expect(TOpenParen));
				let cond = try!(self.parse());
				try!(self.expect(TCloseParen));
				let expr = try!(self.parse());
				let next = self.tokens.get(self.pos + 1).clone();
				Ok(Some(~IfExpr(cond, expr, if next == TIdent(~"else") {
					self.pos += 2;
					Some(try!(self.parse()))
				} else {
					None
				})))
			},
			"while" => {
				try!(self.expect(TOpenParen));
				let cond = try!(self.parse());
				try!(self.expect(TCloseParen));
				let expr = try!(self.parse());
				Ok(Some(~WhileLoopExpr(cond, expr)))
			},
			"switch" => {
				try!(self.expect(TOpenParen));
				let value = self.parse();
				try!(self.expect(TCloseParen));
				try!(self.expect(TOpenBlock));
				let mut cases = Vec::new();
				let mut default = None;
				while self.pos + 1 < self.tokens.len() {
					let tok = self.tokens.get(self.pos).clone();
					self.pos += 1;
					match tok {
						TIdent(ref id) if *id == ~"case" => {
							let cond = self.parse();
							let mut block = Vec::new();
							try!(self.expect(TColon));
							loop {
								match self.tokens.get(self.pos).clone() {
									TIdent(ref id) if *id == ~"case" || *id == ~"default" => break,
									TCloseBlock => break,
									_ => block.push(try!(self.parse()))
								}
							}
							cases.push((cond.unwrap(), block));
						},
						TIdent(ref id) if *id == ~"default" => {
							let mut block = Vec::new();
							try!(self.expect(TColon));
							loop {
								match self.tokens.get(self.pos).clone() {
									TIdent(ref id) if *id == ~"case" || *id == ~"default" => break,
									TCloseBlock => break,
									_ => block.push(try!(self.parse()))
								}
							}
							default = Some(~BlockExpr(block));
						},
						TCloseBlock => break,
						_ => fail!("Expected 'case', 'default' or '{}', not '{}'", '}', tok)
					}
				}
				try!(self.expect(TCloseBlock));
				Ok(Some(~SwitchExpr(value.unwrap(), cases, default)))
			},
			"function" => {
				let tk = self.tokens.get(self.pos).clone();
				let name : Option<~str> = match tk {
					TIdent(ref name) => {
						self.pos += 1;
						Some(name.clone())
					},
					TOpenParen => None,
					_ => return Err(Expected(vec!(TIdent(~"identifier")), tk.clone()))
				};
				try!(self.expect(TOpenParen));
				let mut args:Vec<~str> = Vec::new();
				let mut tk = self.tokens.get(self.pos).clone();
				while tk != TCloseParen {
					match tk {
						TIdent(ref id) => args.push(id.to_owned()),
						_ => return Err(Expected(vec!(TIdent(~"identifier")), tk))
					}
					self.pos += 1;
					if *self.tokens.get(self.pos) == TComma {
						self.pos += 1;
					}
					tk = self.tokens.get(self.pos).clone();
				}
				self.pos += 1;
				let block = try!(self.parse());
				Ok(Some(~FunctionDeclExpr(name, args, block)))
			},
			_ => Ok(None)
		}
	}
	/// Parse a single expression
	pub fn parse(&mut self) -> ParseResult {
		let token = self.tokens.get(self.pos).clone();
		self.pos += 1;
		let expr : ~Expr = match token {
			TSemicolon => try!(self.parse()),
			TIdent(ref s) => {
				let structure = try!(self.parse_struct(s.clone()));
				match structure {
					Some(v) => v,
					None => ~LocalExpr(s.to_owned())
				}
			},
			TString(ref s) => ~ConstExpr(CString(s.to_owned())),
			TOpenParen => {
				let nexte = try!(self.parse());
				try!(self.expect(TCloseParen));
				nexte
			},
			TOpenArray => {
				let mut array = Vec::new();
				let mut expect_comma_or_end = *self.tokens.get(self.pos) == TCloseArray;
				loop {
					let token = self.tokens.get(self.pos).clone();
					if token == TCloseArray && expect_comma_or_end {
						self.pos += 1;
						break;
					} else if token == TComma && expect_comma_or_end {
						expect_comma_or_end = false;
					} else if token == TComma && !expect_comma_or_end {
						array.push(~ConstExpr(CNull));
						expect_comma_or_end = false;
					} else if expect_comma_or_end {
						return Err(Expected(vec!(TComma, TCloseArray), token));
					} else {
						let parsed = try!(self.parse());
						self.pos -= 1;
						array.push(parsed);
						expect_comma_or_end = true;
					}
					self.pos += 1;
				}
				~ArrayDeclExpr(array)
			},
			TOpenBlock if self.tokens.get(self.pos) == &TCloseBlock => {
				self.pos += 1;
				~ObjectDeclExpr(~TreeMap::new())
			},
			TOpenBlock if self.tokens.get(self.pos + 1) == &TColon => {
				let mut map = ~TreeMap::new();
				while self.tokens.get(self.pos - 1) == &TComma || map.len() == 0 {
					let tk = self.tokens.get(self.pos).clone();
					let name = match tk {
						TIdent(ref id) => id,
						TString(ref str) => str,
						_ => return Err(Expected(vec!(TIdent(~"identifier"), TString(~"string")), tk))
					};
					self.pos += 1;
					try!(self.expect(TColon));
					let value = try!(self.parse());
					map.insert(name.to_owned(), value);
					self.pos += 1;
				}
				~ObjectDeclExpr(map)
			},
			TOpenBlock => {
				let mut exprs = Vec::new();
				loop {
					if *self.tokens.get(self.pos) == TCloseBlock {
						break;
					} else {
						exprs.push(try!(self.parse()));
					}
				}
				self.pos += 1;
				~BlockExpr(exprs)
			},
			TNumber(num) => ~ConstExpr(CNum(num)),
			_ => return Err(Expected(Vec::new(), token.clone()))
		};
		return if self.pos >= self.tokens.len() { Ok(expr) } else {self.parse_next(expr)};
	}
	fn parse_next(&mut self, expr:~Expr) -> ParseResult {
		let next = self.tokens.get(self.pos).clone();
		let mut carry_on = true;
		let mut result = expr.clone();
		match next {
			TDot => {
				self.pos += 1;
				let tk = self.tokens.get(self.pos).clone();
				match tk {
					TIdent(ref s) => result = ~GetConstFieldExpr(expr, s.to_owned()),
					_ => return Err(Expected(vec!(TIdent(~"identifier")), next))
				}
				self.pos += 1;
			},
			TOpenParen => {
				let mut args = Vec::new();
				let mut expect_comma_or_end = *self.tokens.get(self.pos + 1) == TCloseParen;
				loop {
					self.pos += 1;
					let token = self.tokens.get(self.pos).clone();
					if token == TCloseParen && expect_comma_or_end {
						self.pos += 1;
						break;
					} else if token == TComma && expect_comma_or_end {
						expect_comma_or_end = false;
					} else if expect_comma_or_end {
						return Err(Expected(vec!(TComma, TCloseParen), token));
					} else {
						let parsed = try!(self.parse());
						self.pos -= 1;
						args.push(parsed);
						expect_comma_or_end = true;
					}
				}
				result = ~CallExpr(expr, args);
			},
			TQuestion => {
				self.pos += 1;
				let if_e = try!(self.parse());
				try!(self.expect(TColon));
				let else_e = try!(self.parse());
				result = ~IfExpr(expr, if_e, Some(else_e));
			},
			TOpenArray => {
				self.pos += 1;
				let index = try!(self.parse());
				try!(self.expect(TCloseArray));
				result = ~GetFieldExpr(expr, index);
			},
			TSemicolon => {
				self.pos += 1;
			},
			TNumOp(op) => {
				self.pos += 1;
				let next = try!(self.parse());
				result = ~NumOpExpr(op, expr, next);
			},
			TBitOp(op) => {
				self.pos += 1;
				let next = try!(self.parse());
				result = ~BitOpExpr(op, expr, next);
			},
			_ => carry_on = false
		};
		return if carry_on && self.pos < self.tokens.len() { self.parse_next(result) } else {Ok(result)};
	}
	/// Returns an error if the next symbol is not [tk]
	fn expect(&mut self, tk:Token) -> Result<(), ParseError> {
		self.pos += 1;
		let curr_tk = self.tokens.get(self.pos - 1).clone();
		return if curr_tk != tk {
			Err(Expected(vec!(tk), curr_tk))
		} else {
			Ok(())
		};
	}
}<commit_msg>Change error messages<commit_after>use ast::{Token, Expr};
use ast::{BlockExpr, ThrowExpr, ReturnExpr, CallExpr, ConstructExpr, IfExpr, WhileLoopExpr, SwitchExpr, FunctionDeclExpr, LocalExpr, ArrayDeclExpr, ObjectDeclExpr, GetConstFieldExpr, GetFieldExpr, NumOpExpr, BitOpExpr, ConstExpr};
use ast::{CBool, CNull, CUndefined, CString, CNum};
use ast::{TIdent, TNumber, TString, TSemicolon, TColon, TDot, TOpenParen, TCloseParen, TComma, TOpenBlock, TCloseBlock, TOpenArray, TCloseArray, TQuestion, TNumOp, TBitOp};
use collections::treemap::TreeMap;
use std::fmt;
use std::vec::Vec;
#[deriving(Clone)]
#[deriving(Eq)]
/// An error encountered during parsing an expression
pub enum ParseError {
	/// When it expected a certain kind of token, but got another
	Expected(Vec<Token>, Token),
	/// When it expected a certain expression, but got another
	ExpectedExpr(~str, Expr)
}
impl fmt::Show for ParseError {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		return match *self {
			Expected(ref wanted, ref got) if wanted.len() == 0 => write!(f.buf, "Expected expression, got {}", got),
			Expected(ref wanted, ref got) => {
				try!(write!(f.buf, "Expected "));
				let last = wanted.last().unwrap();
				for wanted_token in wanted.iter() {
					match write!(f.buf, "'{}'{}", wanted_token, if wanted_token == last {""} else {", "}) {
						Err(err) => return Err(err),
						Ok(_) => ()
					}
				}
				write!(f.buf, " but got {}", got)
			},
			ExpectedExpr(ref wanted, ref got) => {
				write!(f.buf, "Expected {}, but got {}", wanted, got)
			}
		}
	}
}
/// A result which gives a pretty-printed error if it fails
pub trait VerboseResult<T> {
	/// Unwrap the value if it's Ok and if not pretty-print the error
	fn v_unwrap(&self) -> T;
}
impl<T : Clone, E : fmt::Show> VerboseResult<T> for Result<T, E> {
	fn v_unwrap(&self) -> T {
		match *self {
			Ok(ref val) => val.clone(),
			Err(ref err) => fail!("{}", err)
		}
	}
}
pub type ParseResult = Result<~Expr, ParseError>;
pub type ParseStructResult = Result<Option<~Expr>, ParseError>;
/// A Javascript parser
pub struct Parser {
	/// The tokens being input
	tokens: Vec<Token>,
	/// The current position within the tokens
	pos: uint
}
impl Parser {
	/// Creates a new parser, using [tokens] as input
	pub fn new(tokens: Vec<Token>) -> ~Parser {
		return ~Parser {tokens: tokens, pos: 0};
	}
	/// Parse all expressions in the token array
	pub fn parse_all(&mut self) -> ParseResult {
		let mut exprs = Vec::new();
		while self.pos < self.tokens.len() {
			let result = try!(self.parse());
			exprs.push(result);
		}
		return Ok(~BlockExpr(exprs));
	}
	fn parse_struct(&mut self, name:&str) -> ParseStructResult {
		match name {
			"true" => Ok(Some(~ConstExpr(CBool(true)))),
			"false" => Ok(Some(~ConstExpr(CBool(false)))),
			"null" => Ok(Some(~ConstExpr(CNull))),
			"undefined" => Ok(Some(~ConstExpr(CUndefined))),
			"throw" => {
				let thrown = try!(self.parse());
				Ok(Some(~ThrowExpr(thrown)))
			},
			"return" => Ok(Some(~ReturnExpr(Some(try!(self.parse()))))),
			"new" => {
				let call = try!(self.parse());
				print!("new {}", call);
				match *call {
					CallExpr(ref func, ref args) => Ok(Some(~ConstructExpr(func.clone(), args.clone()))),
					_ => Err(ExpectedExpr(~"constructor", *call))
				}
			}
			"if" => {
				try!(self.expect(TOpenParen));
				let cond = try!(self.parse());
				try!(self.expect(TCloseParen));
				let expr = try!(self.parse());
				let next = self.tokens.get(self.pos + 1).clone();
				Ok(Some(~IfExpr(cond, expr, if next == TIdent(~"else") {
					self.pos += 2;
					Some(try!(self.parse()))
				} else {
					None
				})))
			},
			"while" => {
				try!(self.expect(TOpenParen));
				let cond = try!(self.parse());
				try!(self.expect(TCloseParen));
				let expr = try!(self.parse());
				Ok(Some(~WhileLoopExpr(cond, expr)))
			},
			"switch" => {
				try!(self.expect(TOpenParen));
				let value = self.parse();
				try!(self.expect(TCloseParen));
				try!(self.expect(TOpenBlock));
				let mut cases = Vec::new();
				let mut default = None;
				while self.pos + 1 < self.tokens.len() {
					let tok = self.tokens.get(self.pos).clone();
					self.pos += 1;
					match tok {
						TIdent(ref id) if *id == ~"case" => {
							let cond = self.parse();
							let mut block = Vec::new();
							try!(self.expect(TColon));
							loop {
								match self.tokens.get(self.pos).clone() {
									TIdent(ref id) if *id == ~"case" || *id == ~"default" => break,
									TCloseBlock => break,
									_ => block.push(try!(self.parse()))
								}
							}
							cases.push((cond.unwrap(), block));
						},
						TIdent(ref id) if *id == ~"default" => {
							let mut block = Vec::new();
							try!(self.expect(TColon));
							loop {
								match self.tokens.get(self.pos).clone() {
									TIdent(ref id) if *id == ~"case" || *id == ~"default" => break,
									TCloseBlock => break,
									_ => block.push(try!(self.parse()))
								}
							}
							default = Some(~BlockExpr(block));
						},
						TCloseBlock => break,
						_ => fail!("Expected 'case', 'default' or '{}', not '{}'", '}', tok)
					}
				}
				try!(self.expect(TCloseBlock));
				Ok(Some(~SwitchExpr(value.unwrap(), cases, default)))
			},
			"function" => {
				let tk = self.tokens.get(self.pos).clone();
				let name : Option<~str> = match tk {
					TIdent(ref name) => {
						self.pos += 1;
						Some(name.clone())
					},
					TOpenParen => None,
					_ => return Err(Expected(vec!(TIdent(~"identifier")), tk.clone()))
				};
				try!(self.expect(TOpenParen));
				let mut args:Vec<~str> = Vec::new();
				let mut tk = self.tokens.get(self.pos).clone();
				while tk != TCloseParen {
					match tk {
						TIdent(ref id) => args.push(id.to_owned()),
						_ => return Err(Expected(vec!(TIdent(~"identifier")), tk))
					}
					self.pos += 1;
					if *self.tokens.get(self.pos) == TComma {
						self.pos += 1;
					}
					tk = self.tokens.get(self.pos).clone();
				}
				self.pos += 1;
				let block = try!(self.parse());
				Ok(Some(~FunctionDeclExpr(name, args, block)))
			},
			_ => Ok(None)
		}
	}
	/// Parse a single expression
	pub fn parse(&mut self) -> ParseResult {
		let token = self.tokens.get(self.pos).clone();
		self.pos += 1;
		let expr : ~Expr = match token {
			TSemicolon => try!(self.parse()),
			TIdent(ref s) => {
				let structure = try!(self.parse_struct(s.clone()));
				match structure {
					Some(v) => v,
					None => ~LocalExpr(s.to_owned())
				}
			},
			TString(ref s) => ~ConstExpr(CString(s.to_owned())),
			TOpenParen => {
				let nexte = try!(self.parse());
				try!(self.expect(TCloseParen));
				nexte
			},
			TOpenArray => {
				let mut array = Vec::new();
				let mut expect_comma_or_end = *self.tokens.get(self.pos) == TCloseArray;
				loop {
					let token = self.tokens.get(self.pos).clone();
					if token == TCloseArray && expect_comma_or_end {
						self.pos += 1;
						break;
					} else if token == TComma && expect_comma_or_end {
						expect_comma_or_end = false;
					} else if token == TComma && !expect_comma_or_end {
						array.push(~ConstExpr(CNull));
						expect_comma_or_end = false;
					} else if expect_comma_or_end {
						return Err(Expected(vec!(TComma, TCloseArray), token));
					} else {
						let parsed = try!(self.parse());
						self.pos -= 1;
						array.push(parsed);
						expect_comma_or_end = true;
					}
					self.pos += 1;
				}
				~ArrayDeclExpr(array)
			},
			TOpenBlock if self.tokens.get(self.pos) == &TCloseBlock => {
				self.pos += 1;
				~ObjectDeclExpr(~TreeMap::new())
			},
			TOpenBlock if self.tokens.get(self.pos + 1) == &TColon => {
				let mut map = ~TreeMap::new();
				while self.tokens.get(self.pos - 1) == &TComma || map.len() == 0 {
					let tk = self.tokens.get(self.pos).clone();
					let name = match tk {
						TIdent(ref id) => id,
						TString(ref str) => str,
						_ => return Err(Expected(vec!(TIdent(~"identifier"), TString(~"string")), tk))
					};
					self.pos += 1;
					try!(self.expect(TColon));
					let value = try!(self.parse());
					map.insert(name.to_owned(), value);
					self.pos += 1;
				}
				~ObjectDeclExpr(map)
			},
			TOpenBlock => {
				let mut exprs = Vec::new();
				loop {
					if *self.tokens.get(self.pos) == TCloseBlock {
						break;
					} else {
						exprs.push(try!(self.parse()));
					}
				}
				self.pos += 1;
				~BlockExpr(exprs)
			},
			TNumber(num) => ~ConstExpr(CNum(num)),
			_ => return Err(Expected(Vec::new(), token.clone()))
		};
		return if self.pos >= self.tokens.len() { Ok(expr) } else {self.parse_next(expr)};
	}
	fn parse_next(&mut self, expr:~Expr) -> ParseResult {
		let next = self.tokens.get(self.pos).clone();
		let mut carry_on = true;
		let mut result = expr.clone();
		match next {
			TDot => {
				self.pos += 1;
				let tk = self.tokens.get(self.pos).clone();
				match tk {
					TIdent(ref s) => result = ~GetConstFieldExpr(expr, s.to_owned()),
					_ => return Err(Expected(vec!(TIdent(~"identifier")), next))
				}
				self.pos += 1;
			},
			TOpenParen => {
				let mut args = Vec::new();
				let mut expect_comma_or_end = *self.tokens.get(self.pos + 1) == TCloseParen;
				loop {
					self.pos += 1;
					let token = self.tokens.get(self.pos).clone();
					if token == TCloseParen && expect_comma_or_end {
						self.pos += 1;
						break;
					} else if token == TComma && expect_comma_or_end {
						expect_comma_or_end = false;
					} else if expect_comma_or_end {
						return Err(Expected(vec!(TComma, TCloseParen), token));
					} else {
						let parsed = try!(self.parse());
						self.pos -= 1;
						args.push(parsed);
						expect_comma_or_end = true;
					}
				}
				result = ~CallExpr(expr, args);
			},
			TQuestion => {
				self.pos += 1;
				let if_e = try!(self.parse());
				try!(self.expect(TColon));
				let else_e = try!(self.parse());
				result = ~IfExpr(expr, if_e, Some(else_e));
			},
			TOpenArray => {
				self.pos += 1;
				let index = try!(self.parse());
				try!(self.expect(TCloseArray));
				result = ~GetFieldExpr(expr, index);
			},
			TSemicolon => {
				self.pos += 1;
			},
			TNumOp(op) => {
				self.pos += 1;
				let next = try!(self.parse());
				result = ~NumOpExpr(op, expr, next);
			},
			TBitOp(op) => {
				self.pos += 1;
				let next = try!(self.parse());
				result = ~BitOpExpr(op, expr, next);
			},
			_ => carry_on = false
		};
		return if carry_on && self.pos < self.tokens.len() { self.parse_next(result) } else {Ok(result)};
	}
	/// Returns an error if the next symbol is not [tk]
	fn expect(&mut self, tk:Token) -> Result<(), ParseError> {
		self.pos += 1;
		let curr_tk = self.tokens.get(self.pos - 1).clone();
		return if curr_tk != tk {
			Err(Expected(vec!(tk), curr_tk))
		} else {
			Ok(())
		};
	}
}<|endoftext|>


<commit_before>//! The `parser` module contains structures and functions for parsing the VQA
//! (Vector Quantized Animation) format.
//!
//! Information on the VQA format found at:
//!
//! * https://wiki.multimedia.cx/index.php/VQA#Technical_Description
//! * https://multimedia.cx/HC-VQA.TXT

use nom::{be_u32, le_u8, le_u16, le_u32, IResult};

#[derive(Debug)]
pub struct FormChunk {
    pub size: u32
}

named!(pub form_chunk<FormChunk>,
    do_parse!(
        tag!("FORM") >>
        size: be_u32 >>
        (FormChunk {
            size: size
        })
    )
);

#[derive(Debug)]
pub enum VQAVersion {
    One,
    Two,
    Three
}

named!(pub vqa_version<VQAVersion>,
    switch!(le_u16,
        1 => value!(VQAVersion::One) |
        2 => value!(VQAVersion::Two) |
        3 => value!(VQAVersion::Three)
    )
);

bitflags! {
    pub struct VQAFlags: u16 {
        const HAS_SOUND = 0b00000001;
    }
}

#[derive(Debug)]
pub struct VQAHeader {
    pub version       : VQAVersion, // VQA version number
    pub flags         : VQAFlags,   // VQA flags
    pub num_frames    : u16,        // Number of frames
    pub width         : u16,        // Movie width (pixels)
    pub height        : u16,        // Movie height (pixels)
    pub block_width   : u8,         // Width of each image block (pixels)
    pub block_height  : u8,         // Height of each image block (pixels)
    pub frame_rate    : u8,         // Frame rate of the VQA
    pub cbparts       : u8,         // How many images use the same lookup table
    pub colors        : u16,        // Max number of colors used in VQA
    pub maxblocks     : u16,        // Max number of image blocks
    pub unk1          : u32,        // Always 0?
    pub unk2          : u16,        // Some kind of size?
    pub freq          : u16,        // Sound sampling frequency
    pub channels      : u8,         // Number of sound channels
    pub bits          : u8,         // Sound resolution
    pub unk3          : u32,        // Always 0?
    pub unk4          : u16,        // 0 in old VQAs, 4 in HiColor VQAs?
    pub max_cbfz_size : u32,        // 0 in old VQAs, CBFZ size in HiColor
    pub unk5          : u32,        // Always 0?
}

named!(pub vqa_header<VQAHeader>,
    do_parse!(
        tag!("VQHD")              >>
        tag!(b"\x00\x00\x00\x2a") >> // VQAHeader is always 42 bytes long
        version: vqa_version      >>
        flags: le_u16             >>
        num_frames: le_u16        >>
        width: le_u16             >>
        height: le_u16            >>
        block_width: le_u8        >>
        block_height: le_u8       >>
        frame_rate: le_u8         >>
        cbparts: le_u8            >>
        colors: le_u16            >>
        maxblocks: le_u16         >>
        unk1: le_u32              >>
        unk2: le_u16              >>
        freq: le_u16              >>
        channels: le_u8           >>
        bits: le_u8               >>
        unk3: le_u32              >>
        unk4: le_u16              >>
        max_cbfz_size: le_u32     >>
        unk5: le_u32              >>
        (VQAHeader {
            version: version,
            flags: VQAFlags::from_bits_truncate(flags),
            num_frames: num_frames,
            width: width,
            height: height,
            block_width: block_width,
            block_height: block_height,
            frame_rate: frame_rate,
            cbparts: cbparts,
            colors: colors,
            maxblocks: maxblocks,
            unk1: unk1,
            unk2: unk2,
            freq: freq,
            channels: channels,
            bits: bits,
            unk3: unk3,
            unk4: unk4,
            max_cbfz_size: max_cbfz_size,
            unk5: unk5
        })
    )
);

#[derive(Debug)]
pub struct FINFChunk {
    pub size: u32,
    pub offsets: Vec<u32>
}

named!(pub finf_chunk<FINFChunk>,
    do_parse!(
        tag!("FINF") >>
        size: be_u32 >>
        offsets: many_m_n!(size as usize / 4, size as usize / 4, le_u32) >>
        (FINFChunk {
            size: size,
            offsets: offsets
        })
    )
);<commit_msg>add snd2_chunk parser<commit_after>//! The `parser` module contains structures and functions for parsing the VQA
//! (Vector Quantized Animation) format.
//!
//! Information on the VQA format found at:
//!
//! * https://wiki.multimedia.cx/index.php/VQA#Technical_Description
//! * https://multimedia.cx/HC-VQA.TXT

use nom::{be_u32, le_u8, le_u16, le_u32, IResult};

#[derive(Debug)]
pub struct FormChunk {
    pub size: u32
}

named!(pub form_chunk<FormChunk>,
    do_parse!(
        tag!("FORM") >>
        size: be_u32 >>
        (FormChunk {
            size: size
        })
    )
);

#[derive(Debug)]
pub enum VQAVersion {
    One,
    Two,
    Three
}

named!(pub vqa_version<VQAVersion>,
    switch!(le_u16,
        1 => value!(VQAVersion::One) |
        2 => value!(VQAVersion::Two) |
        3 => value!(VQAVersion::Three)
    )
);

bitflags! {
    pub struct VQAFlags: u16 {
        const HAS_SOUND = 0b00000001;
    }
}

#[derive(Debug)]
pub struct VQAHeader {
    pub version       : VQAVersion, // VQA version number
    pub flags         : VQAFlags,   // VQA flags
    pub num_frames    : u16,        // Number of frames
    pub width         : u16,        // Movie width (pixels)
    pub height        : u16,        // Movie height (pixels)
    pub block_width   : u8,         // Width of each image block (pixels)
    pub block_height  : u8,         // Height of each image block (pixels)
    pub frame_rate    : u8,         // Frame rate of the VQA
    pub cbparts       : u8,         // How many images use the same lookup table
    pub colors        : u16,        // Max number of colors used in VQA
    pub maxblocks     : u16,        // Max number of image blocks
    pub unk1          : u32,        // Always 0?
    pub unk2          : u16,        // Some kind of size?
    pub freq          : u16,        // Sound sampling frequency
    pub channels      : u8,         // Number of sound channels
    pub bits          : u8,         // Sound resolution
    pub unk3          : u32,        // Always 0?
    pub unk4          : u16,        // 0 in old VQAs, 4 in HiColor VQAs?
    pub max_cbfz_size : u32,        // 0 in old VQAs, CBFZ size in HiColor
    pub unk5          : u32,        // Always 0?
}

named!(pub vqa_header<VQAHeader>,
    do_parse!(
        tag!("VQHD")              >>
        tag!(b"\x00\x00\x00\x2a") >> // VQAHeader is always 42 bytes long
        version: vqa_version      >>
        flags: le_u16             >>
        num_frames: le_u16        >>
        width: le_u16             >>
        height: le_u16            >>
        block_width: le_u8        >>
        block_height: le_u8       >>
        frame_rate: le_u8         >>
        cbparts: le_u8            >>
        colors: le_u16            >>
        maxblocks: le_u16         >>
        unk1: le_u32              >>
        unk2: le_u16              >>
        freq: le_u16              >>
        channels: le_u8           >>
        bits: le_u8               >>
        unk3: le_u32              >>
        unk4: le_u16              >>
        max_cbfz_size: le_u32     >>
        unk5: le_u32              >>
        (VQAHeader {
            version: version,
            flags: VQAFlags::from_bits_truncate(flags),
            num_frames: num_frames,
            width: width,
            height: height,
            block_width: block_width,
            block_height: block_height,
            frame_rate: frame_rate,
            cbparts: cbparts,
            colors: colors,
            maxblocks: maxblocks,
            unk1: unk1,
            unk2: unk2,
            freq: freq,
            channels: channels,
            bits: bits,
            unk3: unk3,
            unk4: unk4,
            max_cbfz_size: max_cbfz_size,
            unk5: unk5
        })
    )
);

#[derive(Debug)]
pub struct FINFChunk {
    pub offsets: Vec<u32>
}

named!(pub finf_chunk<FINFChunk>,
    do_parse!(
        tag!("FINF") >>
        size: be_u32 >>
        offsets: many_m_n!(size as usize / 4, size as usize / 4, le_u32) >>
        (FINFChunk {
            offsets: offsets
        })
    )
);

#[derive(Debug)]
pub struct SND2Chunk<'a> {
    pub data: &'a [u8]
}

named!(pub snd2_chunk<SND2Chunk>,
    do_parse!(
        tag!("SND2")       >>
        size: be_u32       >>
        data: take!(size)  >>
        (SND2Chunk {
            data: data
        })
    )
);<|endoftext|>


<commit_before>use std::collections::HashMap;
use lexer::{Token, Tokens};
use error::ParserError;

type Operators = HashMap<&'static str, Operator>;

#[derive(PartialEq, Debug)]
enum Associativity {
    LeftToRight,
    RightToLeft,
}

#[derive(PartialEq, Debug)]
struct Operator(usize, Associativity);

impl Operator {
    fn new(precedence: usize, associativity: Associativity) -> Operator {
        Operator(precedence, associativity)
    }
}

pub struct Parser {
    operators: Operators,
    stack: Tokens,
    output: Tokens,
}

impl Parser {
    fn new() -> Parser {
        Parser {
            operators: Operators::new(),
            stack: Tokens::with_capacity(3),
            output: Tokens::with_capacity(3),
        }
    }

    fn lower_precedence(&self, new_token: &Token, top_token: &Token) -> bool {
        let &Operator(new_token_prec, ref new_token_assoc) = match *new_token {
            Token::Operator(ref new_token_name) => {
                self.operators.get::<str>(&new_token_name).unwrap()
            }
            _ => unreachable!(),
        };

        let &Operator(top_token_prec, _) = match *top_token {
            Token::Operator(ref top_token_name) => {
                self.operators.get::<str>(&top_token_name).unwrap()
            }
            _ => unreachable!(),
        };

        (*new_token_assoc == Associativity::LeftToRight && new_token_prec <= top_token_prec) ||
        (*new_token_assoc == Associativity::RightToLeft && new_token_prec < top_token_prec)
    }

    pub fn parse(&mut self, tokens: &Tokens) -> Result<&Tokens, ParserError> {
        self.reset_parser();

        let mut iter = tokens.iter().peekable();
        while let Some(&(position, ref token)) = iter.next() {
            match *token {
                Token::Decimal(_) => self.output.push((position, token.clone())),
                Token::Operator(ref name) => {
                    if !self.operators.contains_key::<str>(&name) {
                        return Err(ParserError::IllegalOperator(position));
                    }

                    loop {
                        match self.stack.last() {
                            Some(&(_, Token::Operator(_))) => {
                                if self.lower_precedence(&token, &self.stack.last().unwrap().1) {
                                    self.output.push(self.stack.pop().unwrap());
                                } else {
                                    break;
                                }
                            }
                            _ => break,
                        }
                    }

                    self.stack.push((position, token.clone()));
                }
                Token::OpenBracket => self.stack.push((position, token.clone())),
                Token::CloseBracket => {
                    let mut found = false;

                    loop {
                        match self.stack.last() {
                            Some(&(_, Token::OpenBracket)) => {
                                found = true;
                                self.stack.pop();
                                break;
                            }
                            None => break,
                            _ => self.output.push(self.stack.pop().unwrap()),
                        }
                    }
                    if !found {
                        return Err(ParserError::MissingOpeningBracket(position));
                    }
                }
                Token::Unknown(_) => {
                    return Err(ParserError::IllegalOperator(position));
                }
                _ => continue,

            }
        }
        loop {
            match self.stack.last() {
                Some(&(position, Token::OpenBracket)) => {
                    return Err(ParserError::MissingClosingBracket(position))
                }
                Some(_) => self.output.push(self.stack.pop().unwrap()),
                None => break,
            }
        }

        Ok((&self.output))
    }

    fn reset_parser(&mut self) {
        self.stack.clear();
        self.output.clear();
    }
}

impl Default for Parser {
    fn default() -> Parser {
        let mut parser = Parser::new();

        parser.operators.insert("~", Operator::new(2, Associativity::RightToLeft));
        parser.operators.insert(">>", Operator::new(3, Associativity::LeftToRight));
        parser.operators.insert("<<", Operator::new(3, Associativity::LeftToRight));
        parser.operators.insert("&", Operator::new(4, Associativity::LeftToRight));
        parser.operators.insert("^", Operator::new(5, Associativity::LeftToRight));
        parser.operators.insert("|", Operator::new(6, Associativity::LeftToRight));

        parser
    }
}
<commit_msg>Bugfix: Fix confusion over operator associativity resulting in backwards precedence<commit_after>use std::collections::HashMap;
use lexer::{Token, Tokens};
use error::ParserError;

type Operators = HashMap<&'static str, Operator>;

#[derive(PartialEq, Debug)]
enum Associativity {
    LeftToRight,
    RightToLeft,
}

#[derive(PartialEq, Debug)]
struct Operator(usize, Associativity);

impl Operator {
    fn new(precedence: usize, associativity: Associativity) -> Operator {
        Operator(precedence, associativity)
    }
}

pub struct Parser {
    operators: Operators,
    stack: Tokens,
    output: Tokens,
}

impl Parser {
    fn new() -> Parser {
        Parser {
            operators: Operators::new(),
            stack: Tokens::with_capacity(3),
            output: Tokens::with_capacity(3),
        }
    }

    fn lower_precedence(&self, new_token: &Token, top_token: &Token) -> bool {
        let &Operator(new_token_prec, ref new_token_assoc) = match *new_token {
            Token::Operator(ref new_token_name) => {
                self.operators.get::<str>(&new_token_name).unwrap()
            }
            _ => unreachable!(),
        };

        let &Operator(top_token_prec, _) = match *top_token {
            Token::Operator(ref top_token_name) => {
                self.operators.get::<str>(&top_token_name).unwrap()
            }
            _ => unreachable!(),
        };

        (*new_token_assoc == Associativity::LeftToRight && new_token_prec > top_token_prec) ||
        (*new_token_assoc == Associativity::RightToLeft && new_token_prec >= top_token_prec)
    }

    pub fn parse(&mut self, tokens: &Tokens) -> Result<&Tokens, ParserError> {
        self.reset_parser();

        let mut iter = tokens.iter().peekable();
        while let Some(&(position, ref token)) = iter.next() {
            match *token {
                Token::Decimal(_) => self.output.push((position, token.clone())),
                Token::Operator(ref name) => {
                    if !self.operators.contains_key::<str>(&name) {
                        return Err(ParserError::IllegalOperator(position));
                    }

                    loop {
                        match self.stack.last() {
                            Some(&(_, Token::Operator(_))) => {
                                if self.lower_precedence(&token, &self.stack.last().unwrap().1) {
                                    self.output.push(self.stack.pop().unwrap());
                                } else {
                                    break;
                                }
                            }
                            _ => break,
                        }
                    }

                    self.stack.push((position, token.clone()));
                }
                Token::OpenBracket => self.stack.push((position, token.clone())),
                Token::CloseBracket => {
                    let mut found = false;

                    loop {
                        match self.stack.last() {
                            Some(&(_, Token::OpenBracket)) => {
                                found = true;
                                self.stack.pop();
                                break;
                            }
                            None => break,
                            _ => self.output.push(self.stack.pop().unwrap()),
                        }
                    }
                    if !found {
                        return Err(ParserError::MissingOpeningBracket(position));
                    }
                }
                Token::Unknown(_) => {
                    return Err(ParserError::IllegalOperator(position));
                }
                _ => continue,

            }
        }
        loop {
            match self.stack.last() {
                Some(&(position, Token::OpenBracket)) => {
                    return Err(ParserError::MissingClosingBracket(position))
                }
                Some(_) => self.output.push(self.stack.pop().unwrap()),
                None => break,
            }
        }

        Ok((&self.output))
    }

    fn reset_parser(&mut self) {
        self.stack.clear();
        self.output.clear();
    }
}

impl Default for Parser {
    fn default() -> Parser {
        let mut parser = Parser::new();

        parser.operators.insert("~", Operator::new(2, Associativity::RightToLeft));
        parser.operators.insert(">>", Operator::new(3, Associativity::LeftToRight));
        parser.operators.insert("<<", Operator::new(3, Associativity::LeftToRight));
        parser.operators.insert("&", Operator::new(4, Associativity::LeftToRight));
        parser.operators.insert("^", Operator::new(5, Associativity::LeftToRight));
        parser.operators.insert("|", Operator::new(6, Associativity::LeftToRight));

        parser
    }
}
<|endoftext|>