<commit_before>use std::cmp;
use std::borrow::Cow;
use std::path::Path;
use std::path::PathBuf;
use std::io::Write;
use std::fs::{File, rename};
use std::sync::{Mutex, Arc};

use tempdir::TempDir;

use buffer::{Buffer, Mark};
use uibuf::{UIBuffer, CharColor};
use frontends::Frontend;
use overlay::{Overlay, OverlayType};
use utils;
use textobject::{Anchor, TextObject, Kind, Offset};

/// A View is an abstract Window (into a Buffer).
///
/// It draws a portion of a Buffer to a UIBuffer which in turn is drawn to the
/// screen. It maintains the status bar for the current view, the "dirty status"
/// which is whether the buffer has been modified or not and a number of other
/// pieces of information.
pub struct View {
    pub buffer: Arc<Mutex<Buffer>>,
    pub last_buffer: Option<Arc<Mutex<Buffer>>>,
    pub overlay: Overlay,

    /// First character of the top line to be displayed
    top_line: Mark,

    /// Index into the top_line - used for horizontal scrolling
    left_col: usize,

    /// The current View's cursor - a reference into the Buffer
    cursor: Mark,

    /// The UIBuffer to which the View is drawn
    uibuf: UIBuffer,

    /// Number of lines from the top/bottom of the View after which vertical
    /// scrolling begins.
    threshold: usize,
}

impl View {

    pub fn new(buffer: Arc<Mutex<Buffer>>, width: usize, height: usize) -> View {
        let cursor = Mark::Cursor(0);
        let top_line = Mark::DisplayMark(0);

        {
            let mut b = buffer.lock().unwrap();

            b.set_mark(cursor, 0);
            b.set_mark(top_line, 0);
        }

        View {
            buffer: buffer,
            last_buffer: None,
            top_line: top_line,
            left_col: 0,
            cursor: cursor,
            uibuf: UIBuffer::new(width, height),
            overlay: Overlay::None,
            threshold: 5,
        }
    }

    pub fn set_buffer(&mut self, buffer: Arc<Mutex<Buffer>>) {
        self.last_buffer = Some(self.buffer.clone());

        {
            let mut b = buffer.lock().unwrap();

            b.set_mark(self.cursor, 0);
            b.set_mark(self.top_line, 0);
        }

        self.buffer = buffer;
    }

    pub fn switch_last_buffer(&mut self) {
        let buffer = self.buffer.clone();
        let last_buffer = match self.last_buffer.clone() {
            Some(buf) => buf,
            None => return
        };

        self.buffer = last_buffer;
        self.last_buffer = Some(buffer);
    }

    /// Get the height of the View.
    ///
    /// This is the height of the UIBuffer minus the status bar height.
    pub fn get_height(&self) -> usize {
        let status_bar_height = 1;
        let uibuf_height = self.uibuf.get_height();

        uibuf_height - status_bar_height
    }

    /// Get the width of the View.
    pub fn get_width(&self) -> usize {
        self.uibuf.get_width()
    }

    /// Resize the view
    ///
    /// This involves simply changing the size of the associated UIBuffer
    pub fn resize(&mut self, width: usize, height: usize) {
        let uibuf = UIBuffer::new(width, height);
        self.uibuf = uibuf;
    }

    /// Clear the buffer
    ///
    /// Fills every cell in the UIBuffer with the space (' ') char.
    pub fn clear<T: Frontend>(&mut self, frontend: &mut T) {
        self.uibuf.fill(' ');
        self.uibuf.draw_everything(frontend);
    }

    pub fn draw<T: Frontend>(&mut self, frontend: &mut T) {
        {
            let buffer = self.buffer.lock().unwrap();
            let height = self.get_height() - 1;

            // FIXME: don't use unwrap here
            //        This will fail if for some reason the buffer doesnt have
            //        the top_line mark
            let mut lines = buffer.lines_from(self.top_line).unwrap().take(height);
            for y_position in 0..height {
                let line = lines.next().unwrap_or(vec![]);
                draw_line(&mut self.uibuf, line.as_slice(), y_position, self.left_col);
            }

        }
        match self.overlay {
            Overlay::None => self.draw_cursor(frontend),
            _ => {
                self.overlay.draw(frontend, &mut self.uibuf);
                self.overlay.draw_cursor(frontend);
            }
        }
        self.draw_status(frontend);
        self.uibuf.draw_everything(frontend);
    }

    fn draw_status<T: Frontend>(&mut self, frontend: &mut T) {
        let buffer = self.buffer.lock().unwrap();
        let buffer_status = buffer.status_text();
        let mut cursor_status = buffer.get_mark_coords(self.cursor).unwrap_or((0,0));
        cursor_status = (cursor_status.0 + 1, cursor_status.1 + 1);
        let status_text = format!("{} ({}, {})", buffer_status, cursor_status.0, cursor_status.1).into_bytes();
        let status_text_len = status_text.len();
        let width = self.get_width();
        let height = self.get_height() - 1;

        for index in 0..width {
            let mut ch: char = ' ';
            if index < status_text_len {
                ch = status_text[index] as char;
            }
            self.uibuf.update_cell(index, height, ch, CharColor::Black, CharColor::Blue);
        }

        self.uibuf.draw_range(frontend, height, height+1);
    }

    fn draw_cursor<T: Frontend>(&mut self, frontend: &mut T) {
        let buffer = self.buffer.lock().unwrap();
        if let Some(top_line) = buffer.get_mark_coords(self.top_line) {
            if let Some((x, y)) = buffer.get_mark_coords(self.cursor) {
                frontend.draw_cursor((x - self.left_col) as isize, y as isize - top_line.1 as isize);
            }
        }
    }

    pub fn set_overlay(&mut self, overlay_type: OverlayType) {
        match overlay_type {
            OverlayType::Prompt => {
                self.overlay = Overlay::Prompt {
                    cursor_x: 1,
                    prefix: ":",
                    data: String::new(),
                };
            }

            OverlayType::SelectFile => {
                let prefix = "Enter file path:";

                self.overlay = Overlay::SelectFile {
                    cursor_x: prefix.len(),
                    prefix: prefix,
                    data: String::new(),
                };
            }
            _ => {}
        }
    }

    pub fn move_mark(&mut self, mark: Mark, object: TextObject) {
        self.buffer.lock().unwrap().set_mark_to_object(mark, object);
        self.maybe_move_screen();
    }

    /// Update the top_line mark if necessary to keep the cursor on the screen.
    fn maybe_move_screen(&mut self) {
        let mut buffer = self.buffer.lock().unwrap();
        if let (Some(cursor), Some((_, top_line))) = (buffer.get_mark_coords(self.cursor),
                                                      buffer.get_mark_coords(self.top_line)) {

            let width  = (self.get_width()  - self.threshold) as isize;
            let height = (self.get_height() - self.threshold) as isize;

            //left-right shifting
            self.left_col = match cursor.0 as isize - self.left_col as isize {
                x_offset if x_offset < self.threshold as isize => {
                    cmp::max(0, self.left_col as isize - (self.threshold as isize - x_offset)) as usize
                }
                x_offset if x_offset >= width => {
                    self.left_col + (x_offset - width + 1) as usize
                }
                _ => { self.left_col }
            };

            //up-down shifting
            match cursor.1 as isize - top_line as isize {
                y_offset if y_offset < self.threshold as isize && top_line > 0 => {
                    let amount = (self.threshold as isize - y_offset) as usize;
                    let obj = TextObject {
                        kind: Kind::Line(Anchor::Same),
                        offset: Offset::Backward(amount, self.top_line)
                    };
                    buffer.set_mark_to_object(self.top_line, obj);
                }
                y_offset if y_offset >= height => {
                    let amount = (y_offset - height + 1) as usize;
                    let obj = TextObject {
                        kind: Kind::Line(Anchor::Same),
                        offset: Offset::Forward(amount, self.top_line)
                    };
                    buffer.set_mark_to_object(self.top_line, obj);
                }
                _ => { }
            }
        }
    }

    // Delete chars from the first index of object to the last index of object
    pub fn delete_object(&mut self, object: TextObject) {
        self.buffer.lock().unwrap().remove_object(object);
    }

    pub fn delete_from_mark_to_object(&mut self, mark: Mark, object: TextObject) {
        let mut buffer = self.buffer.lock().unwrap();
        if let Some((idx, _)) = buffer.get_object_index(object) {
            if let Some(midx) = buffer.get_mark_idx(mark) {
                buffer.remove_from_mark_to_object(mark, object);
                buffer.set_mark(mark, cmp::min(idx, midx));
            }
        }
    }

    /// Insert a chacter into the buffer & update cursor position accordingly.
    pub fn insert_char(&mut self, ch: char) {
        self.buffer.lock().unwrap().insert_char(self.cursor, ch as u8);
        // NOTE: the last param to char_width here may not be correct
        if let Some(ch_width) = utils::char_width(ch, false, 4, 1) {
            let obj = TextObject {
                kind: Kind::Char,
                offset: Offset::Forward(ch_width, Mark::Cursor(0))
            };
            self.move_mark(Mark::Cursor(0), obj)
        }
    }

    pub fn undo(&mut self) {
        {
            let mut buffer = self.buffer.lock().unwrap();
            let point = if let Some(transaction) = buffer.undo() { transaction.end_point }
                        else { return; };
            buffer.set_mark(self.cursor, point);
        }
        self.maybe_move_screen();
    }

    pub fn redo(&mut self) {
        {
            let mut buffer = self.buffer.lock().unwrap();
            let point = if let Some(transaction) = buffer.redo() { transaction.end_point }
                        else { return; };
            buffer.set_mark(self.cursor, point);
        }
        self.maybe_move_screen();
    }

    fn save_buffer(&mut self) {
        let buffer = self.buffer.lock().unwrap();
        let path = match buffer.file_path {
            Some(ref p) => Cow::Borrowed(p),
            None => {
                // NOTE: this should never happen, as the file path
                // should have been set inside the try_save_buffer method.
                //
                // If this runs, it probably means save_buffer has been called
                // directly, rather than try_save_buffer.
                //
                // TODO: ask the user to submit a bug report on how they hit this.
                Cow::Owned(PathBuf::from("untitled"))
            },
        };
        let tmpdir = match TempDir::new_in(&Path::new("."), "iota") {
            Ok(d) => d,
            Err(e) => panic!("file error: {}", e)
        };

        let tmppath = tmpdir.path().join(Path::new("tmpfile"));
        let mut file = match File::create(&tmppath) {
            Ok(f) => f,
            Err(e) => {
                panic!("file error: {}", e)
            }
        };

        //TODO (lee): Is iteration still necessary in this format?
        for line in buffer.lines() {
            let result = file.write_all(&*line);

            if result.is_err() {
                // TODO(greg): figure out what to do here.
                panic!("Something went wrong while writing the file");
            }
        }

        if let Err(e) = rename(&tmppath, &*path) {
            panic!("file error: {}", e);
        }
    }

    pub fn try_save_buffer(&mut self) {
        let mut should_save = false;
        {
            let buffer = self.buffer.lock().unwrap();

            match buffer.file_path {
                Some(_) => { should_save = true }
                None => {
                    let prefix = "Enter file name: ";
                    self.overlay = Overlay::SavePrompt {
                        cursor_x: prefix.len(),
                        prefix: prefix,
                        data: String::new(),
                    };
                },
            }
        }

        if should_save { self.save_buffer() }
    }

}

pub fn draw_line(buf: &mut UIBuffer, line: &[u8], idx: usize, left: usize) {
    let width = buf.get_width() - 1;
    let mut wide_chars = 0;
    for line_idx in left..(left + width) {
        if line_idx < line.len() {
            let special_char = line[line_idx] as char;
            match special_char {
                '\t'   => {
                    let w = 4 - line_idx % 4;
                    for _ in 0..w {
                        buf.update_cell_content(line_idx + wide_chars - left, idx, ' ');
                    }
                }
                '\n'   => buf.update_cell_content(line_idx + wide_chars - left, idx, ' '),
                _       => buf.update_cell_content(line_idx + wide_chars - left, idx,
                                                   line[line_idx] as char),
            }
            wide_chars += (line[line_idx] as char).width(false).unwrap_or(1) - 1;
        } else { buf.update_cell_content(line_idx + wide_chars - left, idx, ' '); }
    }
    if line.len() >= width {
        buf.update_cell_content(width + wide_chars, idx, '→');
    }

}

#[cfg(test)]
mod tests {

    use std::sync::{Arc, Mutex};

    use view::View;
    use input::Input;
    use buffer::Buffer;

    fn setup_view(testcase: &'static str) -> View {
        let mut buffer = Arc::new(Mutex::new(Buffer::new()));
        let mut view = View::new(buffer.clone(), 50, 50);
        for ch in testcase.chars() {
            view.insert_char(ch);
        }

        let mut buffer = buffer.lock().unwrap();
        buffer.set_mark(view.cursor, 0);
        view
    }

    #[test]
    fn test_insert_char() {
        let mut view = setup_view("test\nsecond");
        view.insert_char('t');

        {
            let mut buffer = view.buffer.lock().unwrap();
            assert_eq!(buffer.lines().next().unwrap(), b"ttest\n");
        }
    }
}
<commit_msg>fix arrow indicator at end of line not getting cleared, also fix displaying tab characters and some unicode characters in the same line<commit_after>use std::cmp;
use std::borrow::Cow;
use std::path::Path;
use std::path::PathBuf;
use std::io::Write;
use std::fs::{File, rename};
use std::sync::{Mutex, Arc};

use tempdir::TempDir;

use buffer::{Buffer, Mark};
use uibuf::{UIBuffer, CharColor};
use frontends::Frontend;
use overlay::{Overlay, OverlayType};
use utils;
use textobject::{Anchor, TextObject, Kind, Offset};

/// A View is an abstract Window (into a Buffer).
///
/// It draws a portion of a Buffer to a UIBuffer which in turn is drawn to the
/// screen. It maintains the status bar for the current view, the "dirty status"
/// which is whether the buffer has been modified or not and a number of other
/// pieces of information.
pub struct View {
    pub buffer: Arc<Mutex<Buffer>>,
    pub last_buffer: Option<Arc<Mutex<Buffer>>>,
    pub overlay: Overlay,

    /// First character of the top line to be displayed
    top_line: Mark,

    /// Index into the top_line - used for horizontal scrolling
    left_col: usize,

    /// The current View's cursor - a reference into the Buffer
    cursor: Mark,

    /// The UIBuffer to which the View is drawn
    uibuf: UIBuffer,

    /// Number of lines from the top/bottom of the View after which vertical
    /// scrolling begins.
    threshold: usize,
}

impl View {

    pub fn new(buffer: Arc<Mutex<Buffer>>, width: usize, height: usize) -> View {
        let cursor = Mark::Cursor(0);
        let top_line = Mark::DisplayMark(0);

        {
            let mut b = buffer.lock().unwrap();

            b.set_mark(cursor, 0);
            b.set_mark(top_line, 0);
        }

        View {
            buffer: buffer,
            last_buffer: None,
            top_line: top_line,
            left_col: 0,
            cursor: cursor,
            uibuf: UIBuffer::new(width, height),
            overlay: Overlay::None,
            threshold: 5,
        }
    }

    pub fn set_buffer(&mut self, buffer: Arc<Mutex<Buffer>>) {
        self.last_buffer = Some(self.buffer.clone());

        {
            let mut b = buffer.lock().unwrap();

            b.set_mark(self.cursor, 0);
            b.set_mark(self.top_line, 0);
        }

        self.buffer = buffer;
    }

    pub fn switch_last_buffer(&mut self) {
        let buffer = self.buffer.clone();
        let last_buffer = match self.last_buffer.clone() {
            Some(buf) => buf,
            None => return
        };

        self.buffer = last_buffer;
        self.last_buffer = Some(buffer);
    }

    /// Get the height of the View.
    ///
    /// This is the height of the UIBuffer minus the status bar height.
    pub fn get_height(&self) -> usize {
        let status_bar_height = 1;
        let uibuf_height = self.uibuf.get_height();

        uibuf_height - status_bar_height
    }

    /// Get the width of the View.
    pub fn get_width(&self) -> usize {
        self.uibuf.get_width()
    }

    /// Resize the view
    ///
    /// This involves simply changing the size of the associated UIBuffer
    pub fn resize(&mut self, width: usize, height: usize) {
        let uibuf = UIBuffer::new(width, height);
        self.uibuf = uibuf;
    }

    /// Clear the buffer
    ///
    /// Fills every cell in the UIBuffer with the space (' ') char.
    pub fn clear<T: Frontend>(&mut self, frontend: &mut T) {
        self.uibuf.fill(' ');
        self.uibuf.draw_everything(frontend);
    }

    pub fn draw<T: Frontend>(&mut self, frontend: &mut T) {
        {
            let buffer = self.buffer.lock().unwrap();
            let height = self.get_height() - 1;

            // FIXME: don't use unwrap here
            //        This will fail if for some reason the buffer doesnt have
            //        the top_line mark
            let mut lines = buffer.lines_from(self.top_line).unwrap().take(height);
            for y_position in 0..height {
                let line = lines.next().unwrap_or(vec![]);
                draw_line(&mut self.uibuf, line.as_slice(), y_position, self.left_col);
            }

        }
        match self.overlay {
            Overlay::None => self.draw_cursor(frontend),
            _ => {
                self.overlay.draw(frontend, &mut self.uibuf);
                self.overlay.draw_cursor(frontend);
            }
        }
        self.draw_status(frontend);
        self.uibuf.draw_everything(frontend);
    }

    fn draw_status<T: Frontend>(&mut self, frontend: &mut T) {
        let buffer = self.buffer.lock().unwrap();
        let buffer_status = buffer.status_text();
        let mut cursor_status = buffer.get_mark_coords(self.cursor).unwrap_or((0,0));
        cursor_status = (cursor_status.0 + 1, cursor_status.1 + 1);
        let status_text = format!("{} ({}, {})", buffer_status, cursor_status.0, cursor_status.1).into_bytes();
        let status_text_len = status_text.len();
        let width = self.get_width();
        let height = self.get_height() - 1;

        for index in 0..width {
            let mut ch: char = ' ';
            if index < status_text_len {
                ch = status_text[index] as char;
            }
            self.uibuf.update_cell(index, height, ch, CharColor::Black, CharColor::Blue);
        }

        self.uibuf.draw_range(frontend, height, height+1);
    }

    fn draw_cursor<T: Frontend>(&mut self, frontend: &mut T) {
        let buffer = self.buffer.lock().unwrap();
        if let Some(top_line) = buffer.get_mark_coords(self.top_line) {
            if let Some((x, y)) = buffer.get_mark_coords(self.cursor) {
                frontend.draw_cursor((x - self.left_col) as isize, y as isize - top_line.1 as isize);
            }
        }
    }

    pub fn set_overlay(&mut self, overlay_type: OverlayType) {
        match overlay_type {
            OverlayType::Prompt => {
                self.overlay = Overlay::Prompt {
                    cursor_x: 1,
                    prefix: ":",
                    data: String::new(),
                };
            }

            OverlayType::SelectFile => {
                let prefix = "Enter file path:";

                self.overlay = Overlay::SelectFile {
                    cursor_x: prefix.len(),
                    prefix: prefix,
                    data: String::new(),
                };
            }
            _ => {}
        }
    }

    pub fn move_mark(&mut self, mark: Mark, object: TextObject) {
        self.buffer.lock().unwrap().set_mark_to_object(mark, object);
        self.maybe_move_screen();
    }

    /// Update the top_line mark if necessary to keep the cursor on the screen.
    fn maybe_move_screen(&mut self) {
        let mut buffer = self.buffer.lock().unwrap();
        if let (Some(cursor), Some((_, top_line))) = (buffer.get_mark_coords(self.cursor),
                                                      buffer.get_mark_coords(self.top_line)) {

            let width  = (self.get_width()  - self.threshold) as isize;
            let height = (self.get_height() - self.threshold) as isize;

            //left-right shifting
            self.left_col = match cursor.0 as isize - self.left_col as isize {
                x_offset if x_offset < self.threshold as isize => {
                    cmp::max(0, self.left_col as isize - (self.threshold as isize - x_offset)) as usize
                }
                x_offset if x_offset >= width => {
                    self.left_col + (x_offset - width + 1) as usize
                }
                _ => { self.left_col }
            };

            //up-down shifting
            match cursor.1 as isize - top_line as isize {
                y_offset if y_offset < self.threshold as isize && top_line > 0 => {
                    let amount = (self.threshold as isize - y_offset) as usize;
                    let obj = TextObject {
                        kind: Kind::Line(Anchor::Same),
                        offset: Offset::Backward(amount, self.top_line)
                    };
                    buffer.set_mark_to_object(self.top_line, obj);
                }
                y_offset if y_offset >= height => {
                    let amount = (y_offset - height + 1) as usize;
                    let obj = TextObject {
                        kind: Kind::Line(Anchor::Same),
                        offset: Offset::Forward(amount, self.top_line)
                    };
                    buffer.set_mark_to_object(self.top_line, obj);
                }
                _ => { }
            }
        }
    }

    // Delete chars from the first index of object to the last index of object
    pub fn delete_object(&mut self, object: TextObject) {
        self.buffer.lock().unwrap().remove_object(object);
    }

    pub fn delete_from_mark_to_object(&mut self, mark: Mark, object: TextObject) {
        let mut buffer = self.buffer.lock().unwrap();
        if let Some((idx, _)) = buffer.get_object_index(object) {
            if let Some(midx) = buffer.get_mark_idx(mark) {
                buffer.remove_from_mark_to_object(mark, object);
                buffer.set_mark(mark, cmp::min(idx, midx));
            }
        }
    }

    /// Insert a chacter into the buffer & update cursor position accordingly.
    pub fn insert_char(&mut self, ch: char) {
        self.buffer.lock().unwrap().insert_char(self.cursor, ch as u8);
        // NOTE: the last param to char_width here may not be correct
        if let Some(ch_width) = utils::char_width(ch, false, 4, 1) {
            let obj = TextObject {
                kind: Kind::Char,
                offset: Offset::Forward(ch_width, Mark::Cursor(0))
            };
            self.move_mark(Mark::Cursor(0), obj)
        }
    }

    pub fn undo(&mut self) {
        {
            let mut buffer = self.buffer.lock().unwrap();
            let point = if let Some(transaction) = buffer.undo() { transaction.end_point }
                        else { return; };
            buffer.set_mark(self.cursor, point);
        }
        self.maybe_move_screen();
    }

    pub fn redo(&mut self) {
        {
            let mut buffer = self.buffer.lock().unwrap();
            let point = if let Some(transaction) = buffer.redo() { transaction.end_point }
                        else { return; };
            buffer.set_mark(self.cursor, point);
        }
        self.maybe_move_screen();
    }

    fn save_buffer(&mut self) {
        let buffer = self.buffer.lock().unwrap();
        let path = match buffer.file_path {
            Some(ref p) => Cow::Borrowed(p),
            None => {
                // NOTE: this should never happen, as the file path
                // should have been set inside the try_save_buffer method.
                //
                // If this runs, it probably means save_buffer has been called
                // directly, rather than try_save_buffer.
                //
                // TODO: ask the user to submit a bug report on how they hit this.
                Cow::Owned(PathBuf::from("untitled"))
            },
        };
        let tmpdir = match TempDir::new_in(&Path::new("."), "iota") {
            Ok(d) => d,
            Err(e) => panic!("file error: {}", e)
        };

        let tmppath = tmpdir.path().join(Path::new("tmpfile"));
        let mut file = match File::create(&tmppath) {
            Ok(f) => f,
            Err(e) => {
                panic!("file error: {}", e)
            }
        };

        //TODO (lee): Is iteration still necessary in this format?
        for line in buffer.lines() {
            let result = file.write_all(&*line);

            if result.is_err() {
                // TODO(greg): figure out what to do here.
                panic!("Something went wrong while writing the file");
            }
        }

        if let Err(e) = rename(&tmppath, &*path) {
            panic!("file error: {}", e);
        }
    }

    pub fn try_save_buffer(&mut self) {
        let mut should_save = false;
        {
            let buffer = self.buffer.lock().unwrap();

            match buffer.file_path {
                Some(_) => { should_save = true }
                None => {
                    let prefix = "Enter file name: ";
                    self.overlay = Overlay::SavePrompt {
                        cursor_x: prefix.len(),
                        prefix: prefix,
                        data: String::new(),
                    };
                },
            }
        }

        if should_save { self.save_buffer() }
    }

}

pub fn draw_line(buf: &mut UIBuffer, line: &[u8], idx: usize, left: usize) {
    let width = buf.get_width() - 1;
    let mut x = 0;

    for ch in line.iter().skip(left).take(width) {
        let ch = *ch as char;
        match ch {
            '\t' => {
                let w = 4 - x % 4;
                for _ in 0..w {
                    buf.update_cell_content(x, idx, ' ');
                    x += 1;
                }
            }
            '\n' => {}
            _ => {
                buf.update_cell_content(x, idx, ch);
                x += ch.width(false).unwrap_or(1);
            }
        }
    }

    // Replace any cells after end of line with ' '
    while x < width {
        buf.update_cell_content(x, idx, ' ');
        x += 1;
    }

    // If the line is too long to fit on the screen, show an indicator
    let indicator = if line.len() > width + left { '→' } else { ' ' };
    buf.update_cell_content(width, idx, indicator);
}

#[cfg(test)]
mod tests {

    use std::sync::{Arc, Mutex};

    use view::View;
    use input::Input;
    use buffer::Buffer;

    fn setup_view(testcase: &'static str) -> View {
        let mut buffer = Arc::new(Mutex::new(Buffer::new()));
        let mut view = View::new(buffer.clone(), 50, 50);
        for ch in testcase.chars() {
            view.insert_char(ch);
        }

        let mut buffer = buffer.lock().unwrap();
        buffer.set_mark(view.cursor, 0);
        view
    }

    #[test]
    fn test_insert_char() {
        let mut view = setup_view("test\nsecond");
        view.insert_char('t');

        {
            let mut buffer = view.buffer.lock().unwrap();
            assert_eq!(buffer.lines().next().unwrap(), b"ttest\n");
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

// Detecting language items.
//
// Language items are items that represent concepts intrinsic to the language
// itself. Examples are:
//
// * Traits that specify "kinds"; e.g. "Freeze", "Send".
//
// * Traits that represent operators; e.g. "Add", "Sub", "Index".
//
// * Functions called by the compiler itself.

use driver::session::Session;
use metadata::csearch::each_lang_item;
use middle::ty::{BuiltinBound, BoundFreeze, BoundPod, BoundSend, BoundSized};
use syntax::ast;
use syntax::ast_util::local_def;
use syntax::attr::AttrMetaMethods;
use syntax::visit;
use syntax::visit::Visitor;

use std::hashmap::HashMap;
use std::iter::Enumerate;
use std::vec;

// The actual lang items defined come at the end of this file in one handy table.
// So you probably just want to nip down to the end.
macro_rules! lets_do_this {
    (
        There are $num_lang_items:expr lang items.
        $( $num:pat, $variant:ident, $name:expr, $method:ident; )*
    ) => {

pub enum LangItem {
    $($variant),*
}

pub struct LanguageItems {
    items: [Option<ast::DefId>, ..$num_lang_items]
}

impl LanguageItems {
    pub fn new() -> LanguageItems {
        LanguageItems {
            items: [ None, ..$num_lang_items ]
        }
    }

    pub fn items<'a>(&'a self) -> Enumerate<vec::Items<'a, Option<ast::DefId>>> {
        self.items.iter().enumerate()
    }

    pub fn item_name(index: uint) -> &'static str {
        match index {
            $( $num => $name, )*
            _ => "???"
        }
    }

    pub fn require(&self, it: LangItem) -> Result<ast::DefId, ~str> {
        match self.items[it as uint] {
            Some(id) => Ok(id),
            None => Err(format!("requires `{}` lang_item",
                             LanguageItems::item_name(it as uint)))
        }
    }

    pub fn to_builtin_kind(&self, id: ast::DefId) -> Option<BuiltinBound> {
        if Some(id) == self.freeze_trait() {
            Some(BoundFreeze)
        } else if Some(id) == self.send_trait() {
            Some(BoundSend)
        } else if Some(id) == self.sized_trait() {
            Some(BoundSized)
        } else if Some(id) == self.pod_trait() {
            Some(BoundPod)
        } else {
            None
        }
    }

    $(
        pub fn $method(&self) -> Option<ast::DefId> {
            self.items[$variant as uint]
        }
    )*
}

struct LanguageItemCollector {
    items: LanguageItems,

    session: Session,

    item_refs: HashMap<&'static str, uint>,
}

struct LanguageItemVisitor<'a> {
    this: &'a mut LanguageItemCollector,
}

impl<'a> Visitor<()> for LanguageItemVisitor<'a> {
    fn visit_item(&mut self, item: &ast::Item, _: ()) {
        match extract(item.attrs) {
            Some(value) => {
                let item_index = self.this.item_refs.find_equiv(&value).map(|x| *x);

                match item_index {
                    Some(item_index) => {
                        self.this.collect_item(item_index, local_def(item.id))
                    }
                    None => {}
                }
            }
            None => {}
        }

        visit::walk_item(self, item, ());
    }
}

impl LanguageItemCollector {
    pub fn new(session: Session) -> LanguageItemCollector {
        let mut item_refs = HashMap::new();

        $( item_refs.insert($name, $variant as uint); )*

        LanguageItemCollector {
            session: session,
            items: LanguageItems::new(),
            item_refs: item_refs
        }
    }

    pub fn collect_item(&mut self, item_index: uint, item_def_id: ast::DefId) {
        // Check for duplicates.
        match self.items.items[item_index] {
            Some(original_def_id) if original_def_id != item_def_id => {
                self.session.err(format!("duplicate entry for `{}`",
                                      LanguageItems::item_name(item_index)));
            }
            Some(_) | None => {
                // OK.
            }
        }

        // Matched.
        self.items.items[item_index] = Some(item_def_id);
    }

    pub fn collect_local_language_items(&mut self, crate: &ast::Crate) {
        let mut v = LanguageItemVisitor { this: self };
        visit::walk_crate(&mut v, crate, ());
    }

    pub fn collect_external_language_items(&mut self) {
        let crate_store = self.session.cstore;
        crate_store.iter_crate_data(|crate_number, _crate_metadata| {
            each_lang_item(crate_store, crate_number, |node_id, item_index| {
                let def_id = ast::DefId { crate: crate_number, node: node_id };
                self.collect_item(item_index, def_id);
                true
            });
        })
    }

    pub fn collect(&mut self, crate: &ast::Crate) {
        self.collect_local_language_items(crate);
        self.collect_external_language_items();
    }
}

pub fn extract(attrs: &[ast::Attribute]) -> Option<@str> {
    for attribute in attrs.iter() {
        match attribute.name_str_pair() {
            Some((key, value)) if "lang" == key => {
                return Some(value);
            }
            Some(..) | None => {}
        }
    }

    return None;
}

pub fn collect_language_items(crate: &ast::Crate,
                              session: Session)
                           -> LanguageItems {
    let mut collector = LanguageItemCollector::new(session);
    collector.collect(crate);
    let LanguageItemCollector { items, .. } = collector;
    session.abort_if_errors();
    items
}

// End of the macro
    }
}

lets_do_this! {
    There are 40 lang items.

//  ID, Variant name,                    Name,                      Method name;
    0,  FreezeTraitLangItem,             "freeze",                  freeze_trait;
    1,  SendTraitLangItem,               "send",                    send_trait;
    2,  SizedTraitLangItem,              "sized",                   sized_trait;
    3,  PodTraitLangItem,                "pod",                     pod_trait;

    4,  DropTraitLangItem,               "drop",                    drop_trait;

    5,  AddTraitLangItem,                "add",                     add_trait;
    6,  SubTraitLangItem,                "sub",                     sub_trait;
    7,  MulTraitLangItem,                "mul",                     mul_trait;
    8,  DivTraitLangItem,                "div",                     div_trait;
    9,  RemTraitLangItem,                "rem",                     rem_trait;
    10, NegTraitLangItem,                "neg",                     neg_trait;
    11, NotTraitLangItem,                "not",                     not_trait;
    12, BitXorTraitLangItem,             "bitxor",                  bitxor_trait;
    13, BitAndTraitLangItem,             "bitand",                  bitand_trait;
    14, BitOrTraitLangItem,              "bitor",                   bitor_trait;
    15, ShlTraitLangItem,                "shl",                     shl_trait;
    16, ShrTraitLangItem,                "shr",                     shr_trait;
    17, IndexTraitLangItem,              "index",                   index_trait;

    18, EqTraitLangItem,                 "eq",                      eq_trait;
    19, OrdTraitLangItem,                "ord",                     ord_trait;

    20, StrEqFnLangItem,                 "str_eq",                  str_eq_fn;
    21, UniqStrEqFnLangItem,             "uniq_str_eq",             uniq_str_eq_fn;
    22, FailFnLangItem,                  "fail_",                   fail_fn;
    23, FailBoundsCheckFnLangItem,       "fail_bounds_check",       fail_bounds_check_fn;
    24, ExchangeMallocFnLangItem,        "exchange_malloc",         exchange_malloc_fn;
    25, ClosureExchangeMallocFnLangItem, "closure_exchange_malloc", closure_exchange_malloc_fn;
    26, ExchangeFreeFnLangItem,          "exchange_free",           exchange_free_fn;
    27, MallocFnLangItem,                "malloc",                  malloc_fn;
    28, FreeFnLangItem,                  "free",                    free_fn;
    29, StrDupUniqFnLangItem,            "strdup_uniq",             strdup_uniq_fn;

    30, StartFnLangItem,                 "start",                   start_fn;

    31, TyDescStructLangItem,            "ty_desc",                 ty_desc;
    32, TyVisitorTraitLangItem,          "ty_visitor",              ty_visitor;
    33, OpaqueStructLangItem,            "opaque",                  opaque;

    34, EventLoopFactoryLangItem,        "event_loop_factory",      event_loop_factory;

    35, TypeIdLangItem,                  "type_id",                 type_id;

    36, EhPersonalityLangItem,           "eh_personality",          eh_personality_fn;

    37, ManagedHeapLangItem,             "managed_heap",            managed_heap;
    38, ExchangeHeapLangItem,            "exchange_heap",           exchange_heap;
    39, GcLangItem,                      "gc",                      gc;
}

<commit_msg>auto merge of #11657 : huonw/rust/less-lang-duplication, r=cmr<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

// Detecting language items.
//
// Language items are items that represent concepts intrinsic to the language
// itself. Examples are:
//
// * Traits that specify "kinds"; e.g. "Freeze", "Send".
//
// * Traits that represent operators; e.g. "Add", "Sub", "Index".
//
// * Functions called by the compiler itself.

use driver::session::Session;
use metadata::csearch::each_lang_item;
use middle::ty::{BuiltinBound, BoundFreeze, BoundPod, BoundSend, BoundSized};
use syntax::ast;
use syntax::ast_util::local_def;
use syntax::attr::AttrMetaMethods;
use syntax::visit;
use syntax::visit::Visitor;

use std::hashmap::HashMap;
use std::iter::Enumerate;
use std::vec;

// Get the last "argument" (has to be done recursively to avoid phoney local ambiguity error)
macro_rules! last {
    ( $first:expr, $( $remainder:expr, )+ ) => ( last!( $( $remainder, )+ ) );
    ( $first:expr, ) => ( $first )
}

// The actual lang items defined come at the end of this file in one handy table.
// So you probably just want to nip down to the end.
macro_rules! lets_do_this {
    // secondary rule to allow us to use `$num` as both an expression
    // and a pattern.
    (
        $( $num:tt, $variant:ident, $name:expr, $method:ident; )*
    ) => {
        lets_do_this!(count = 1 + last!($($num,)*),
                      $($num, $variant, $name, $method; )*)
    };

    (
        count = $num_lang_items:expr, $( $num:pat, $variant:ident, $name:expr, $method:ident; )*
    ) => {

pub enum LangItem {
    $($variant),*
}

pub struct LanguageItems {
    items: [Option<ast::DefId>, ..$num_lang_items]
}

impl LanguageItems {
    pub fn new() -> LanguageItems {
        LanguageItems {
            items: [ None, ..$num_lang_items ]
        }
    }

    pub fn items<'a>(&'a self) -> Enumerate<vec::Items<'a, Option<ast::DefId>>> {
        self.items.iter().enumerate()
    }

    pub fn item_name(index: uint) -> &'static str {
        match index {
            $( $num => $name, )*
            _ => "???"
        }
    }

    pub fn require(&self, it: LangItem) -> Result<ast::DefId, ~str> {
        match self.items[it as uint] {
            Some(id) => Ok(id),
            None => Err(format!("requires `{}` lang_item",
                             LanguageItems::item_name(it as uint)))
        }
    }

    pub fn to_builtin_kind(&self, id: ast::DefId) -> Option<BuiltinBound> {
        if Some(id) == self.freeze_trait() {
            Some(BoundFreeze)
        } else if Some(id) == self.send_trait() {
            Some(BoundSend)
        } else if Some(id) == self.sized_trait() {
            Some(BoundSized)
        } else if Some(id) == self.pod_trait() {
            Some(BoundPod)
        } else {
            None
        }
    }

    $(
        pub fn $method(&self) -> Option<ast::DefId> {
            self.items[$variant as uint]
        }
    )*
}

struct LanguageItemCollector {
    items: LanguageItems,

    session: Session,

    item_refs: HashMap<&'static str, uint>,
}

struct LanguageItemVisitor<'a> {
    this: &'a mut LanguageItemCollector,
}

impl<'a> Visitor<()> for LanguageItemVisitor<'a> {
    fn visit_item(&mut self, item: &ast::Item, _: ()) {
        match extract(item.attrs) {
            Some(value) => {
                let item_index = self.this.item_refs.find_equiv(&value).map(|x| *x);

                match item_index {
                    Some(item_index) => {
                        self.this.collect_item(item_index, local_def(item.id))
                    }
                    None => {}
                }
            }
            None => {}
        }

        visit::walk_item(self, item, ());
    }
}

impl LanguageItemCollector {
    pub fn new(session: Session) -> LanguageItemCollector {
        let mut item_refs = HashMap::new();

        $( item_refs.insert($name, $variant as uint); )*

        LanguageItemCollector {
            session: session,
            items: LanguageItems::new(),
            item_refs: item_refs
        }
    }

    pub fn collect_item(&mut self, item_index: uint, item_def_id: ast::DefId) {
        // Check for duplicates.
        match self.items.items[item_index] {
            Some(original_def_id) if original_def_id != item_def_id => {
                self.session.err(format!("duplicate entry for `{}`",
                                      LanguageItems::item_name(item_index)));
            }
            Some(_) | None => {
                // OK.
            }
        }

        // Matched.
        self.items.items[item_index] = Some(item_def_id);
    }

    pub fn collect_local_language_items(&mut self, crate: &ast::Crate) {
        let mut v = LanguageItemVisitor { this: self };
        visit::walk_crate(&mut v, crate, ());
    }

    pub fn collect_external_language_items(&mut self) {
        let crate_store = self.session.cstore;
        crate_store.iter_crate_data(|crate_number, _crate_metadata| {
            each_lang_item(crate_store, crate_number, |node_id, item_index| {
                let def_id = ast::DefId { crate: crate_number, node: node_id };
                self.collect_item(item_index, def_id);
                true
            });
        })
    }

    pub fn collect(&mut self, crate: &ast::Crate) {
        self.collect_local_language_items(crate);
        self.collect_external_language_items();
    }
}

pub fn extract(attrs: &[ast::Attribute]) -> Option<@str> {
    for attribute in attrs.iter() {
        match attribute.name_str_pair() {
            Some((key, value)) if "lang" == key => {
                return Some(value);
            }
            Some(..) | None => {}
        }
    }

    return None;
}

pub fn collect_language_items(crate: &ast::Crate,
                              session: Session)
                           -> LanguageItems {
    let mut collector = LanguageItemCollector::new(session);
    collector.collect(crate);
    let LanguageItemCollector { items, .. } = collector;
    session.abort_if_errors();
    items
}

// End of the macro
    }
}

lets_do_this! {
//  ID, Variant name,                    Name,                      Method name;
    0,  FreezeTraitLangItem,             "freeze",                  freeze_trait;
    1,  SendTraitLangItem,               "send",                    send_trait;
    2,  SizedTraitLangItem,              "sized",                   sized_trait;
    3,  PodTraitLangItem,                "pod",                     pod_trait;

    4,  DropTraitLangItem,               "drop",                    drop_trait;

    5,  AddTraitLangItem,                "add",                     add_trait;
    6,  SubTraitLangItem,                "sub",                     sub_trait;
    7,  MulTraitLangItem,                "mul",                     mul_trait;
    8,  DivTraitLangItem,                "div",                     div_trait;
    9,  RemTraitLangItem,                "rem",                     rem_trait;
    10, NegTraitLangItem,                "neg",                     neg_trait;
    11, NotTraitLangItem,                "not",                     not_trait;
    12, BitXorTraitLangItem,             "bitxor",                  bitxor_trait;
    13, BitAndTraitLangItem,             "bitand",                  bitand_trait;
    14, BitOrTraitLangItem,              "bitor",                   bitor_trait;
    15, ShlTraitLangItem,                "shl",                     shl_trait;
    16, ShrTraitLangItem,                "shr",                     shr_trait;
    17, IndexTraitLangItem,              "index",                   index_trait;

    18, EqTraitLangItem,                 "eq",                      eq_trait;
    19, OrdTraitLangItem,                "ord",                     ord_trait;

    20, StrEqFnLangItem,                 "str_eq",                  str_eq_fn;
    21, UniqStrEqFnLangItem,             "uniq_str_eq",             uniq_str_eq_fn;
    22, FailFnLangItem,                  "fail_",                   fail_fn;
    23, FailBoundsCheckFnLangItem,       "fail_bounds_check",       fail_bounds_check_fn;
    24, ExchangeMallocFnLangItem,        "exchange_malloc",         exchange_malloc_fn;
    25, ClosureExchangeMallocFnLangItem, "closure_exchange_malloc", closure_exchange_malloc_fn;
    26, ExchangeFreeFnLangItem,          "exchange_free",           exchange_free_fn;
    27, MallocFnLangItem,                "malloc",                  malloc_fn;
    28, FreeFnLangItem,                  "free",                    free_fn;
    29, StrDupUniqFnLangItem,            "strdup_uniq",             strdup_uniq_fn;

    30, StartFnLangItem,                 "start",                   start_fn;

    31, TyDescStructLangItem,            "ty_desc",                 ty_desc;
    32, TyVisitorTraitLangItem,          "ty_visitor",              ty_visitor;
    33, OpaqueStructLangItem,            "opaque",                  opaque;

    34, EventLoopFactoryLangItem,        "event_loop_factory",      event_loop_factory;

    35, TypeIdLangItem,                  "type_id",                 type_id;

    36, EhPersonalityLangItem,           "eh_personality",          eh_personality_fn;

    37, ManagedHeapLangItem,             "managed_heap",            managed_heap;
    38, ExchangeHeapLangItem,            "exchange_heap",           exchange_heap;
    39, GcLangItem,                      "gc",                      gc;
}
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

use lib::llvm::Attribute;
use std::option;
use middle::trans::context::CrateContext;
use middle::trans::cabi_x86;
use middle::trans::cabi_x86_64;
use middle::trans::cabi_arm;
use middle::trans::cabi_mips;
use middle::trans::type_::Type;
use syntax::abi::{X86, X86_64, Arm, Mips};

#[deriving(Clone, Eq)]
pub enum ArgKind {
    /// Pass the argument directly using the normal converted
    /// LLVM type or by coercing to another specified type
    Direct,
    /// Pass the argument indirectly via a hidden pointer
    Indirect,
    /// Ignore the argument (useful for empty struct)
    Ignore,
}

/// Information about how a specific C type
/// should be passed to or returned from a function
///
/// This is borrowed from clang's ABIInfo.h
#[deriving(Clone)]
pub struct ArgType {
    pub kind: ArgKind,
    /// Original LLVM type
    pub ty: Type,
    /// Coerced LLVM Type
    pub cast: option::Option<Type>,
    /// Dummy argument, which is emitted before the real argument
    pub pad: option::Option<Type>,
    /// LLVM attribute of argument
    pub attr: option::Option<Attribute>
}

impl ArgType {
    pub fn direct(ty: Type, cast: option::Option<Type>,
                            pad: option::Option<Type>,
                            attr: option::Option<Attribute>) -> ArgType {
        ArgType {
            kind: Direct,
            ty: ty,
            cast: cast,
            pad: pad,
            attr: attr
        }
    }

    pub fn indirect(ty: Type, attr: option::Option<Attribute>) -> ArgType {
        ArgType {
            kind: Indirect,
            ty: ty,
            cast: option::None,
            pad: option::None,
            attr: attr
        }
    }

    pub fn ignore(ty: Type) -> ArgType {
        ArgType {
            kind: Ignore,
            ty: ty,
            cast: None,
            pad: None,
            attr: None,
        }
    }

    pub fn is_direct(&self) -> bool {
        return self.kind == Direct;
    }

    pub fn is_indirect(&self) -> bool {
        return self.kind == Indirect;
    }

    pub fn is_ignore(&self) -> bool {
        return self.kind == Ignore;
    }
}

/// Metadata describing how the arguments to a native function
/// should be passed in order to respect the native ABI.
///
/// I will do my best to describe this structure, but these
/// comments are reverse-engineered and may be inaccurate. -NDM
pub struct FnType {
    /// The LLVM types of each argument.
    pub arg_tys: Vec<ArgType> ,

    /// LLVM return type.
    pub ret_ty: ArgType,
}

pub fn compute_abi_info(ccx: &CrateContext,
                        atys: &[Type],
                        rty: Type,
                        ret_def: bool) -> FnType {
    match ccx.sess().targ_cfg.arch {
        X86 => cabi_x86::compute_abi_info(ccx, atys, rty, ret_def),
        X86_64 => cabi_x86_64::compute_abi_info(ccx, atys, rty, ret_def),
        Arm => cabi_arm::compute_abi_info(ccx, atys, rty, ret_def),
        Mips => cabi_mips::compute_abi_info(ccx, atys, rty, ret_def),
    }
}
<commit_msg>middle: trans: cabi: remove dead code<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

use lib::llvm::Attribute;
use std::option;
use middle::trans::context::CrateContext;
use middle::trans::cabi_x86;
use middle::trans::cabi_x86_64;
use middle::trans::cabi_arm;
use middle::trans::cabi_mips;
use middle::trans::type_::Type;
use syntax::abi::{X86, X86_64, Arm, Mips};

#[deriving(Clone, Eq)]
pub enum ArgKind {
    /// Pass the argument directly using the normal converted
    /// LLVM type or by coercing to another specified type
    Direct,
    /// Pass the argument indirectly via a hidden pointer
    Indirect,
    /// Ignore the argument (useful for empty struct)
    Ignore,
}

/// Information about how a specific C type
/// should be passed to or returned from a function
///
/// This is borrowed from clang's ABIInfo.h
#[deriving(Clone)]
pub struct ArgType {
    pub kind: ArgKind,
    /// Original LLVM type
    pub ty: Type,
    /// Coerced LLVM Type
    pub cast: option::Option<Type>,
    /// Dummy argument, which is emitted before the real argument
    pub pad: option::Option<Type>,
    /// LLVM attribute of argument
    pub attr: option::Option<Attribute>
}

impl ArgType {
    pub fn direct(ty: Type, cast: option::Option<Type>,
                            pad: option::Option<Type>,
                            attr: option::Option<Attribute>) -> ArgType {
        ArgType {
            kind: Direct,
            ty: ty,
            cast: cast,
            pad: pad,
            attr: attr
        }
    }

    pub fn indirect(ty: Type, attr: option::Option<Attribute>) -> ArgType {
        ArgType {
            kind: Indirect,
            ty: ty,
            cast: option::None,
            pad: option::None,
            attr: attr
        }
    }

    pub fn ignore(ty: Type) -> ArgType {
        ArgType {
            kind: Ignore,
            ty: ty,
            cast: None,
            pad: None,
            attr: None,
        }
    }

    pub fn is_indirect(&self) -> bool {
        return self.kind == Indirect;
    }

    pub fn is_ignore(&self) -> bool {
        return self.kind == Ignore;
    }
}

/// Metadata describing how the arguments to a native function
/// should be passed in order to respect the native ABI.
///
/// I will do my best to describe this structure, but these
/// comments are reverse-engineered and may be inaccurate. -NDM
pub struct FnType {
    /// The LLVM types of each argument.
    pub arg_tys: Vec<ArgType> ,

    /// LLVM return type.
    pub ret_ty: ArgType,
}

pub fn compute_abi_info(ccx: &CrateContext,
                        atys: &[Type],
                        rty: Type,
                        ret_def: bool) -> FnType {
    match ccx.sess().targ_cfg.arch {
        X86 => cabi_x86::compute_abi_info(ccx, atys, rty, ret_def),
        X86_64 => cabi_x86_64::compute_abi_info(ccx, atys, rty, ret_def),
        Arm => cabi_arm::compute_abi_info(ccx, atys, rty, ret_def),
        Mips => cabi_mips::compute_abi_info(ccx, atys, rty, ret_def),
    }
}
<|endoftext|>


<commit_before>use rustc::hir::def_id::DefId;
use rustc::mir::*;
use rustc::ty::TyCtxt;
use rustc_data_structures::indexed_vec::Idx;
use std::fmt::Debug;
use std::io::{self, Write};

use super::pretty::dump_mir_def_ids;

/// Write a graphviz DOT graph of a list of MIRs.
pub fn write_mir_graphviz<'tcx, W>(tcx: TyCtxt<'_, '_, 'tcx>,
                                   single: Option<DefId>,
                                   w: &mut W)
                                   -> io::Result<()>
    where W: Write
{
    for def_id in dump_mir_def_ids(tcx, single) {
        let mir = &tcx.optimized_mir(def_id);
        write_mir_fn_graphviz(tcx, def_id, mir, w)?;
    }
    Ok(())
}

// Must match `[0-9A-Za-z_]*`. This does not appear in the rendered graph, so
// it does not have to be user friendly.
pub fn graphviz_safe_def_name(def_id: DefId) -> String {
    format!(
        "{}_{}",
        def_id.krate.index(),
        def_id.index.as_array_index(),
    )
}

/// Write a graphviz DOT graph of the MIR.
pub fn write_mir_fn_graphviz<'tcx, W>(tcx: TyCtxt<'_, '_, 'tcx>,
                                      def_id: DefId,
                                      mir: &Mir<'_>,
                                      w: &mut W) -> io::Result<()>
    where W: Write
{
    writeln!(w, "digraph Mir_{} {{", graphviz_safe_def_name(def_id))?;

    // Global graph properties
    writeln!(w, r#"    graph [fontname="monospace"];"#)?;
    writeln!(w, r#"    node [fontname="monospace"];"#)?;
    writeln!(w, r#"    edge [fontname="monospace"];"#)?;

    // Graph label
    write_graph_label(tcx, def_id, mir, w)?;

    // Nodes
    for (block, _) in mir.basic_blocks().iter_enumerated() {
        write_node(block, mir, w)?;
    }

    // Edges
    for (source, _) in mir.basic_blocks().iter_enumerated() {
        write_edges(source, mir, w)?;
    }
    writeln!(w, "}}")
}

/// Write a graphviz HTML-styled label for the given basic block, with
/// all necessary escaping already performed. (This is suitable for
/// emitting directly, as is done in this module, or for use with the
/// LabelText::HtmlStr from libgraphviz.)
///
/// `init` and `fini` are callbacks for emitting additional rows of
/// data (using HTML enclosed with `<tr>` in the emitted text).
pub fn write_node_label<W: Write, INIT, FINI>(block: BasicBlock,
                                              mir: &Mir<'_>,
                                              w: &mut W,
                                              num_cols: u32,
                                              init: INIT,
                                              fini: FINI) -> io::Result<()>
    where INIT: Fn(&mut W) -> io::Result<()>,
          FINI: Fn(&mut W) -> io::Result<()>
{
    let data = &mir[block];

    write!(w, r#"
"#)?;

    // Basic block number at the top.
    write!(w, r#"
{blk}
"#,
           attrs=r#"bgcolor="gray" align="center""#,
           colspan=num_cols,
           blk=block.index())?;

    init(w)?;

    // List of statements in the middle.
    if !data.statements.is_empty() {
        write!(w, r#"
"#)?;
        for statement in &data.statements {
            write!(w, "{}
", escape(statement))?;
        }
        write!(w, "
")?;
    }

    // Terminator head at the bottom, not including the list of successor blocks. Those will be
    // displayed as labels on the edges between blocks.
    let mut terminator_head = String::new();
    data.terminator().kind.fmt_head(&mut terminator_head).unwrap();
    write!(w, r#"
{}
"#, dot::escape_html(&terminator_head))?;

    fini(w)?;

    // Close the table
    writeln!(w, "
")
}

/// Write a graphviz DOT node for the given basic block.
fn write_node<W: Write>(block: BasicBlock, mir: &Mir<'_>, w: &mut W) -> io::Result<()> {
    // Start a new node with the label to follow, in one of DOT's pseudo-HTML tables.
    write!(w, r#"    {} [shape="none", label=<"#, node(block))?;
    write_node_label(block, mir, w, 1, |_| Ok(()), |_| Ok(()))?;
    // Close the node label and the node itself.
    writeln!(w, ">];")
}

/// Write graphviz DOT edges with labels between the given basic block and all of its successors.
fn write_edges<W: Write>(source: BasicBlock, mir: &Mir<'_>, w: &mut W) -> io::Result<()> {
    let terminator = mir[source].terminator();
    let labels = terminator.kind.fmt_successor_labels();

    for (&target, label) in terminator.successors().zip(labels) {
        writeln!(w, r#"    {} -> {} [label="{}"];"#, node(source), node(target), label)?;
    }

    Ok(())
}

/// Write the graphviz DOT label for the overall graph. This is essentially a block of text that
/// will appear below the graph, showing the type of the `fn` this MIR represents and the types of
/// all the variables and temporaries.
fn write_graph_label<'a, 'gcx, 'tcx, W: Write>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                                               def_id: DefId,
                                               mir: &Mir<'_>,
                                               w: &mut W)
                                               -> io::Result<()> {
    write!(w, "    label=<fn {}(", dot::escape_html(&tcx.def_path_str(def_id)))?;

    // fn argument types.
    for (i, arg) in mir.args_iter().enumerate() {
        if i > 0 {
            write!(w, ", ")?;
        }
        write!(w,
               "{:?}: {}",
               Place::Base(PlaceBase::Local(arg)),
               escape(&mir.local_decls[arg].ty)
        )?;
    }

    write!(w, ") -> {}", escape(&mir.return_ty()))?;
    write!(w, r#"
"#)?;

    for local in mir.vars_and_temps_iter() {
        let decl = &mir.local_decls[local];

        write!(w, "let ")?;
        if decl.mutability == Mutability::Mut {
            write!(w, "mut ")?;
        }

        if let Some(name) = decl.name {
            write!(w, r#"{:?}: {}; // {}
"#,
                   Place::Base(PlaceBase::Local(local)), escape(&decl.ty), name)?;
        } else {
            write!(w, r#"let mut {:?}: {};
"#,
                   Place::Base(PlaceBase::Local(local)), escape(&decl.ty))?;
        }
    }

    writeln!(w, ">;")
}

fn node(block: BasicBlock) -> String {
    format!("bb{}", block.index())
}

fn escape<T: Debug>(t: &T) -> String {
    dot::escape_html(&format!("{:?}", t))
}
<commit_msg>Remove redundant "let mut" in write_graph_label<commit_after>use rustc::hir::def_id::DefId;
use rustc::mir::*;
use rustc::ty::TyCtxt;
use rustc_data_structures::indexed_vec::Idx;
use std::fmt::Debug;
use std::io::{self, Write};

use super::pretty::dump_mir_def_ids;

/// Write a graphviz DOT graph of a list of MIRs.
pub fn write_mir_graphviz<'tcx, W>(tcx: TyCtxt<'_, '_, 'tcx>,
                                   single: Option<DefId>,
                                   w: &mut W)
                                   -> io::Result<()>
    where W: Write
{
    for def_id in dump_mir_def_ids(tcx, single) {
        let mir = &tcx.optimized_mir(def_id);
        write_mir_fn_graphviz(tcx, def_id, mir, w)?;
    }
    Ok(())
}

// Must match `[0-9A-Za-z_]*`. This does not appear in the rendered graph, so
// it does not have to be user friendly.
pub fn graphviz_safe_def_name(def_id: DefId) -> String {
    format!(
        "{}_{}",
        def_id.krate.index(),
        def_id.index.as_array_index(),
    )
}

/// Write a graphviz DOT graph of the MIR.
pub fn write_mir_fn_graphviz<'tcx, W>(tcx: TyCtxt<'_, '_, 'tcx>,
                                      def_id: DefId,
                                      mir: &Mir<'_>,
                                      w: &mut W) -> io::Result<()>
    where W: Write
{
    writeln!(w, "digraph Mir_{} {{", graphviz_safe_def_name(def_id))?;

    // Global graph properties
    writeln!(w, r#"    graph [fontname="monospace"];"#)?;
    writeln!(w, r#"    node [fontname="monospace"];"#)?;
    writeln!(w, r#"    edge [fontname="monospace"];"#)?;

    // Graph label
    write_graph_label(tcx, def_id, mir, w)?;

    // Nodes
    for (block, _) in mir.basic_blocks().iter_enumerated() {
        write_node(block, mir, w)?;
    }

    // Edges
    for (source, _) in mir.basic_blocks().iter_enumerated() {
        write_edges(source, mir, w)?;
    }
    writeln!(w, "}}")
}

/// Write a graphviz HTML-styled label for the given basic block, with
/// all necessary escaping already performed. (This is suitable for
/// emitting directly, as is done in this module, or for use with the
/// LabelText::HtmlStr from libgraphviz.)
///
/// `init` and `fini` are callbacks for emitting additional rows of
/// data (using HTML enclosed with `<tr>` in the emitted text).
pub fn write_node_label<W: Write, INIT, FINI>(block: BasicBlock,
                                              mir: &Mir<'_>,
                                              w: &mut W,
                                              num_cols: u32,
                                              init: INIT,
                                              fini: FINI) -> io::Result<()>
    where INIT: Fn(&mut W) -> io::Result<()>,
          FINI: Fn(&mut W) -> io::Result<()>
{
    let data = &mir[block];

    write!(w, r#"
"#)?;

    // Basic block number at the top.
    write!(w, r#"
{blk}
"#,
           attrs=r#"bgcolor="gray" align="center""#,
           colspan=num_cols,
           blk=block.index())?;

    init(w)?;

    // List of statements in the middle.
    if !data.statements.is_empty() {
        write!(w, r#"
"#)?;
        for statement in &data.statements {
            write!(w, "{}
", escape(statement))?;
        }
        write!(w, "
")?;
    }

    // Terminator head at the bottom, not including the list of successor blocks. Those will be
    // displayed as labels on the edges between blocks.
    let mut terminator_head = String::new();
    data.terminator().kind.fmt_head(&mut terminator_head).unwrap();
    write!(w, r#"
{}
"#, dot::escape_html(&terminator_head))?;

    fini(w)?;

    // Close the table
    writeln!(w, "
")
}

/// Write a graphviz DOT node for the given basic block.
fn write_node<W: Write>(block: BasicBlock, mir: &Mir<'_>, w: &mut W) -> io::Result<()> {
    // Start a new node with the label to follow, in one of DOT's pseudo-HTML tables.
    write!(w, r#"    {} [shape="none", label=<"#, node(block))?;
    write_node_label(block, mir, w, 1, |_| Ok(()), |_| Ok(()))?;
    // Close the node label and the node itself.
    writeln!(w, ">];")
}

/// Write graphviz DOT edges with labels between the given basic block and all of its successors.
fn write_edges<W: Write>(source: BasicBlock, mir: &Mir<'_>, w: &mut W) -> io::Result<()> {
    let terminator = mir[source].terminator();
    let labels = terminator.kind.fmt_successor_labels();

    for (&target, label) in terminator.successors().zip(labels) {
        writeln!(w, r#"    {} -> {} [label="{}"];"#, node(source), node(target), label)?;
    }

    Ok(())
}

/// Write the graphviz DOT label for the overall graph. This is essentially a block of text that
/// will appear below the graph, showing the type of the `fn` this MIR represents and the types of
/// all the variables and temporaries.
fn write_graph_label<'a, 'gcx, 'tcx, W: Write>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                                               def_id: DefId,
                                               mir: &Mir<'_>,
                                               w: &mut W)
                                               -> io::Result<()> {
    write!(w, "    label=<fn {}(", dot::escape_html(&tcx.def_path_str(def_id)))?;

    // fn argument types.
    for (i, arg) in mir.args_iter().enumerate() {
        if i > 0 {
            write!(w, ", ")?;
        }
        write!(w,
               "{:?}: {}",
               Place::Base(PlaceBase::Local(arg)),
               escape(&mir.local_decls[arg].ty)
        )?;
    }

    write!(w, ") -> {}", escape(&mir.return_ty()))?;
    write!(w, r#"
"#)?;

    for local in mir.vars_and_temps_iter() {
        let decl = &mir.local_decls[local];

        write!(w, "let ")?;
        if decl.mutability == Mutability::Mut {
            write!(w, "mut ")?;
        }

        if let Some(name) = decl.name {
            write!(w, r#"{:?}: {}; // {}
"#,
                   Place::Base(PlaceBase::Local(local)), escape(&decl.ty), name)?;
        } else {
            write!(w, r#"{:?}: {};
"#,
                   Place::Base(PlaceBase::Local(local)), escape(&decl.ty))?;
        }
    }

    writeln!(w, ">;")
}

fn node(block: BasicBlock) -> String {
    format!("bb{}", block.index())
}

fn escape<T: Debug>(t: &T) -> String {
    dot::escape_html(&format!("{:?}", t))
}
<|endoftext|>


<commit_before>mod token;
mod error;
#[cfg(test)]
mod tests;

use std::iter::Peekable;

pub use self::token::{Token, Span};
pub use self::error::LexerError;

pub type LexerResult = Result<Token, LexerError>;

pub struct Lexer<I: Iterator> {
    reader: Peekable<I>,
    char: Option<char>,
    line: usize,
    col: usize,
    is_finished: bool,
}

impl<I: Iterator<Item=char>> Iterator for Lexer<I> {
    type Item = LexerResult;

    fn next(&mut self) -> Option<LexerResult> {
        self.read()
    }
}

impl<I: Iterator<Item=char>> Lexer<I> {
    pub fn new(reader: I) -> Lexer<I> {
        let mut l = Lexer {
            reader: reader.peekable(),
            char: None,
            line: 1,
            col: 0,
            is_finished: false,
        };
        l.bump();
        l
    }

    fn bump(&mut self) {
        self.char = self.reader.next();
        if Some('\n') == self.char {
            self.line += 1;
            self.col = 1;
        } else {
            self.col += 1;
        }
    }

    fn read(&mut self) -> Option<LexerResult> {
        self.consume_whitespaces();
        if self.is_finished {
            None
        } else {
            self.read_next()
        }
    }

    fn read_next(&mut self) -> Option<LexerResult> {
        if let Some(c) = self.char {
            match c {
                '-' | '+' => {
                    let mut is_digit = false;
                    if let Some(nc) = self.reader.peek() {
                        is_digit = nc.is_digit(10)
                    }
                    if is_digit {
                        self.read_number()
                    } else {
                        self.read_symbol()
                    }
                },
                'a' ... 'z' | 'A' ... 'Z' | '/' | '*' | '%' | '>' | '<' | '=' => {
                    self.read_symbol()
                },
                ':' => {
                    self.read_keyword()
                },
                '0' ... '9' => {
                    self.read_number()
                },
                '"' => {
                    self.read_string()
                },
                '(' => {
                    let (line, col) = (self.line, self.col);
                    self.bump();
                    Some(Ok(t_list_start!(span!(line, col, line, col + 1))))
                },
                ')' => {
                    let (line, col) = (self.line, self.col);
                    self.bump();
                    Some(Ok(t_list_end!(span!(line, col, line, col + 1))))
                },
                '[' => {
                    let (line, col) = (self.line, self.col);
                    self.bump();
                    Some(Ok(t_vec_start!(span!(line, col, line, col + 1))))
                },
                ']' => {
                    let (line, col) = (self.line, self.col);
                    self.bump();
                    Some(Ok(t_vec_end!(span!(line, col, line, col + 1))))
                },
                '\'' => {
                    let (line, col) = (self.line, self.col);
                    self.bump();
                    Some(Ok(t_quote![span![line, col, line, col + 1]]))
                },
                '~' => {
                    let (line, col) = (self.line, self.col);
                    self.bump();
                    if Some('@') == self.char {
                        self.bump();
                        Some(Ok(t_unquote_splicing![span![line, col, line, col + 2]]))
                    } else {
                        Some(Ok(t_unquote![span![line, col, line, col + 1]]))
                    }
                },
                _ => {
                    Some(self.error())
                }
            }
        } else {
            None
        }
    }

    fn read_symbol(&mut self) -> Option<LexerResult> {
        let (line, col) = (self.line, self.col);
        let mut symbol = String::new();

        while let Some(c) = self.char {
            if c == ')' ||
               c == ']' ||
               c.is_whitespace() {
                break
            } else {
                symbol.push(c)
            }
            self.bump();
        }

        Some(Ok(t_symbol!(symbol, span!(line, col, self.line, self.col))))
    }

    fn read_keyword(&mut self) -> Option<LexerResult> {
        let (line, col) = (self.line, self.col);
        let mut keyword = String::new();

        while let Some(c) = self.char {
            if c == ')' ||
               c == ']' ||
               c.is_whitespace() {
                break
            } else {
                keyword.push(c)
            }
            self.bump();
        }

        Some(Ok(t_keyword!(keyword, span!(line, col, self.line, self.col))))
    }

    fn read_number(&mut self) -> Option<LexerResult> {
        let (line, col) = (self.line, self.col);

        let mut neg = false;
        if Some('-') == self.char {
            neg = true;
            self.bump();
        } else if Some('+') == self.char {
            self.bump();
        }

        let mut accum = 0_f64;

        while let Some(c) = self.char {
            match c {
                '0' ... '9' => {
                    accum *= 10_f64;
                    accum += c.to_digit(10).unwrap() as f64;
                    self.bump()
                },
                '.' => {
                    self.bump();

                    let mut dec = 1.0;
                    while let Some(c) = self.char {
                        match c {
                            '0' ... '9' => {
                                dec /= 10.0;
                                accum += dec * c.to_digit(10).unwrap() as f64;
                                self.bump();
                            },
                            _ => {
                                break
                            }
                        }
                    }
                },
                '(' | ')' | '[' | ']' => {
                    break
                },
                c if c.is_whitespace() => {
                    break
                },
                _ => {
                    return Some(self.error())
                }
            }
        }

        if neg {
            accum *= -1_f64;
        }

        Some(Ok(t_number!(accum, span!(line, col, self.line, self.col))))
    }

    fn read_string(&mut self) -> Option<LexerResult> {
        let (line, col) = (self.line, self.col);

        let mut res = String::new();

        self.bump();

        while let Some(c) = self.char {
            if c == '"' {
                break
            } else {
                res.push(c)
            }
            self.bump();
        }

        self.bump();

        Some(Ok(t_string!(res, span!(line, col, self.line, self.col))))
    }

    fn consume_whitespaces(&mut self) {
        while let Some(c) = self.char {
            if c.is_whitespace() {
                self.bump()
            } else {
                break
            }
        }
    }

    fn error(&mut self) -> LexerResult {
        self.is_finished = true;
        Err(LexerError::new(self.line, self.col))
    }
}
<commit_msg>Read ampersand as symbol<commit_after>mod token;
mod error;
#[cfg(test)]
mod tests;

use std::iter::Peekable;

pub use self::token::{Token, Span};
pub use self::error::LexerError;

pub type LexerResult = Result<Token, LexerError>;

pub struct Lexer<I: Iterator> {
    reader: Peekable<I>,
    char: Option<char>,
    line: usize,
    col: usize,
    is_finished: bool,
}

impl<I: Iterator<Item=char>> Iterator for Lexer<I> {
    type Item = LexerResult;

    fn next(&mut self) -> Option<LexerResult> {
        self.read()
    }
}

impl<I: Iterator<Item=char>> Lexer<I> {
    pub fn new(reader: I) -> Lexer<I> {
        let mut l = Lexer {
            reader: reader.peekable(),
            char: None,
            line: 1,
            col: 0,
            is_finished: false,
        };
        l.bump();
        l
    }

    fn bump(&mut self) {
        self.char = self.reader.next();
        if Some('\n') == self.char {
            self.line += 1;
            self.col = 1;
        } else {
            self.col += 1;
        }
    }

    fn read(&mut self) -> Option<LexerResult> {
        self.consume_whitespaces();
        if self.is_finished {
            None
        } else {
            self.read_next()
        }
    }

    fn read_next(&mut self) -> Option<LexerResult> {
        if let Some(c) = self.char {
            match c {
                '-' | '+' => {
                    let mut is_digit = false;
                    if let Some(nc) = self.reader.peek() {
                        is_digit = nc.is_digit(10)
                    }
                    if is_digit {
                        self.read_number()
                    } else {
                        self.read_symbol()
                    }
                },
                'a' ... 'z' | 'A' ... 'Z' |
                '/' | '*' | '%' | '>' | '<' | '=' |
                '&' => {
                    self.read_symbol()
                },
                ':' => {
                    self.read_keyword()
                },
                '0' ... '9' => {
                    self.read_number()
                },
                '"' => {
                    self.read_string()
                },
                '(' => {
                    let (line, col) = (self.line, self.col);
                    self.bump();
                    Some(Ok(t_list_start!(span!(line, col, line, col + 1))))
                },
                ')' => {
                    let (line, col) = (self.line, self.col);
                    self.bump();
                    Some(Ok(t_list_end!(span!(line, col, line, col + 1))))
                },
                '[' => {
                    let (line, col) = (self.line, self.col);
                    self.bump();
                    Some(Ok(t_vec_start!(span!(line, col, line, col + 1))))
                },
                ']' => {
                    let (line, col) = (self.line, self.col);
                    self.bump();
                    Some(Ok(t_vec_end!(span!(line, col, line, col + 1))))
                },
                '\'' => {
                    let (line, col) = (self.line, self.col);
                    self.bump();
                    Some(Ok(t_quote![span![line, col, line, col + 1]]))
                },
                '~' => {
                    let (line, col) = (self.line, self.col);
                    self.bump();
                    if Some('@') == self.char {
                        self.bump();
                        Some(Ok(t_unquote_splicing![span![line, col, line, col + 2]]))
                    } else {
                        Some(Ok(t_unquote![span![line, col, line, col + 1]]))
                    }
                },
                _ => {
                    Some(self.error())
                }
            }
        } else {
            None
        }
    }

    fn read_symbol(&mut self) -> Option<LexerResult> {
        let (line, col) = (self.line, self.col);
        let mut symbol = String::new();

        while let Some(c) = self.char {
            if c == ')' ||
               c == ']' ||
               c.is_whitespace() {
                break
            } else {
                symbol.push(c)
            }
            self.bump();
        }

        Some(Ok(t_symbol!(symbol, span!(line, col, self.line, self.col))))
    }

    fn read_keyword(&mut self) -> Option<LexerResult> {
        let (line, col) = (self.line, self.col);
        let mut keyword = String::new();

        while let Some(c) = self.char {
            if c == ')' ||
               c == ']' ||
               c.is_whitespace() {
                break
            } else {
                keyword.push(c)
            }
            self.bump();
        }

        Some(Ok(t_keyword!(keyword, span!(line, col, self.line, self.col))))
    }

    fn read_number(&mut self) -> Option<LexerResult> {
        let (line, col) = (self.line, self.col);

        let mut neg = false;
        if Some('-') == self.char {
            neg = true;
            self.bump();
        } else if Some('+') == self.char {
            self.bump();
        }

        let mut accum = 0_f64;

        while let Some(c) = self.char {
            match c {
                '0' ... '9' => {
                    accum *= 10_f64;
                    accum += c.to_digit(10).unwrap() as f64;
                    self.bump()
                },
                '.' => {
                    self.bump();

                    let mut dec = 1.0;
                    while let Some(c) = self.char {
                        match c {
                            '0' ... '9' => {
                                dec /= 10.0;
                                accum += dec * c.to_digit(10).unwrap() as f64;
                                self.bump();
                            },
                            _ => {
                                break
                            }
                        }
                    }
                },
                '(' | ')' | '[' | ']' => {
                    break
                },
                c if c.is_whitespace() => {
                    break
                },
                _ => {
                    return Some(self.error())
                }
            }
        }

        if neg {
            accum *= -1_f64;
        }

        Some(Ok(t_number!(accum, span!(line, col, self.line, self.col))))
    }

    fn read_string(&mut self) -> Option<LexerResult> {
        let (line, col) = (self.line, self.col);

        let mut res = String::new();

        self.bump();

        while let Some(c) = self.char {
            if c == '"' {
                break
            } else {
                res.push(c)
            }
            self.bump();
        }

        self.bump();

        Some(Ok(t_string!(res, span!(line, col, self.line, self.col))))
    }

    fn consume_whitespaces(&mut self) {
        while let Some(c) = self.char {
            if c.is_whitespace() {
                self.bump()
            } else {
                break
            }
        }
    }

    fn error(&mut self) -> LexerResult {
        self.is_finished = true;
        Err(LexerError::new(self.line, self.col))
    }
}
<|endoftext|>


<commit_before>// xfail-fast

// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

#[forbid(deprecated_pattern)];

extern mod std;

// These tests used to be separate files, but I wanted to refactor all
// the common code.

use EBReader = std::ebml::reader;
use EBWriter = std::ebml::writer;
use core::cmp::Eq;
use core::io::Writer;
use std::ebml;
use std::serialize::{Encodable, Decodable};
use std::time;

fn test_ebml<A:
    Eq +
    Encodable<EBWriter::Encoder> +
    Decodable<EBReader::Decoder>
>(a1: &A) {
    let bytes = do io::with_bytes_writer |wr| {
        let ebml_w = &EBWriter::Encoder(wr);
        a1.encode(ebml_w)
    };
    let d = EBReader::Doc(@bytes);
    let a2: A = Decodable::decode(&EBReader::Decoder(d));
    assert!(*a1 == a2);
}

#[auto_encode]
#[auto_decode]
enum Expr {
    Val(uint),
    Plus(@Expr, @Expr),
    Minus(@Expr, @Expr)
}

impl cmp::Eq for Expr {
    fn eq(&self, other: &Expr) -> bool {
        match *self {
            Val(e0a) => {
                match *other {
                    Val(e0b) => e0a == e0b,
                    _ => false
                }
            }
            Plus(e0a, e1a) => {
                match *other {
                    Plus(e0b, e1b) => e0a == e0b && e1a == e1b,
                    _ => false
                }
            }
            Minus(e0a, e1a) => {
                match *other {
                    Minus(e0b, e1b) => e0a == e0b && e1a == e1b,
                    _ => false
                }
            }
        }
    }
    fn ne(&self, other: &Expr) -> bool { !(*self).eq(other) }
}

impl cmp::Eq for Point {
    fn eq(&self, other: &Point) -> bool {
        self.x == other.x && self.y == other.y
    }
    fn ne(&self, other: &Point) -> bool { !(*self).eq(other) }
}

impl<T:cmp::Eq> cmp::Eq for Quark<T> {
    fn eq(&self, other: &Quark<T>) -> bool {
        match *self {
            Top(ref q) => {
                match *other {
                    Top(ref r) => q == r,
                    Bottom(_) => false
                }
            },
            Bottom(ref q) => {
                match *other {
                    Top(_) => false,
                    Bottom(ref r) => q == r
                }
            },
        }
    }
    fn ne(&self, other: &Quark<T>) -> bool { !(*self).eq(other) }
}

impl cmp::Eq for CLike {
    fn eq(&self, other: &CLike) -> bool {
        (*self) as int == *other as int
    }
    fn ne(&self, other: &CLike) -> bool { !self.eq(other) }
}

#[auto_encode]
#[auto_decode]
#[deriving(Eq)]
struct Spanned<T> {
    lo: uint,
    hi: uint,
    node: T,
}

#[auto_encode]
#[auto_decode]
struct SomeStruct { v: ~[uint] }

#[auto_encode]
#[auto_decode]
struct Point {x: uint, y: uint}

#[auto_encode]
#[auto_decode]
enum Quark<T> {
    Top(T),
    Bottom(T)
}

#[auto_encode]
#[auto_decode]
enum CLike { A, B, C }

pub fn main() {
    let a = &Plus(@Minus(@Val(3u), @Val(10u)), @Plus(@Val(22u), @Val(5u)));
    test_ebml(a);

    let a = &Spanned {lo: 0u, hi: 5u, node: 22u};
    test_ebml(a);

    let a = &Point {x: 3u, y: 5u};
    test_ebml(a);

    let a = &@[1u, 2u, 3u];
    test_ebml(a);

    let a = &Top(22u);
    test_ebml(a);

    let a = &Bottom(222u);
    test_ebml(a);

    let a = &A;
    test_ebml(a);

    let a = &B;
    test_ebml(a);

    let a = &time::now();
    test_ebml(a);
}
<commit_msg>test: update serialization tests to use new macro<commit_after>// xfail-fast

// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

#[forbid(deprecated_pattern)];

extern mod std;

// These tests used to be separate files, but I wanted to refactor all
// the common code.

use EBReader = std::ebml::reader;
use EBWriter = std::ebml::writer;
use core::cmp::Eq;
use core::io::Writer;
use std::ebml;
use std::serialize::{Decodable, Encodable};
use std::time;

fn test_ebml<A:
    Eq +
    Encodable<EBWriter::Encoder> +
    Decodable<EBReader::Decoder>
>(a1: &A) {
    let bytes = do io::with_bytes_writer |wr| {
        let ebml_w = &EBWriter::Encoder(wr);
        a1.encode(ebml_w)
    };
    let d = EBReader::Doc(@bytes);
    let a2: A = Decodable::decode(&EBReader::Decoder(d));
    assert!(*a1 == a2);
}

#[deriving(Decodable, Encodable)]
enum Expr {
    Val(uint),
    Plus(@Expr, @Expr),
    Minus(@Expr, @Expr)
}

impl cmp::Eq for Expr {
    fn eq(&self, other: &Expr) -> bool {
        match *self {
            Val(e0a) => {
                match *other {
                    Val(e0b) => e0a == e0b,
                    _ => false
                }
            }
            Plus(e0a, e1a) => {
                match *other {
                    Plus(e0b, e1b) => e0a == e0b && e1a == e1b,
                    _ => false
                }
            }
            Minus(e0a, e1a) => {
                match *other {
                    Minus(e0b, e1b) => e0a == e0b && e1a == e1b,
                    _ => false
                }
            }
        }
    }
    fn ne(&self, other: &Expr) -> bool { !(*self).eq(other) }
}

impl cmp::Eq for Point {
    fn eq(&self, other: &Point) -> bool {
        self.x == other.x && self.y == other.y
    }
    fn ne(&self, other: &Point) -> bool { !(*self).eq(other) }
}

impl<T:cmp::Eq> cmp::Eq for Quark<T> {
    fn eq(&self, other: &Quark<T>) -> bool {
        match *self {
            Top(ref q) => {
                match *other {
                    Top(ref r) => q == r,
                    Bottom(_) => false
                }
            },
            Bottom(ref q) => {
                match *other {
                    Top(_) => false,
                    Bottom(ref r) => q == r
                }
            },
        }
    }
    fn ne(&self, other: &Quark<T>) -> bool { !(*self).eq(other) }
}

impl cmp::Eq for CLike {
    fn eq(&self, other: &CLike) -> bool {
        (*self) as int == *other as int
    }
    fn ne(&self, other: &CLike) -> bool { !self.eq(other) }
}

#[deriving(Decodable, Encodable, Eq)]
struct Spanned<T> {
    lo: uint,
    hi: uint,
    node: T,
}

#[deriving(Decodable, Encodable)]
struct SomeStruct { v: ~[uint] }

#[deriving(Decodable, Encodable)]
struct Point {x: uint, y: uint}

#[deriving(Decodable, Encodable)]
enum Quark<T> {
    Top(T),
    Bottom(T)
}

#[deriving(Decodable, Encodable)]
enum CLike { A, B, C }

pub fn main() {
    let a = &Plus(@Minus(@Val(3u), @Val(10u)), @Plus(@Val(22u), @Val(5u)));
    test_ebml(a);

    let a = &Spanned {lo: 0u, hi: 5u, node: 22u};
    test_ebml(a);

    let a = &Point {x: 3u, y: 5u};
    test_ebml(a);

    let a = &@[1u, 2u, 3u];
    test_ebml(a);

    let a = &Top(22u);
    test_ebml(a);

    let a = &Bottom(222u);
    test_ebml(a);

    let a = &A;
    test_ebml(a);

    let a = &B;
    test_ebml(a);

    let a = &time::now();
    test_ebml(a);
}
<|endoftext|>


<commit_before>use std::sync::mpsc::{Sender, Receiver};
use std::sync::{mpsc, Arc, TaskPool};
use rand::{Rng, thread_rng};

use evaluation::{EvaluationFn};
use genotype::{Genotype};
use statistics::{Statistic};
use util::{shuffle};

// TODO?
//type Result = (Genotype, Statistic);

pub struct MuLambda<G: Genotype> {
    threads: usize,
    iterations: usize,
    current_iteration: usize,
    mu: usize,     // number to keep
    lambda: usize, // number to generate
    mutation: f64, // mutation of genotype to mutate (between 0.0 and 1.0)
    genotype: G,
    evaluations: Arc<Vec<EvaluationFn>>
}

impl<G: Genotype + Clone + Send + 'static> MuLambda<G> {
    pub fn new(threads: usize,
               iterations: usize,
               mu: usize,
               lambda: usize,
               mutation: f64,
               genotype: G,
               funcs: Vec<EvaluationFn>) -> MuLambda<G> {
        MuLambda {
            threads: threads,
            iterations: iterations,
            current_iteration: 0,
            mu: mu,
            lambda: lambda,
            mutation: mutation,
            genotype: genotype,
            evaluations: Arc::new(funcs)
        }
    }

    pub fn evaluate(&mut self) -> Vec<(G, Statistic)> {
        let total = self.mu + self.lambda;
        let mut rng = thread_rng();
        let mut primer: Vec<(G, Statistic)> = range(0, total).map(|_| {
            (self.genotype.initialize(&mut rng), Statistic::empty())
        }).collect();
        while self.current_iteration < self.iterations {
            primer = self.iterate(&mut rng, primer.as_mut_slice(), self.current_iteration);
            self.current_iteration += 1;
        }
        primer.clone()
    }

    fn iterate<R: Rng>(&self, rng: &mut R, primer: &mut [(G, Statistic)], iteration: usize) -> Vec<(G, Statistic)> {
        // shuffle the population
        shuffle(rng, primer);
        // calculate the fitness for each individual (in a separate thread)
        let n = primer.len();
        let pool = TaskPool::new(self.threads);
        let (tx, rx): (Sender<(G, Statistic)>, Receiver<(G, Statistic)>) = mpsc::channel();
        for &(ref adult, _) in primer.iter() {
            let individual = adult.clone();
            let sender = tx.clone();
            let fns = self.evaluations.clone();
            pool.execute(move || {
                let dungeon = individual.generate();
                let fitness = individual.evaluate(&dungeon, fns.as_slice());
                let statistic = Statistic::new(iteration as u32, fitness);
                sender.send((individual, statistic)).unwrap();
            });
        }
        let mut colony: Vec<(G, Statistic)> = range(0, n).map(|_| rx.recv().unwrap()).collect();
        // sort by fitness
        colony.sort_by(|&(_, ref f1), &(_, ref f2)| {
            match f1.fitness.partial_cmp(&f2.fitness) {
                Some(ordering) => ordering,
                None => panic!(format!("{:?} and {:?} could not be ordered.", f1.fitness, f2.fitness))
            }
        });
        // keep mu
        let mut survivors: Vec<(G, Statistic)> = colony.iter().map(|v| v.clone()).take(self.mu).collect();
        // add the next generation
        let mut laggards: Vec<G> = colony.iter().map(|&(ref i, _)| i.clone()).skip(self.mu).collect();
        let next_generation: Vec<(G, Statistic)> = laggards.drain().map(|mut individual| {
            let mut new_rng = thread_rng();
            individual.mutate(&mut new_rng, self.mutation);
            (individual, Statistic::empty())
        }).collect();
        survivors.push_all(next_generation.as_slice());
        survivors
    }
}
<commit_msg>Remove an unnecessary iteration.<commit_after>use std::sync::mpsc::{Sender, Receiver};
use std::sync::{mpsc, Arc, TaskPool};
use rand::{Rng, thread_rng};

use evaluation::{EvaluationFn};
use genotype::{Genotype};
use statistics::{Statistic};
use util::{shuffle};

// TODO?
//type Result = (Genotype, Statistic);

pub struct MuLambda<G: Genotype> {
    threads: usize,
    iterations: usize,
    current_iteration: usize,
    mu: usize,     // number to keep
    lambda: usize, // number to generate
    mutation: f64, // mutation of genotype to mutate (between 0.0 and 1.0)
    genotype: G,
    evaluations: Arc<Vec<EvaluationFn>>
}

impl<G: Genotype + Clone + Send + 'static> MuLambda<G> {
    pub fn new(threads: usize,
               iterations: usize,
               mu: usize,
               lambda: usize,
               mutation: f64,
               genotype: G,
               funcs: Vec<EvaluationFn>) -> MuLambda<G> {
        MuLambda {
            threads: threads,
            iterations: iterations,
            current_iteration: 0,
            mu: mu,
            lambda: lambda,
            mutation: mutation,
            genotype: genotype,
            evaluations: Arc::new(funcs)
        }
    }

    pub fn evaluate(&mut self) -> Vec<(G, Statistic)> {
        let total = self.mu + self.lambda;
        let mut rng = thread_rng();
        let mut primer: Vec<(G, Statistic)> = range(0, total).map(|_| {
            (self.genotype.initialize(&mut rng), Statistic::empty())
        }).collect();
        while self.current_iteration < self.iterations {
            primer = self.iterate(&mut rng, primer.as_mut_slice(), self.current_iteration);
            self.current_iteration += 1;
        }
        primer.clone()
    }

    fn iterate<R: Rng>(&self, rng: &mut R, primer: &mut [(G, Statistic)], iteration: usize) -> Vec<(G, Statistic)> {
        // shuffle the population
        shuffle(rng, primer);
        // calculate the fitness for each individual (in a separate thread)
        let n = primer.len();
        let pool = TaskPool::new(self.threads);
        let (tx, rx): (Sender<(G, Statistic)>, Receiver<(G, Statistic)>) = mpsc::channel();
        for &(ref adult, _) in primer.iter() {
            let individual = adult.clone();
            let sender = tx.clone();
            let fns = self.evaluations.clone();
            pool.execute(move || {
                let dungeon = individual.generate();
                let fitness = individual.evaluate(&dungeon, fns.as_slice());
                let statistic = Statistic::new(iteration as u32, fitness);
                sender.send((individual, statistic)).unwrap();
            });
        }
        let mut colony: Vec<(G, Statistic)> = range(0, n).map(|_| rx.recv().unwrap()).collect();
        // sort by fitness
        colony.sort_by(|&(_, ref f1), &(_, ref f2)| {
            match f1.fitness.partial_cmp(&f2.fitness) {
                Some(ordering) => ordering,
                None => panic!(format!("{:?} and {:?} could not be ordered.", f1.fitness, f2.fitness))
            }
        });
        // keep mu
        let mut survivors: Vec<(G, Statistic)> = colony.iter().map(|v| v.clone()).take(self.mu).collect();
        // add the next generation
        let next_generation: Vec<(G, Statistic)> = colony.into_iter().map(|(ref mut individual, _)| {
            let mut new_rng = thread_rng();
            let mut baby = individual.clone();
            baby.mutate(&mut new_rng, self.mutation);
            (baby, Statistic::empty())
        }).skip(self.mu).collect();
        survivors.push_all(next_generation.as_slice());
        survivors
    }
}
<|endoftext|>


<commit_before>#![crate_id(name="getopt", vers="0.0.1", author="Mahmut Bulut")]
#![feature(macro_rules)]
#![feature(phase)]

/*
 * This file is part of the trafo package.
 *
 * (c) Mahmut Bulut <mahmutbulut0@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

use std::os;

#[path = "../common/util.rs"]
mod util;

static EXIT_OK:  i32 = 0;
static EXIT_ERR: i32 = 1;

static NAME: &'static str = "getopt";
static VERSION:  &'static str = "0.0.1";

fn main() {
	let args = os::args();
	print!(" -- ");

	for opt in args.slice(2, args.len()).iter() {
		print!("{} ", opt);
	}

	// they said parse opts so we print it all . lol.

	println!("");
}<commit_msg>bsd type getopt work<commit_after>#![crate_id(name="getopt", vers="0.0.1", author="Mahmut Bulut")]
#![feature(macro_rules)]
#![feature(phase)]

/*
 * This file is part of the trafo package.
 *
 * (c) Mahmut Bulut <mahmutbulut0@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

extern crate getopts;

use std::os;
use std::str;

use getopts::{
    getopts,
    optopt,
    optflag,
    optflagopt,
    usage,
};

#[path = "../common/util.rs"]
mod util;

static EXIT_OK:  i32 = 0;
static EXIT_ERR: i32 = 1;

static NAME: &'static str = "getopt";
static VERSION:  &'static str = "0.0.1";

fn main() {
	let args = os::args();
	//print!(" -- ");

	let checks = args[1].clone();

	let rest = args.slice(2, args.len());

	let opts: ~[getopts::OptGroup] = checks.chars().map(|x| optflag(str::from_char(x), "", "")).collect();

    //let opts = ~[checks.chars()];

	// they said parse opts so we print it all . lol.

	let mut a = 0;

	for arg in rest.iter() {
		if rest[a].chars().nth(0).unwrap() == '-' {
			let mut v: ~[~str] = rest[a].chars().map(|x| x.to_str()).collect();
			let matches = match getopts(v, opts) {
				Ok(m) => { m }
				Err(f) => { fail!(f) }
			};
			for ex in matches.free.iter() {
				print!(" -{} ", ex);
			}
			a+=1;
		} else {
			//for c in rest[a].chars() { print!(" {} ", c); }
			print!(" {} ", rest[a]);
			a+=1;
		}
	}

	/*
	for c in opts.iter() {
		//print!("{} ", c);
		println!("ZENCİ");
		let mut a = 0;
		if rest[a].chars().nth(0).unwrap() == '-' {
			let matches = match getopts(rest[a], opts) {
				Ok(m) => { m }
				Err(f) => { fail!(f) }
			};
			a+=1;
		} else {

		}

		//print!(matches);
	}
	*/

	println!("");
}<|endoftext|>