<commit_before>use std::collections::{BTreeMap, HashSet};
use reporter::{Diagnostic, Note, Severity};

#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Debug, Copy, Clone)]
enum MarkerStyle {
    // ~~~~~ or ____~
    Secondary,
    // ^^^^^ or ____^
    Primary,
}

impl MarkerStyle {
    fn from_note_index(index: usize) -> MarkerStyle {
        if index == 0 {
            MarkerStyle::Primary
        } else {
            MarkerStyle::Secondary
        }
    }

    fn to_marker_part(self, is_arrow: bool) -> MarkerPart {
        match self {
            MarkerStyle::Primary => {
                if is_arrow {
                    MarkerPart::ArrowPrimary
                } else {
                    MarkerPart::PrimaryMarker
                }
            }
            MarkerStyle::Secondary => {
                if is_arrow {
                    MarkerPart::ArrowSecondary
                } else {
                    MarkerPart::SecondaryMarker
                }
            }
        }
    }
}

#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Debug, Copy, Clone)]
enum MarkerPart {
    None,
    ArrowBottom,
    SecondaryMarker,
    PrimaryMarker,
    ArrowSecondary,
    ArrowPrimary,
    SingleColumn
}

impl MarkerPart {
    fn or(self, other: MarkerPart) -> MarkerPart {
        ::std::cmp::max(self, other)
    }

    fn to_char(self) -> char {
        match self {
            MarkerPart::None => ' ',
            MarkerPart::ArrowBottom => '_',
            MarkerPart::SecondaryMarker |
            MarkerPart::ArrowSecondary => '~',
            MarkerPart::PrimaryMarker |
            MarkerPart::ArrowPrimary => '^',
            MarkerPart::SingleColumn => '|',
        }
    }
}

#[derive(Debug, Clone)]
enum LineMarker<'a> {
    FromStart {
        connect_col: u32,
        arrow_col: u32,
        message: Option<&'a str>,
        style: MarkerStyle,
    },
    FromTo {
        start_col: u32,
        end_col: u32,
        message: Option<&'a str>,
        style: MarkerStyle,
    },
}

impl<'a> LineMarker<'a> {
    fn message(&self) -> Option<&str> {
        match *self {
            LineMarker::FromStart { message, .. } |
            LineMarker::FromTo { message, .. } => message,
        }
    }

    fn end_col(&self) -> u32 {
        match *self {
            LineMarker::FromStart { arrow_col, .. } => arrow_col,
            LineMarker::FromTo { end_col, .. } => end_col,
        }
    }

    fn is_arrow(&self) -> bool {
        match *self {
            LineMarker::FromStart { .. } => true,
            LineMarker::FromTo { .. } => false,
        }
    }
}

struct Printer<'a> {
    lines: Vec<&'a str>,
    // use BTreeMap here so that we can iterate annotated lines in order
    line_markers: BTreeMap<u32, Vec<LineMarker<'a>>>,
    next_connect_col: u32,
    full_connection_cols: HashSet<u32>,
    number_space: usize,
}

impl<'a> Printer<'a> {
    fn new(source: &'a str) -> Self {
        Printer {
            lines: source.lines().map(str::trim_right).collect(),
            line_markers: BTreeMap::new(),
            next_connect_col: 0,
            full_connection_cols: HashSet::new(),
            number_space: 0,
        }
    }

    fn pretty_print(&mut self, diagnostic: &'a Diagnostic) {
        match diagnostic.severity {
            Severity::Error => {
                println!("error: {}", diagnostic.message);
            }
            Severity::Warning => {
                println!("warning: {}", diagnostic.message);
            }
        }
        assert!(diagnostic.notes.len() > 0, "got diagnostic without notes");
        self.print_notes(&diagnostic.notes);
    }

    fn print_notes(&mut self, notes: &'a [Note]) {
        assert!(self.line_markers.is_empty());
        assert_eq!(self.next_connect_col, 0);
        assert!(self.full_connection_cols.is_empty());
        for (index, note) in notes.iter().enumerate() {
            self.add_note_markers(note, MarkerStyle::from_note_index(index));
        }
        for markers in self.line_markers.values_mut() {
            markers.sort_by_key(LineMarker::end_col);
        }
        assert!(!self.line_markers.is_empty());
        let last_line = *self.line_markers.keys().next_back().unwrap();
        self.number_space = number_length(last_line) as usize;
        self.print_annotations();
        self.line_markers.clear();
        assert!(self.full_connection_cols.is_empty());
        self.next_connect_col = 0;
    }

    fn add_note_markers(&mut self, note: &'a Note, style: MarkerStyle) {
        if note.span.start.line == note.span.end.line {
            self.add_line_marker(note.span.start.line, LineMarker::FromTo {
                start_col: note.span.start.column,
                end_col: note.span.end.column,
                message: note.message.as_ref().map(AsRef::as_ref),
                style,
            });
        } else {
            let connect_col = self.next_connect_col;
            self.next_connect_col += 2;
            self.add_line_marker(note.span.start.line, LineMarker::FromStart {
                connect_col,
                arrow_col: note.span.start.column,
                message: None,
                style,
            });
            self.add_line_marker(note.span.end.line, LineMarker::FromStart {
                connect_col,
                arrow_col: note.span.end.column - 1,
                message: note.message.as_ref().map(AsRef::as_ref),
                style,
            });
        }
    }

    fn add_line_marker(&mut self, line: u32, marker: LineMarker<'a>) {
        self.line_markers
            .entry(line)
            .or_insert_with(Vec::new)
            .push(marker);
    }

    fn print_annotations(&mut self) {
        let line_markers = ::std::mem::replace(&mut self.line_markers, BTreeMap::new());
        for (line, markers) in line_markers {
            self.print_line_and_markers(line, markers);
        }
    }

    fn print_line_and_markers(&mut self, line: u32, mut markers: Vec<LineMarker>) {
        assert!(markers.len() > 0, "line has no markers");
        self.print_line(line);
        self.print_immediate_markers(&markers);
        // last span has its message printed inline
        println!(" {}", markers
            .iter()
            .next_back()
            .unwrap()
            .message()
            .unwrap_or(""));
        markers.pop();

        // non-arrow markers without messages don't extend below first line
        markers.retain(|m| m.message().is_some() || m.is_arrow());

        // possibly print additional line so that instead of
        //      let x = 1;
        //          ~~~  ~ first note
        //            second note
        // we would get
        //      let x = 1;
        //          ~~~  ~ first note
        //            |
        //            second note
        match markers.iter().next_back().cloned().unwrap() {
            LineMarker::FromTo { end_col, .. } => {
                self.print_markers(&markers, end_col);
                println!();
            }
            LineMarker::FromStart { arrow_col, message, .. } if message.is_some() => {
                self.print_markers(&markers, arrow_col + 1);
                println!();
            }
            _ => {}
        }
        for i in (1..(markers.len() + 1)).rev() {
            let markers = &markers[0..i];
            match &markers[i - 1] {
                &LineMarker::FromTo { end_col, message, .. } => {
                    self.print_markers(markers, end_col - 1);
                    println!("{}", message.unwrap_or(""));
                }
                &LineMarker::FromStart { arrow_col, message, .. } => {
                    self.print_markers(markers, arrow_col + 2);
                    println!("{}", message.unwrap_or(""));
                }
            }
        }
    }

    fn print_line(&mut self, line: u32) {
        self.print_line_header(Some(line), None);
        for ch in self.lines.get((line - 1) as usize).unwrap_or(&"").chars() {
            match ch {
                // print these chars as one space, otherwise
                // they will break note alignment with code
                '\t' | '\r' => print!(" "),
                ch => print!("{}", ch),
            }
        }
        println!();
    }

    fn print_line_header(&mut self, line: Option<u32>, arrow_from: Option<u32>) {
        if let Some(line) = line {
            print!("{: >width$} |  ", line, width = self.number_space);
        } else {
            print!("{: >width$} |  ", "", width = self.number_space);
        }
        for col in 0..self.next_connect_col {
            if self.full_connection_cols.contains(&col) {
                print!("|");
            } else {
                match arrow_from {
                    Some(c) if c < col => print!("_"),
                    _ => print!(" "),
                }
            }
            if arrow_from == Some(col) {
                if self.full_connection_cols.contains(&col) {
                    self.full_connection_cols.remove(&col);
                } else {
                    self.full_connection_cols.insert(col);
                }
            }
        }
    }

    fn print_immediate_markers(&mut self, markers: &[LineMarker]) {
        let (connect, arrow_end) = match markers.iter().next_back().unwrap() {
            &LineMarker::FromStart { connect_col, arrow_col, .. } => {
                (Some(connect_col), arrow_col - 1)
            }
            _ => {
                (None, 0)
            }
        };
        self.print_line_header(None, connect);
        let last_col = markers.iter().next_back().unwrap().end_col();
        for col in 1..last_col {
            let mut part = MarkerPart::None;
            if col <= arrow_end {
                part = MarkerPart::ArrowBottom;
            }
            for (index, marker) in markers.iter().rev().enumerate() {
                match *marker {
                    LineMarker::FromStart { arrow_col, style, .. } => {
                        if arrow_col == col {
                            part = part.or(style.to_marker_part(true));
                        }
                    }
                    LineMarker::FromTo { start_col, end_col, style, message } => {
                        if start_col <= col && col < end_col {
                            part = part.or(style.to_marker_part(false));
                        }
                        if start_col == col
                            && end_col == start_col + 1 // marker is one col wide
                            && index > 0 // and not the last one in line
                            && message.is_some() // and has a message
                            && style != MarkerStyle::Primary // and it is not primary
                        {
                            part = part.or(MarkerPart::SingleColumn);
                        }
                    }
                }
            }
            print!("{}", part.to_char());
        }
    }

    fn print_markers(&mut self, markers: &[LineMarker], last_col: u32) {
        let (connect, arrow_end) = match markers.iter().next_back().unwrap() {
            &LineMarker::FromStart { connect_col, arrow_col, .. } => {
                (Some(connect_col), arrow_col - 1)
            }
            _ => {
                (None, 0)
            }
        };
        self.print_line_header(None, connect);
        for col in 1..last_col {
            let mut part = MarkerPart::None;
            if col <= arrow_end {
                part = MarkerPart::ArrowBottom;
            }
            for marker in markers.iter().rev() {
                match *marker {
                    LineMarker::FromStart { arrow_col, .. } => {
                        if arrow_col == col {
                            part = MarkerPart::SingleColumn;
                        }
                    }
                    LineMarker::FromTo { end_col, message, .. } => {
                        if end_col == col + 1 && message.is_some() {
                            part = MarkerPart::SingleColumn;
                        }
                    }
                }
            }
            print!("{}", part.to_char());
        }
    }
}

fn number_length(mut num: u32) -> u32 {
    let mut len = 1;
    while num >= 10 {
        len += 1;
        num /= 10;
    }
    len
}

pub fn print_diagnostic(source: &str, diagnostic: &Diagnostic) {
    Printer::new(source).pretty_print(diagnostic)
}

pub fn print_diagnostics(source: &str, diagnostics: &[Diagnostic]) {
    let mut printer = Printer::new(source);
    for diagnostic in diagnostics {
        printer.pretty_print(diagnostic);
        println!("");
    }
}
<commit_msg>print intermediate lines and fix a bug<commit_after>use std::collections::{BTreeMap, HashSet};
use reporter::{Diagnostic, Note, Severity};

#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Debug, Copy, Clone)]
enum MarkerStyle {
    // ~~~~~ or ____~
    Secondary,
    // ^^^^^ or ____^
    Primary,
}

impl MarkerStyle {
    fn from_note_index(index: usize) -> MarkerStyle {
        if index == 0 {
            MarkerStyle::Primary
        } else {
            MarkerStyle::Secondary
        }
    }

    fn to_marker_part(self, is_arrow: bool) -> MarkerPart {
        match self {
            MarkerStyle::Primary => {
                if is_arrow {
                    MarkerPart::ArrowPrimary
                } else {
                    MarkerPart::PrimaryMarker
                }
            }
            MarkerStyle::Secondary => {
                if is_arrow {
                    MarkerPart::ArrowSecondary
                } else {
                    MarkerPart::SecondaryMarker
                }
            }
        }
    }
}

#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Debug, Copy, Clone)]
enum MarkerPart {
    None,
    ArrowBottom,
    SecondaryMarker,
    PrimaryMarker,
    ArrowSecondary,
    ArrowPrimary,
    SingleColumn
}

impl MarkerPart {
    fn or(self, other: MarkerPart) -> MarkerPart {
        ::std::cmp::max(self, other)
    }

    fn to_char(self) -> char {
        match self {
            MarkerPart::None => ' ',
            MarkerPart::ArrowBottom => '_',
            MarkerPart::SecondaryMarker |
            MarkerPart::ArrowSecondary => '~',
            MarkerPart::PrimaryMarker |
            MarkerPart::ArrowPrimary => '^',
            MarkerPart::SingleColumn => '|',
        }
    }
}

#[derive(Debug, Clone)]
enum LineMarker<'a> {
    FromStart {
        connect_col: u32,
        arrow_col: u32,
        message: Option<&'a str>,
        style: MarkerStyle,
    },
    FromTo {
        start_col: u32,
        end_col: u32,
        message: Option<&'a str>,
        style: MarkerStyle,
    },
}

impl<'a> LineMarker<'a> {
    fn message(&self) -> Option<&str> {
        match *self {
            LineMarker::FromStart { message, .. } |
            LineMarker::FromTo { message, .. } => message,
        }
    }

    fn end_col(&self) -> u32 {
        match *self {
            LineMarker::FromStart { arrow_col, .. } => arrow_col,
            LineMarker::FromTo { end_col, .. } => end_col,
        }
    }

    fn is_arrow(&self) -> bool {
        match *self {
            LineMarker::FromStart { .. } => true,
            LineMarker::FromTo { .. } => false,
        }
    }
}

struct Printer<'a> {
    lines: Vec<&'a str>,
    // use BTreeMap here so that we can iterate annotated lines in order
    line_markers: BTreeMap<u32, Vec<LineMarker<'a>>>,
    next_connect_col: u32,
    full_connection_cols: HashSet<u32>,
    number_space: usize,
}

impl<'a> Printer<'a> {
    fn new(source: &'a str) -> Self {
        Printer {
            lines: source.lines().map(str::trim_right).collect(),
            line_markers: BTreeMap::new(),
            next_connect_col: 0,
            full_connection_cols: HashSet::new(),
            number_space: 0,
        }
    }

    fn pretty_print(&mut self, diagnostic: &'a Diagnostic) {
        match diagnostic.severity {
            Severity::Error => {
                println!("error: {}", diagnostic.message);
            }
            Severity::Warning => {
                println!("warning: {}", diagnostic.message);
            }
        }
        assert!(diagnostic.notes.len() > 0, "got diagnostic without notes");
        self.print_notes(&diagnostic.notes);
    }

    fn print_notes(&mut self, notes: &'a [Note]) {
        assert!(self.line_markers.is_empty());
        assert_eq!(self.next_connect_col, 0);
        assert!(self.full_connection_cols.is_empty());
        for (index, note) in notes.iter().enumerate() {
            self.add_note_markers(note, MarkerStyle::from_note_index(index));
        }
        for markers in self.line_markers.values_mut() {
            markers.sort_by_key(LineMarker::end_col);
        }
        assert!(!self.line_markers.is_empty());
        let last_line = *self.line_markers.keys().next_back().unwrap();
        self.number_space = number_length(last_line) as usize;
        self.print_annotations();
        self.line_markers.clear();
        assert!(self.full_connection_cols.is_empty());
        self.next_connect_col = 0;
    }

    fn add_note_markers(&mut self, note: &'a Note, style: MarkerStyle) {
        if note.span.start.line == note.span.end.line {
            self.add_line_marker(note.span.start.line, LineMarker::FromTo {
                start_col: note.span.start.column,
                end_col: note.span.end.column,
                message: note.message.as_ref().map(AsRef::as_ref),
                style,
            });
        } else {
            let connect_col = self.next_connect_col;
            self.next_connect_col += 2;
            self.add_line_marker(note.span.start.line, LineMarker::FromStart {
                connect_col,
                arrow_col: note.span.start.column,
                message: None,
                style,
            });
            self.add_line_marker(note.span.end.line, LineMarker::FromStart {
                connect_col,
                arrow_col: note.span.end.column - 1,
                message: note.message.as_ref().map(AsRef::as_ref),
                style,
            });
        }
    }

    fn add_line_marker(&mut self, line: u32, marker: LineMarker<'a>) {
        self.line_markers
            .entry(line)
            .or_insert_with(Vec::new)
            .push(marker);
    }

    fn print_annotations(&mut self) {
        let line_markers = ::std::mem::replace(&mut self.line_markers, BTreeMap::new());
        let mut last_printed = None;
        for (line, markers) in line_markers {
            // println!("now: {}, prev: {:?}", line, last_printed);
            if let Some(prev) = last_printed {
                if self.full_connection_cols.len() > 0 {
                    if line - prev > 2 {
                        self.print_line(prev + 1);
                        self.print_gap_line();
                        self.print_line(line - 1);
                    } else {
                        for line in (prev + 1)..line {
                            self.print_line(line);
                        }
                    }
                } else if line - prev > 1 {
                    self.print_gap_line();
                }
            }
            last_printed = Some(line);
            self.print_line_and_markers(line, markers);
        }
    }

    fn print_line_and_markers(&mut self, line: u32, mut markers: Vec<LineMarker>) {
        assert!(markers.len() > 0, "line has no markers");
        self.print_line(line);
        self.print_immediate_markers(&markers);
        // last span has its message printed inline
        println!(" {}", markers
            .iter()
            .next_back()
            .unwrap()
            .message()
            .unwrap_or(""));
        markers.pop();

        // non-arrow markers without messages don't extend below first line
        markers.retain(|m| m.message().is_some() || m.is_arrow());

        // possibly print additional line so that instead of
        //      let x = 1;
        //          ~~~  ~ first note
        //            second note
        // we would get
        //      let x = 1;
        //          ~~~  ~ first note
        //            |
        //            second note
        match markers.iter().next_back().cloned() {
            Some(LineMarker::FromTo { end_col, .. }) => {
                self.print_markers(&markers, end_col);
                println!();
            }
            Some(LineMarker::FromStart { arrow_col, message, .. })
                if message.is_some() =>
            {
                self.print_markers(&markers, arrow_col + 1);
                println!();
            }
            _ => {}
        }
        for i in (1..(markers.len() + 1)).rev() {
            let markers = &markers[0..i];
            match &markers[i - 1] {
                &LineMarker::FromTo { end_col, message, .. } => {
                    self.print_markers(markers, end_col - 1);
                    println!("{}", message.unwrap_or(""));
                }
                &LineMarker::FromStart { arrow_col, message, .. } => {
                    self.print_markers(markers, arrow_col + 2);
                    println!("{}", message.unwrap_or(""));
                }
            }
        }
    }

    fn print_line(&mut self, line: u32) {
        self.print_line_header(Some(line), None);
        for ch in self.lines.get((line - 1) as usize).unwrap_or(&"").chars() {
            match ch {
                // print these chars as one space, otherwise
                // they will break note alignment with code
                '\t' | '\r' => print!(" "),
                ch => print!("{}", ch),
            }
        }
        println!();
    }

    fn print_line_header(&mut self, line: Option<u32>, arrow_from: Option<u32>) {
        if let Some(line) = line {
            print!("{: >width$} |  ", line, width = self.number_space);
        } else {
            print!("{: >width$} |  ", "", width = self.number_space);
        }
        for col in 0..self.next_connect_col {
            if self.full_connection_cols.contains(&col) {
                print!("|");
            } else {
                match arrow_from {
                    Some(c) if c < col => print!("_"),
                    _ => print!(" "),
                }
            }
            if arrow_from == Some(col) {
                if self.full_connection_cols.contains(&col) {
                    self.full_connection_cols.remove(&col);
                } else {
                    self.full_connection_cols.insert(col);
                }
            }
        }
    }

    fn print_gap_line(&mut self) {
        print!("{: <width$}", "...", width = self.number_space + 4);
        for col in 0..self.next_connect_col {
            if self.full_connection_cols.contains(&col) {
                print!("|");
            } else {
                print!(" ");
            }
        }
        println!();
    }

    fn print_immediate_markers(&mut self, markers: &[LineMarker]) {
        let (connect, arrow_end) = match markers.iter().next_back().unwrap() {
            &LineMarker::FromStart { connect_col, arrow_col, .. } => {
                (Some(connect_col), arrow_col - 1)
            }
            _ => {
                (None, 0)
            }
        };
        self.print_line_header(None, connect);
        let last_col = markers.iter().next_back().unwrap().end_col();
        for col in 1..last_col {
            let mut part = MarkerPart::None;
            if col <= arrow_end {
                part = MarkerPart::ArrowBottom;
            }
            for (index, marker) in markers.iter().rev().enumerate() {
                match *marker {
                    LineMarker::FromStart { arrow_col, style, .. } => {
                        if arrow_col == col {
                            part = part.or(style.to_marker_part(true));
                        }
                    }
                    LineMarker::FromTo { start_col, end_col, style, message } => {
                        if start_col <= col && col < end_col {
                            part = part.or(style.to_marker_part(false));
                        }
                        if start_col == col
                            && end_col == start_col + 1 // marker is one col wide
                            && index > 0 // and not the last one in line
                            && message.is_some() // and has a message
                            && style != MarkerStyle::Primary // and it is not primary
                        {
                            part = part.or(MarkerPart::SingleColumn);
                        }
                    }
                }
            }
            print!("{}", part.to_char());
        }
    }

    fn print_markers(&mut self, markers: &[LineMarker], last_col: u32) {
        let (connect, arrow_end) = match markers.iter().next_back().unwrap() {
            &LineMarker::FromStart { connect_col, arrow_col, .. } => {
                (Some(connect_col), arrow_col - 1)
            }
            _ => {
                (None, 0)
            }
        };
        self.print_line_header(None, connect);
        for col in 1..last_col {
            let mut part = MarkerPart::None;
            if col <= arrow_end {
                part = MarkerPart::ArrowBottom;
            }
            for marker in markers.iter().rev() {
                match *marker {
                    LineMarker::FromStart { arrow_col, .. } => {
                        if arrow_col == col {
                            part = MarkerPart::SingleColumn;
                        }
                    }
                    LineMarker::FromTo { end_col, message, .. } => {
                        if end_col == col + 1 && message.is_some() {
                            part = MarkerPart::SingleColumn;
                        }
                    }
                }
            }
            print!("{}", part.to_char());
        }
    }
}

fn number_length(mut num: u32) -> u32 {
    let mut len = 1;
    while num >= 10 {
        len += 1;
        num /= 10;
    }
    len
}

pub fn print_diagnostic(source: &str, diagnostic: &Diagnostic) {
    Printer::new(source).pretty_print(diagnostic)
}

pub fn print_diagnostics(source: &str, diagnostics: &[Diagnostic]) {
    let mut printer = Printer::new(source);
    for diagnostic in diagnostics {
        printer.pretty_print(diagnostic);
        println!("");
    }
}
<|endoftext|>


<commit_before>use std::hash::{Hash};
use std::slice::{
    Items,
};
use std::fmt;
use test;

// FIXME: These aren't stable, so a public wrapper of node/edge indices
// should be lifetimed just like pointers.
#[deriving(Copy, Clone, Show, PartialEq, PartialOrd, Eq, Hash)]
pub struct NodeIndex(uint);
#[deriving(Copy, Clone, Show, PartialEq, PartialOrd, Eq, Hash)]
pub struct EdgeIndex(uint);

const EdgeEnd: EdgeIndex = EdgeIndex(::std::uint::MAX);
//const InvalidNode: NodeIndex = NodeIndex(::std::uint::MAX);

/// Index into the EdgeIndex arrays
enum Dir {
    Out = 0,
    In = 1
}

#[deriving(Show)]
pub struct Node<N> {
    pub data: N,
    next: [EdgeIndex, ..2],
}

#[deriving(Show, Copy)]
pub struct Edge<E> {
    pub data: E,
    next: [EdgeIndex, ..2],
    a: NodeIndex,
    b: NodeIndex,
}

/// **OGraph\<N, E\>** is a directed graph using an adjacency list representation.
///
/// The graph maintains unique indices for nodes and edges, so both node and edge
/// data may be accessed mutably. Removing nodes or edges from the graph is expensive,
/// while adding is very cheap.
///
/// Based upon the graph implementation in rustc.
//#[deriving(Show)]
pub struct OGraph<N> {
    nodes: Vec<Node<N>>,
    edges: Vec<Edge<()>>,
}

impl<N: fmt::Show> fmt::Show for OGraph<N>
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for n in self.nodes.iter() {
            try!(writeln!(f, "{}", n));
        }
        for n in self.edges.iter() {
            try!(writeln!(f, "{}", n));
        }
        Ok(())
    }
}

pub enum Pair<'a, T: 'a> {
    Both(&'a mut T, &'a mut T),
    One(&'a mut T),
    None,
}

pub fn index_twice<T>(slc: &mut [T], a: uint, b: uint) -> Pair<T>
{
    if a == b {
        slc.get_mut(a).map_or(Pair::None, Pair::One)
    } else {
        if a >= slc.len() || b >= slc.len() {
            Pair::None
        } else {
            // safe because a, b are in bounds and distinct
            unsafe {
                let ar = &mut *(slc.unsafe_mut(a) as *mut _);
                let br = &mut *(slc.unsafe_mut(b) as *mut _);
                Pair::Both(ar, br)
            }
        }
    }
}

impl<N> OGraph<N>
//where N: fmt::Show
{
    pub fn new() -> OGraph<N>
    {
        OGraph{nodes: Vec::new(), edges: Vec::new()}
    }

    pub fn add_node(&mut self, data: N) -> NodeIndex
    {
        let node = Node{data: data, next: [EdgeEnd, EdgeEnd]};
        let node_idx = NodeIndex(self.nodes.len());
        self.nodes.push(node);
        node_idx
    }

    pub fn node(&self, a: NodeIndex) -> Option<&N>
    {
        self.nodes.get(a.0).map(|n| &n.data)
    }

    pub fn node_mut(&mut self, a: NodeIndex) -> Option<&mut N>
    {
        self.nodes.get_mut(a.0).map(|n| &mut n.data)
    }

    pub fn neighbors(&self, a: NodeIndex) -> Neighbors<N>
    {
        Neighbors{
            graph: self,
            next: match self.nodes.get(a.0) {
                None => EdgeEnd,
                Some(n) => n.next[0],
            }
        }
    }

    pub fn add_edge(&mut self, a: NodeIndex, b: NodeIndex) -> EdgeIndex
    {
        let edge_idx = EdgeIndex(self.edges.len());
        match index_twice(self.nodes[mut], a.0, b.0) {
            Pair::None => panic!("NodeIndices out of bounds"),
            Pair::One(an) => {
                let edge = Edge {
                    data: (),
                    a: a,
                    b: b,
                    next: an.next,
                };
                an.next[0] = edge_idx;
                an.next[1] = edge_idx;
                self.edges.push(edge);
            }
            Pair::Both(an, bn) => {
                // a and b are different indices
                let edge = Edge {
                    data: (),
                    a: a,
                    b: b,
                    next: [an.next[0], bn.next[1]],
                };
                an.next[0] = edge_idx;
                bn.next[1] = edge_idx;
                self.edges.push(edge);
            }
        }
        edge_idx
    }

    pub fn remove_node(&mut self, a: NodeIndex) -> Option<N>
    {
        match self.nodes.get(a.0) {
            None => return None,
            _ => {}
        }
        // Remove all edges from and to this node.
        loop {
            let next = self.nodes[a.0].next[0];
            if next == EdgeEnd {
                break
            }
            //println!("Rmove edge {}", next);
            self.remove_edge(next);
        }

        loop {
            let next = self.nodes[a.0].next[1];
            if next == EdgeEnd {
                break
            }
            //println!("Rmove edge {}", next);
            self.remove_edge(next);
        }

        //println!("REMOVED EDGES: {}", self);

        // Adjust all node indices affected
        for edge in self.edges.iter_mut() {
            debug_assert!(edge.a != a);
            debug_assert!(edge.b != a);
            if edge.a > a {
                edge.a.0 -= 1;
            }
            if edge.b > a {
                edge.b.0 -= 1;
            }
        }
        self.nodes.remove(a.0).map(|n|n.data)
    }

    pub fn edge_mut(&mut self, e: EdgeIndex) -> &mut Edge<()>
    {
        &mut self.edges[e.0]
    }

    pub fn remove_edge(&mut self, e: EdgeIndex)
    {
        fn update_edge_list(replace: EdgeIndex, fst: EdgeIndex, edges: &mut [Edge<()>], d: Dir) {
            debug_assert!(fst != replace);
            let k = d as uint;
            let edge_next = edges[replace.0].next[k];
            // walk through edge list
            let mut cur = fst;
            while cur != EdgeEnd {
                let curedge = &mut edges[cur.0];
                if curedge.next[k] == replace {
                    //println!("Have to replace link in {}", curedge);
                    curedge.next[k] = edge_next;
                    break
                } else {
                    cur = curedge.next[k];
                }
            }
        }
        // every edge is part of two lists,
        // outgoing and incoming edges.
        // Remove it from both
        let (edge_a, edge_b, edge_next) = match self.edges.get(e.0) {
            None => return,
            Some(x) => (x.a, x.b, x.next),
        };
        {
            // List out from A
            let node = &mut self.nodes[edge_a.0];
            let fst = node.next[0];
            if fst == e {
                node.next[0] = edge_next[0];
            } else {
                update_edge_list(e, fst, self.edges[mut], Dir::Out);
            }
        }
        {
            // List in to B
            let node = &mut self.nodes[edge_b.0];
            let fst = node.next[1];
            if fst == e {
                node.next[1] = edge_next[1];
            } else {
                update_edge_list(e, fst, self.edges[mut], Dir::In);
            }
        }
        self.remove_edge_adjust_indices(e);
    }

    fn remove_edge_adjust_indices(&mut self, e: EdgeIndex) -> Option<()>
    {
        // swap_remove the edge -- only the removed edge
        // and the edge swapped into place are affected and need updating
        // indices.
        let edge = self.edges.swap_remove(e.0).unwrap();
        if self.edges.len() == e.0 {
            return Some(edge.data);
        }
        let swapped_e = EdgeIndex(self.edges.len());
        let swapped_edge = self.edges[e.0];

        fn update_edge_list(replace: EdgeIndex, fst: EdgeIndex, new: EdgeIndex, edges: &mut [Edge<()>], d: Dir) {
            debug_assert!(fst != replace);
            let k = d as uint;
            // walk through edge list
            let mut cur = fst;
            while cur != EdgeEnd {
                let curedge = &mut edges[cur.0];
                if curedge.next[k] == replace {
                    //println!("Have to replace link in {}", curedge);
                    curedge.next[k] = new;
                    break
                } else {
                    cur = curedge.next[k];
                }
            }
        }
        {
            // List out from A
            let node = &mut self.nodes[swapped_edge.a.0];
            let fst = node.next[0];
            if fst == swapped_e {
                node.next[0] = e;
            } else {
                update_edge_list(swapped_e, fst, e, self.edges[mut], Dir::Out);
            }
        }
        {
            // List in to B
            let node = &mut self.nodes[swapped_edge.b.0];
            let fst = node.next[1];
            if fst == swapped_e {
                node.next[1] = e;
            } else {
                update_edge_list(swapped_e, fst, e, self.edges[mut], Dir::In);
            }
        }
        // All that refer to the swapped edge need to update.
        //
        /*
        // Edge lists are fine, so remove the edge and adjust all edge indices in nodes
        let edge_data = self.edges.remove(e.0).unwrap().data;
        for &k in [0u, 1].iter() {
            for node in self.nodes.iter_mut() {
                debug_assert!(node.next[k] != e);
                if node.next[k] != EdgeEnd && node.next[k] > e {
                    node.next[k].0 -= 1;
                }
            }
            for edge in self.edges.iter_mut() {
                debug_assert!(edge.next[k] != e);
                if edge.next[k] != EdgeEnd && edge.next[k] > e {
                    edge.next[k].0 -= 1;
                }
            }
        }
        */
        let edge_data = edge.data;
        Some(edge_data)
    }
}

pub struct Neighbors<'a, N: 'a> {
    graph: &'a OGraph<N>,
    next: EdgeIndex,
}

impl<'a, N> Iterator<NodeIndex> for Neighbors<'a, N>
{
    fn next(&mut self) -> Option<NodeIndex>
    {
        match self.graph.edges.get(self.next.0) {
            None => None,
            Some(edge) => {
                self.next = edge.next[0];
                Some(edge.b)
            }
        }
    }
}

#[bench]
fn bench_inser(b: &mut test::Bencher) {
    let mut og = OGraph::new();
    let fst = og.add_node(0i);
    for x in range(1, 125) {
        let n = og.add_node(x);
        og.add_edge(fst, n);
    }
    b.iter(|| {
        og.add_node(1)
    })
}

#[bench]
fn bench_remove(b: &mut test::Bencher) {
    // removal is very slow in a big graph.
    // and this one doesn't even have many nodes.
    let mut og = OGraph::new();
    let fst = og.add_node(0i);
    let mut prev = fst;
    for x in range(1, 1250) {
        let n = og.add_node(x);
        og.add_edge(prev, n);
        prev = n;
    }
    //println!("{}", og);
    b.iter(|| {
        for _ in range(0, 100i) {
            og.remove_node(fst);
        }
    })
}
<commit_msg>Fix copying of edge<commit_after>use std::hash::{Hash};
use std::slice::{
    Items,
};
use std::fmt;
use test;

// FIXME: These aren't stable, so a public wrapper of node/edge indices
// should be lifetimed just like pointers.
#[deriving(Copy, Clone, Show, PartialEq, PartialOrd, Eq, Hash)]
pub struct NodeIndex(uint);
#[deriving(Copy, Clone, Show, PartialEq, PartialOrd, Eq, Hash)]
pub struct EdgeIndex(uint);

const EdgeEnd: EdgeIndex = EdgeIndex(::std::uint::MAX);
//const InvalidNode: NodeIndex = NodeIndex(::std::uint::MAX);

/// Index into the EdgeIndex arrays
enum Dir {
    Out = 0,
    In = 1
}

#[deriving(Show)]
pub struct Node<N> {
    pub data: N,
    next: [EdgeIndex, ..2],
}

#[deriving(Show, Copy)]
pub struct Edge<E> {
    pub data: E,
    next: [EdgeIndex, ..2],
    a: NodeIndex,
    b: NodeIndex,
}

/// **OGraph\<N, E\>** is a directed graph using an adjacency list representation.
///
/// The graph maintains unique indices for nodes and edges, so both node and edge
/// data may be accessed mutably. Removing nodes or edges from the graph is expensive,
/// while adding is very cheap.
///
/// Based upon the graph implementation in rustc.
//#[deriving(Show)]
pub struct OGraph<N> {
    nodes: Vec<Node<N>>,
    edges: Vec<Edge<()>>,
}

impl<N: fmt::Show> fmt::Show for OGraph<N>
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for n in self.nodes.iter() {
            try!(writeln!(f, "{}", n));
        }
        for n in self.edges.iter() {
            try!(writeln!(f, "{}", n));
        }
        Ok(())
    }
}

pub enum Pair<'a, T: 'a> {
    Both(&'a mut T, &'a mut T),
    One(&'a mut T),
    None,
}

pub fn index_twice<T>(slc: &mut [T], a: uint, b: uint) -> Pair<T>
{
    if a == b {
        slc.get_mut(a).map_or(Pair::None, Pair::One)
    } else {
        if a >= slc.len() || b >= slc.len() {
            Pair::None
        } else {
            // safe because a, b are in bounds and distinct
            unsafe {
                let ar = &mut *(slc.unsafe_mut(a) as *mut _);
                let br = &mut *(slc.unsafe_mut(b) as *mut _);
                Pair::Both(ar, br)
            }
        }
    }
}

impl<N> OGraph<N>
//where N: fmt::Show
{
    pub fn new() -> OGraph<N>
    {
        OGraph{nodes: Vec::new(), edges: Vec::new()}
    }

    pub fn add_node(&mut self, data: N) -> NodeIndex
    {
        let node = Node{data: data, next: [EdgeEnd, EdgeEnd]};
        let node_idx = NodeIndex(self.nodes.len());
        self.nodes.push(node);
        node_idx
    }

    pub fn node(&self, a: NodeIndex) -> Option<&N>
    {
        self.nodes.get(a.0).map(|n| &n.data)
    }

    pub fn node_mut(&mut self, a: NodeIndex) -> Option<&mut N>
    {
        self.nodes.get_mut(a.0).map(|n| &mut n.data)
    }

    pub fn neighbors(&self, a: NodeIndex) -> Neighbors<N>
    {
        Neighbors{
            graph: self,
            next: match self.nodes.get(a.0) {
                None => EdgeEnd,
                Some(n) => n.next[0],
            }
        }
    }

    pub fn add_edge(&mut self, a: NodeIndex, b: NodeIndex) -> EdgeIndex
    {
        let edge_idx = EdgeIndex(self.edges.len());
        match index_twice(self.nodes[mut], a.0, b.0) {
            Pair::None => panic!("NodeIndices out of bounds"),
            Pair::One(an) => {
                let edge = Edge {
                    data: (),
                    a: a,
                    b: b,
                    next: an.next,
                };
                an.next[0] = edge_idx;
                an.next[1] = edge_idx;
                self.edges.push(edge);
            }
            Pair::Both(an, bn) => {
                // a and b are different indices
                let edge = Edge {
                    data: (),
                    a: a,
                    b: b,
                    next: [an.next[0], bn.next[1]],
                };
                an.next[0] = edge_idx;
                bn.next[1] = edge_idx;
                self.edges.push(edge);
            }
        }
        edge_idx
    }

    pub fn remove_node(&mut self, a: NodeIndex) -> Option<N>
    {
        match self.nodes.get(a.0) {
            None => return None,
            _ => {}
        }
        // Remove all edges from and to this node.
        loop {
            let next = self.nodes[a.0].next[0];
            if next == EdgeEnd {
                break
            }
            //println!("Rmove edge {}", next);
            self.remove_edge(next);
        }

        loop {
            let next = self.nodes[a.0].next[1];
            if next == EdgeEnd {
                break
            }
            //println!("Rmove edge {}", next);
            self.remove_edge(next);
        }

        //println!("REMOVED EDGES: {}", self);

        // Adjust all node indices affected
        for edge in self.edges.iter_mut() {
            debug_assert!(edge.a != a);
            debug_assert!(edge.b != a);
            if edge.a > a {
                edge.a.0 -= 1;
            }
            if edge.b > a {
                edge.b.0 -= 1;
            }
        }
        self.nodes.remove(a.0).map(|n|n.data)
    }

    pub fn edge_mut(&mut self, e: EdgeIndex) -> &mut Edge<()>
    {
        &mut self.edges[e.0]
    }

    pub fn remove_edge(&mut self, e: EdgeIndex)
    {
        fn update_edge_list(replace: EdgeIndex, fst: EdgeIndex, edges: &mut [Edge<()>], d: Dir) {
            debug_assert!(fst != replace);
            let k = d as uint;
            let edge_next = edges[replace.0].next[k];
            // walk through edge list
            let mut cur = fst;
            while cur != EdgeEnd {
                let curedge = &mut edges[cur.0];
                if curedge.next[k] == replace {
                    //println!("Have to replace link in {}", curedge);
                    curedge.next[k] = edge_next;
                    break
                } else {
                    cur = curedge.next[k];
                }
            }
        }
        // every edge is part of two lists,
        // outgoing and incoming edges.
        // Remove it from both
        let (edge_a, edge_b, edge_next) = match self.edges.get(e.0) {
            None => return,
            Some(x) => (x.a, x.b, x.next),
        };
        {
            // List out from A
            let node = &mut self.nodes[edge_a.0];
            let fst = node.next[0];
            if fst == e {
                node.next[0] = edge_next[0];
            } else {
                update_edge_list(e, fst, self.edges[mut], Dir::Out);
            }
        }
        {
            // List in to B
            let node = &mut self.nodes[edge_b.0];
            let fst = node.next[1];
            if fst == e {
                node.next[1] = edge_next[1];
            } else {
                update_edge_list(e, fst, self.edges[mut], Dir::In);
            }
        }
        self.remove_edge_adjust_indices(e);
    }

    fn remove_edge_adjust_indices(&mut self, e: EdgeIndex) -> Option<()>
    {
        // swap_remove the edge -- only the removed edge
        // and the edge swapped into place are affected and need updating
        // indices.
        let edge = self.edges.swap_remove(e.0).unwrap();
        let (swap_a, swap_b) = match self.edges.get(e.0) {
            // no elment needed to be swapped.
            None => return Some(edge.data),
            Some(ed) => (ed.a, ed.b),
        };
        let swapped_e = EdgeIndex(self.edges.len());

        fn update_edge_list(replace: EdgeIndex, fst: EdgeIndex, new: EdgeIndex, edges: &mut [Edge<()>], d: Dir) {
            debug_assert!(fst != replace);
            let k = d as uint;
            // walk through edge list
            let mut cur = fst;
            while cur != EdgeEnd {
                let curedge = &mut edges[cur.0];
                if curedge.next[k] == replace {
                    //println!("Have to replace link in {}", curedge);
                    curedge.next[k] = new;
                    break
                } else {
                    cur = curedge.next[k];
                }
            }
        }
        {
            // List out from A
            let node = &mut self.nodes[swap_a.0];
            let fst = node.next[0];
            if fst == swapped_e {
                node.next[0] = e;
            } else {
                update_edge_list(swapped_e, fst, e, self.edges[mut], Dir::Out);
            }
        }
        {
            // List in to B
            let node = &mut self.nodes[swap_b.0];
            let fst = node.next[1];
            if fst == swapped_e {
                node.next[1] = e;
            } else {
                update_edge_list(swapped_e, fst, e, self.edges[mut], Dir::In);
            }
        }
        // All that refer to the swapped edge need to update.
        //
        /*
        // Edge lists are fine, so remove the edge and adjust all edge indices in nodes
        let edge_data = self.edges.remove(e.0).unwrap().data;
        for &k in [0u, 1].iter() {
            for node in self.nodes.iter_mut() {
                debug_assert!(node.next[k] != e);
                if node.next[k] != EdgeEnd && node.next[k] > e {
                    node.next[k].0 -= 1;
                }
            }
            for edge in self.edges.iter_mut() {
                debug_assert!(edge.next[k] != e);
                if edge.next[k] != EdgeEnd && edge.next[k] > e {
                    edge.next[k].0 -= 1;
                }
            }
        }
        */
        let edge_data = edge.data;
        Some(edge_data)
    }
}

pub struct Neighbors<'a, N: 'a> {
    graph: &'a OGraph<N>,
    next: EdgeIndex,
}

impl<'a, N> Iterator<NodeIndex> for Neighbors<'a, N>
{
    fn next(&mut self) -> Option<NodeIndex>
    {
        match self.graph.edges.get(self.next.0) {
            None => None,
            Some(edge) => {
                self.next = edge.next[0];
                Some(edge.b)
            }
        }
    }
}

#[bench]
fn bench_inser(b: &mut test::Bencher) {
    let mut og = OGraph::new();
    let fst = og.add_node(0i);
    for x in range(1, 125) {
        let n = og.add_node(x);
        og.add_edge(fst, n);
    }
    b.iter(|| {
        og.add_node(1)
    })
}

#[bench]
fn bench_remove(b: &mut test::Bencher) {
    // removal is very slow in a big graph.
    // and this one doesn't even have many nodes.
    let mut og = OGraph::new();
    let fst = og.add_node(0i);
    let mut prev = fst;
    for x in range(1, 1250) {
        let n = og.add_node(x);
        og.add_edge(prev, n);
        prev = n;
    }
    //println!("{}", og);
    b.iter(|| {
        for _ in range(0, 100i) {
            og.remove_node(fst);
        }
    })
}
<|endoftext|>


<commit_before>use std::cmp::max;
use std::iter::{AdditiveIterator, repeat};

use column::{Column, Cell};
use column::Alignment::Left;
use dir::Dir;
use file::File;
use options::Columns;
use users::OSUsers;

use ansi_term::Style::Plain;

#[derive(PartialEq, Copy, Debug)]
pub enum View {
    Details(Columns, bool, bool),
    Lines,
    Grid(bool, usize),
}

impl View {
    pub fn view(&self, dir: Option<&Dir>, files: &[File]) {
        match *self {
            View::Grid(across, width)       => grid_view(across, width, files),
            View::Details(ref cols, header, tree) => details_view(&*cols.for_dir(dir), files, header, tree),
            View::Lines                     => lines_view(files),
        }
    }
}

/// The lines view literally just displays each file, line-by-line.
fn lines_view(files: &[File]) {
    for file in files.iter() {
        println!("{}", file.file_name_view().text);
    }
}

fn fit_into_grid(across: bool, console_width: usize, files: &[File]) -> Option<(usize, Vec<usize>)> {
    // TODO: this function could almost certainly be optimised...
    // surely not *all* of the numbers of lines are worth searching through!

    // Instead of numbers of columns, try to find the fewest number of *lines*
    // that the output will fit in.
    for num_lines in range(1, files.len()) {

        // The number of columns is the number of files divided by the number
        // of lines, *rounded up*.
        let mut num_columns = files.len() / num_lines;
        if files.len() % num_lines != 0 {
            num_columns += 1;
        }

        // Early abort: if there are so many columns that the width of the
        // *column separators* is bigger than the width of the screen, then
        // don't even try to tabulate it.
        // This is actually a necessary check, because the width is stored as
        // a usize, and making it go negative makes it huge instead, but it
        // also serves as a speed-up.
        let separator_width = (num_columns - 1) * 2;
        if console_width < separator_width {
            continue;
        }

        // Remove the separator width from the available space.
        let adjusted_width = console_width - separator_width;

        // Find the width of each column by adding the lengths of the file
        // names in that column up.
        let mut column_widths: Vec<usize> = repeat(0).take(num_columns).collect();
        for (index, file) in files.iter().enumerate() {
            let index = if across {
                index % num_columns
            }
            else {
                index / num_lines
            };
            column_widths[index] = max(column_widths[index], file.name.len());
        }

        // If they all fit in the terminal, combined, then success!
        if column_widths.iter().map(|&x| x).sum() < adjusted_width {
            return Some((num_lines, column_widths));
        }
    }

    // If you get here you have really long file names.
    return None;
}

fn grid_view(across: bool, console_width: usize, files: &[File]) {
    if let Some((num_lines, widths)) = fit_into_grid(across, console_width, files) {
        for y in range(0, num_lines) {
            for x in range(0, widths.len()) {
                let num = if across {
                    y * widths.len() + x
                }
                else {
                    y + num_lines * x
                };

                // Show whitespace in the place of trailing files
                if num >= files.len() {
                    continue;
                }

                let ref file = files[num];
                let styled_name = file.file_colour().paint(file.name.as_slice()).to_string();
                if x == widths.len() - 1 {
                    // The final column doesn't need to have trailing spaces
                    print!("{}", styled_name);
                }
                else {
                    assert!(widths[x] >= file.name.len());
                    print!("{}", Left.pad_string(&styled_name, widths[x] - file.name.len() + 2));
                }
            }
            print!("\n");
        }
    }
    else {
        // Drop down to lines view if the file names are too big for a grid
        lines_view(files);
    }
}

fn details_view(columns: &[Column], files: &[File], header: bool, tree: bool) {
    // The output gets formatted into columns, which looks nicer. To
    // do this, we have to write the results into a table, instead of
    // displaying each file immediately, then calculating the maximum
    // width of each column based on the length of the results and
    // padding the fields during output.

    let mut cache = OSUsers::empty_cache();

    let mut table = Vec::new();
    get_files(columns, &mut cache, tree, &mut table, files, 0);

    if header {
        table.insert(0, (0, columns.iter().map(|c| Cell::paint(Plain.underline(), c.header())).collect()));
    }

    let column_widths: Vec<usize> = range(0, columns.len())
        .map(|n| table.iter().map(|row| row.1[n].length).max().unwrap_or(0))
        .collect();

    for &(depth, ref row) in table.iter() {
        for _ in range(0, depth) {
            print!("#");
        }

        for (num, column) in columns.iter().enumerate() {
            if num != 0 {
                print!(" ");  // Separator
            }

            if num == columns.len() - 1 {
                // The final column doesn't need to have trailing spaces
                print!("{}", row[num].text);
            }
            else {
                let padding = column_widths[num] - row[num].length;
                print!("{}", column.alignment().pad_string(&row[num].text, padding));
            }
        }
        print!("\n");
    }
}

fn get_files(columns: &[Column], cache: &mut OSUsers, recurse: bool, dest: &mut Vec<(usize, Vec<Cell>)>, src: &[File], depth: usize) {
    for file in src.iter() {
        let cols = columns.iter().map(|c| file.display(c, cache)).collect();
        dest.push((depth, cols));

        if recurse {
            if let Some(ref dir) = file.this {
                get_files(columns, cache, recurse, dest, dir.files(true).as_slice(), depth + 1);
            }
        }
    }
}
<commit_msg>Replace tuple with actual struct<commit_after>use std::cmp::max;
use std::iter::{AdditiveIterator, repeat};

use column::{Column, Cell};
use column::Alignment::Left;
use dir::Dir;
use file::File;
use options::Columns;
use users::OSUsers;

use ansi_term::Style::Plain;

#[derive(PartialEq, Copy, Debug)]
pub enum View {
    Details(Columns, bool, bool),
    Lines,
    Grid(bool, usize),
}

impl View {
    pub fn view(&self, dir: Option<&Dir>, files: &[File]) {
        match *self {
            View::Grid(across, width)       => grid_view(across, width, files),
            View::Details(ref cols, header, tree) => details_view(&*cols.for_dir(dir), files, header, tree),
            View::Lines                     => lines_view(files),
        }
    }
}

/// The lines view literally just displays each file, line-by-line.
fn lines_view(files: &[File]) {
    for file in files.iter() {
        println!("{}", file.file_name_view().text);
    }
}

fn fit_into_grid(across: bool, console_width: usize, files: &[File]) -> Option<(usize, Vec<usize>)> {
    // TODO: this function could almost certainly be optimised...
    // surely not *all* of the numbers of lines are worth searching through!

    // Instead of numbers of columns, try to find the fewest number of *lines*
    // that the output will fit in.
    for num_lines in range(1, files.len()) {

        // The number of columns is the number of files divided by the number
        // of lines, *rounded up*.
        let mut num_columns = files.len() / num_lines;
        if files.len() % num_lines != 0 {
            num_columns += 1;
        }

        // Early abort: if there are so many columns that the width of the
        // *column separators* is bigger than the width of the screen, then
        // don't even try to tabulate it.
        // This is actually a necessary check, because the width is stored as
        // a usize, and making it go negative makes it huge instead, but it
        // also serves as a speed-up.
        let separator_width = (num_columns - 1) * 2;
        if console_width < separator_width {
            continue;
        }

        // Remove the separator width from the available space.
        let adjusted_width = console_width - separator_width;

        // Find the width of each column by adding the lengths of the file
        // names in that column up.
        let mut column_widths: Vec<usize> = repeat(0).take(num_columns).collect();
        for (index, file) in files.iter().enumerate() {
            let index = if across {
                index % num_columns
            }
            else {
                index / num_lines
            };
            column_widths[index] = max(column_widths[index], file.name.len());
        }

        // If they all fit in the terminal, combined, then success!
        if column_widths.iter().map(|&x| x).sum() < adjusted_width {
            return Some((num_lines, column_widths));
        }
    }

    // If you get here you have really long file names.
    return None;
}

fn grid_view(across: bool, console_width: usize, files: &[File]) {
    if let Some((num_lines, widths)) = fit_into_grid(across, console_width, files) {
        for y in range(0, num_lines) {
            for x in range(0, widths.len()) {
                let num = if across {
                    y * widths.len() + x
                }
                else {
                    y + num_lines * x
                };

                // Show whitespace in the place of trailing files
                if num >= files.len() {
                    continue;
                }

                let ref file = files[num];
                let styled_name = file.file_colour().paint(file.name.as_slice()).to_string();
                if x == widths.len() - 1 {
                    // The final column doesn't need to have trailing spaces
                    print!("{}", styled_name);
                }
                else {
                    assert!(widths[x] >= file.name.len());
                    print!("{}", Left.pad_string(&styled_name, widths[x] - file.name.len() + 2));
                }
            }
            print!("\n");
        }
    }
    else {
        // Drop down to lines view if the file names are too big for a grid
        lines_view(files);
    }
}

fn details_view(columns: &[Column], files: &[File], header: bool, tree: bool) {
    // The output gets formatted into columns, which looks nicer. To
    // do this, we have to write the results into a table, instead of
    // displaying each file immediately, then calculating the maximum
    // width of each column based on the length of the results and
    // padding the fields during output.

    let mut cache = OSUsers::empty_cache();

    let mut table = Vec::new();
    get_files(columns, &mut cache, tree, &mut table, files, 0);

    if header {
        let row = Row {
            depth: 0,
            cells: columns.iter().map(|c| Cell::paint(Plain.underline(), c.header())).collect()
        };

        table.insert(0, row);
    }

    let column_widths: Vec<usize> = range(0, columns.len())
        .map(|n| table.iter().map(|row| row.cells[n].length).max().unwrap_or(0))
        .collect();

    for row in table.iter() {
        for _ in range(0, row.depth) {
            print!("#");
        }

        for (num, column) in columns.iter().enumerate() {
            if num != 0 {
                print!(" ");  // Separator
            }

            if num == columns.len() - 1 {
                // The final column doesn't need to have trailing spaces
                print!("{}", row.cells[num].text);
            }
            else {
                let padding = column_widths[num] - row.cells[num].length;
                print!("{}", column.alignment().pad_string(&row.cells[num].text, padding));
            }
        }
        print!("\n");
    }
}

fn get_files(columns: &[Column], cache: &mut OSUsers, recurse: bool, dest: &mut Vec<Row>, src: &[File], depth: u8) {
    for file in src.iter() {

        let row = Row {
            depth: depth,
            cells: columns.iter().map(|c| file.display(c, cache)).collect(),
        };

        dest.push(row);

        if recurse {
            if let Some(ref dir) = file.this {
                get_files(columns, cache, recurse, dest, dir.files(true).as_slice(), depth + 1);
            }
        }
    }
}

struct Row {
    pub depth: u8,
    pub cells: Vec<Cell>,
}
<|endoftext|>


<commit_before>use super::Expr;
use super::Atom;
use super::token::{Token, Tokenizer};

pub struct Parser<'a> {
    current_token: Option<Token<'a>>,
    tokenizer: Tokenizer<'a>,
}

impl<'a> Parser<'a> {
    pub fn new(s: &'a str) -> Parser<'a> {
        Parser {
            current_token: None,
            tokenizer: Tokenizer::new(s, true),
        }
    }

    // skips the current token
    fn skip(&mut self) {
        assert!(self.current_token.is_some());
        self.current_token = None;
    }

    // returns the current token.
    fn token(&mut self) -> Option<Token<'a>> {
        if let Some(token) = self.current_token {
            return Some(token);
        }
        assert!(self.current_token.is_none());
        self.current_token = self.tokenizer.next();
        self.current_token
    }

    pub fn at_end(&mut self) -> bool {
        self.token().is_none()
    }

    // Returns either the successfully parsed expression, or
    // the invalid token which was not expected.
    pub fn parse_expr(&mut self) -> Result<Expr, Token<'a>> {
        let current = self.token().unwrap();
        match current {
            Token::Str(s) => {
                self.skip();
                Ok(Expr::from(s))
            }
            Token::UInt(u) => {
                self.skip();
                Ok(Expr::from(Atom::UInt(u)))
            }
            Token::SInt(s) => {
                self.skip();
                Ok(Expr::from(Atom::SInt(s)))
            }
            Token::Float(s) => {
                self.skip();
                Ok(Expr::from(Atom::Float(s)))
            }
            Token::OpenBrace => {
                self.skip();
                let mut exprs = vec![];
                loop {
                    if let Some(Token::CloseBrace) = self.token() {
                        self.skip();
                        break;
                    }
                    match self.parse_expr() {
                        Ok(ex) => exprs.push(ex),
                        Err(tok) => return Err(tok),
                    }
                }
                Ok(Expr::Tuple(exprs))
            }
            tok => Err(tok),
        }
    }
}

#[test]
fn test_parse_expr() {
    let mut p = Parser::new("123.45");
    assert_eq!(Ok(Expr::from(123.45)), p.parse_expr());
    assert_eq!(true, p.at_end());

    let mut p = Parser::new("123");
    assert_eq!(Ok(Expr::from(123usize)), p.parse_expr());
    assert_eq!(true, p.at_end());

    let mut p = Parser::new("(123)");
    assert_eq!(Ok(Expr::from((123usize,))), p.parse_expr());
    assert_eq!(true, p.at_end());

    let mut p = Parser::new("(test 123)   ");
    assert_eq!(Ok(Expr::from(("test", 123usize))), p.parse_expr());
    assert_eq!(true, p.at_end());

    let mut p = Parser::new("(test 123)   123");
    assert_eq!(Ok(Expr::from(("test", 123usize))), p.parse_expr());
    assert_eq!(false, p.at_end());
}
<commit_msg>Refactor the parser so that it does not require to peek.<commit_after>use super::Expr;
use super::Atom;
use super::token::{Token, Tokenizer};

pub struct Parser<'a> {
    tokenizer: Tokenizer<'a>,
}

#[derive(Debug, PartialEq)]
pub enum ParseError<'a> {
    UnexpectedToken(Token<'a>),
    UnexpectedEnd,
}

impl<'a> Parser<'a> {
    pub fn new(s: &'a str) -> Parser<'a> {
        Parser { tokenizer: Tokenizer::new(s, true) }
    }

    pub fn at_end(&mut self) -> bool {
        self.tokenizer.next().is_none()
    }

    // Returns either the successfully parsed expression, or
    // the invalid token which was not expected.
    pub fn parse_expr(&mut self) -> Result<Expr, ParseError<'a>> {
        match self.tokenizer.next() {
            None => Err(ParseError::UnexpectedEnd),
            Some(tok) => {
                match tok {
                    Token::Str(s) => Ok(Expr::from(s)),
                    Token::UInt(u) => Ok(Expr::from(Atom::UInt(u))),
                    Token::SInt(s) => Ok(Expr::from(Atom::SInt(s))),
                    Token::Float(s) => Ok(Expr::from(Atom::Float(s))),
                    Token::OpenBrace => {
                        let mut exprs = vec![];
                        loop {
                            match self.parse_expr() {
                                Ok(ex) => exprs.push(ex),
                                Err(ParseError::UnexpectedToken(Token::CloseBrace)) => break,
                                Err(err) => return Err(err),
                            }
                        }
                        Ok(Expr::Tuple(exprs))
                    }
                    tok => Err(ParseError::UnexpectedToken(tok)),
                }
            }
        }
    }
}

#[test]
fn test_parse_expr() {
    let mut p = Parser::new("123.45");
    assert_eq!(Ok(Expr::from(123.45)), p.parse_expr());
    assert_eq!(true, p.at_end());

    let mut p = Parser::new("123");
    assert_eq!(Ok(Expr::from(123usize)), p.parse_expr());
    assert_eq!(true, p.at_end());

    let mut p = Parser::new("(123)");
    assert_eq!(Ok(Expr::from((123usize,))), p.parse_expr());
    assert_eq!(true, p.at_end());

    let mut p = Parser::new("(test 123)   ");
    assert_eq!(Ok(Expr::from(("test", 123usize))), p.parse_expr());
    assert_eq!(true, p.at_end());

    let mut p = Parser::new("(test 123)   123");
    assert_eq!(Ok(Expr::from(("test", 123usize))), p.parse_expr());
    assert_eq!(false, p.at_end());

    let mut p = Parser::new("   ");
    assert_eq!(Err(ParseError::UnexpectedEnd), p.parse_expr());

    let mut p = Parser::new("(abc    ");
    assert_eq!(Err(ParseError::UnexpectedEnd), p.parse_expr());

    let mut p = Parser::new("(abc  }  ");
    assert_eq!(Err(ParseError::UnexpectedToken(Token::CloseCurly)),
               p.parse_expr());
}
<|endoftext|>


<commit_before>use ast::*;
use scanner::{Lexeme, Position, Token, TokenWithContext};
use std::iter::Peekable;

/// This behave exactly as try! but wraps the returned result in a Some.
/// It's useful to remove some boilerplate in the code introduced by
/// the use of Option<Result<T, E>>
macro_rules! try_wrap_err {
    ($e:expr) => (match $e {Ok(e) => e, Err(e) => return Some(Err(e))})
}

#[derive(Debug)]
pub enum ParseError {
    UnconsumedTokens,
    UnexpectedEndOfFile,
    UnexpectedToken(Lexeme, Position),
    MissingSubexpression(Lexeme, Position),
    MissingClosingParen(Lexeme, Position),
}

pub fn parse(tokens: Vec<TokenWithContext>) -> Result<Expr, Vec<ParseError>> {
    let mut iter = tokens.iter().peekable();
    if let Some(result) = parse_expression(&mut iter) {
        match result {
            Ok(expr) => {
                if let None = iter.next() {
                    Ok(expr)
                } else {
                    Err(vec![ParseError::UnconsumedTokens])
                }
            }
            Err(error) => {
                {
                    synchronise(&mut iter);
                }
                Err(vec![error])
            }
        }

    } else {
        Err(vec![ParseError::UnexpectedEndOfFile])
    }
}

fn synchronise<'a, I>(tokens: &mut Peekable<I>)
    where I: Iterator<Item = &'a TokenWithContext>
{
    enum TokenKind {
        StartOfConstruct,
        BodyOfConstruct,
        EndOfConstruct,
    };
    fn classify(token: &Token) -> TokenKind {
        match token {
            &Token::Semicolon => TokenKind::EndOfConstruct,
            &Token::Class => TokenKind::StartOfConstruct,
            &Token::Fun => TokenKind::StartOfConstruct,
            &Token::Var => TokenKind::StartOfConstruct,
            &Token::For => TokenKind::StartOfConstruct,
            &Token::If => TokenKind::StartOfConstruct,
            &Token::While => TokenKind::StartOfConstruct,
            &Token::Print => TokenKind::StartOfConstruct,
            &Token::Return => TokenKind::StartOfConstruct,
            _ => TokenKind::BodyOfConstruct,
        }
    }
    while let Some(token_kind) = tokens.peek().map(|t| classify(&t.token)) {
        match token_kind {
            TokenKind::StartOfConstruct => {
                break;
            }
            TokenKind::BodyOfConstruct => {
                let _ = tokens.next();
            }
            TokenKind::EndOfConstruct => {
                let _ = tokens.next();
                break;
            }
        }
    }
}

fn parse_expression<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    parse_equality(tokens)
}

fn parse_binary<'a, I>(tokens: &mut Peekable<I>,
                       map_operator: &Fn(&Token) -> Option<BinaryOperator>,
                       parse_subexpression: &Fn(&mut Peekable<I>)
                                                -> Option<Result<Expr, ParseError>>)
                       -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    let mut expr;
    {
        let result = parse_subexpression(tokens);
        if let Some(Ok(subexpression)) = result {
            expr = subexpression;
        } else {
            return result;
        }
    };
    while let Some(Some(mapped_operator)) = tokens.peek().map(|pt| map_operator(&pt.token)) {
        let operator; // We know it's right, we read it just for error reporting
        {
            operator = tokens.next().unwrap();
        }
        let right;
        {
            if let Some(result) = parse_subexpression(tokens) {
                right = try_wrap_err!(result);
            } else {
                return Some(Err(ParseError::MissingSubexpression(operator.lexeme.clone(),
                                                                 operator.position)));
            }
        };
        let binary_expression = BinaryExpr {
            left: expr,
            operator: mapped_operator,
            right: right,
        };
        expr = Expr::Binary(Box::new(binary_expression));
    }
    Some(Ok(expr))
}

fn parse_equality<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<BinaryOperator> {
        match token {
            &Token::BangEqual => Some(BinaryOperator::NotEqual),
            &Token::EqualEqual => Some(BinaryOperator::Equal),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_comparison)
}

fn parse_comparison<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<BinaryOperator> {
        match token {
            &Token::Greater => Some(BinaryOperator::Greater),
            &Token::GreaterEqual => Some(BinaryOperator::GreaterEqual),
            &Token::Less => Some(BinaryOperator::Less),
            &Token::LessEqual => Some(BinaryOperator::LessEqual),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_term)
}

fn parse_term<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<BinaryOperator> {
        match token {
            &Token::Minus => Some(BinaryOperator::Minus),
            &Token::Plus => Some(BinaryOperator::Plus),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_factor)
}

fn parse_factor<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<BinaryOperator> {
        match token {
            &Token::Slash => Some(BinaryOperator::Slash),
            &Token::Star => Some(BinaryOperator::Star),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_unary)
}

fn parse_unary<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<UnaryOperator> {
        match token {
            &Token::Minus => Some(UnaryOperator::Minus),
            &Token::Bang => Some(UnaryOperator::Bang),
            _ => None,
        }
    }
    if let Some(Some(mapped_operator)) = tokens.peek().map(|pt| map_operator(&pt.token)) {
        let operator; // For error reporting
        {
            operator = tokens.next().unwrap();
        }
        let right = if let Some(result) = parse_unary(tokens) {
            try_wrap_err!(result)
        } else {
            return Some(Err(ParseError::MissingSubexpression(operator.lexeme.clone(),
                                                             operator.position)));
        };
        let unary_expression = UnaryExpr {
            operator: mapped_operator,
            right: right,
        };
        return Some(Ok(Expr::Unary(Box::new(unary_expression))));
    } else {
        parse_primary(tokens)
    }
}

fn parse_primary<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    let primary_token;
    {
        primary_token = tokens.next();
    };
    if let Some(primary_token) = primary_token {
        let parsed_expression = match primary_token.token {
            Token::False => Expr::Literal(Literal::BoolLiteral(false)),
            Token::True => Expr::Literal(Literal::BoolLiteral(true)),
            Token::Nil => Expr::Literal(Literal::NilLiteral),
            Token::NumberLiteral(n) => Expr::Literal(Literal::NumberLiteral(n)),
            Token::StringLiteral(ref s) => Expr::Literal(Literal::StringLiteral(s.clone())),
            Token::LeftParen => {
                let expr = if let Some(result) = parse_expression(tokens) {
                    try_wrap_err!(result)
                } else {
                    return Some(Err(ParseError::UnexpectedEndOfFile));
                };
                {
                    if let Some(token) = tokens.next() {
                        if token.token == Token::RightParen {
                            let grouping_expression = Grouping { expr: expr };
                            return Some(Ok(Expr::Grouping(Box::new(grouping_expression))));
                        } else {
                            return Some(Err(ParseError::MissingClosingParen(token.lexeme.clone(),
                                                                            token.position)));
                        }

                    }
                    return Some(Err(ParseError::UnexpectedEndOfFile));
                }
            }
            _ => {
                return Some(Err(ParseError::UnexpectedToken(primary_token.lexeme.clone(),
                                                            primary_token.position)));
            }
        };
        Some(Ok(parsed_expression))
    } else {
        None
    }
}

#[cfg(test)]
mod tests {
    use scanner::*;
    use parser::*;
    use pretty_printer::PrettyPrint;

    #[test]
    fn literal() {
        let string = String::from("123");
        let (tokens, _) = scan(&string);
        let expr = parse(tokens).unwrap();
        assert_eq!(&string, &expr.pretty_print());
    }

    #[test]
    fn binary() {
        let (tokens, _) = scan(&"123+456");
        let expr = parse(tokens).unwrap();
        assert_eq!("(+ 123 456)", &expr.pretty_print());
    }

    #[test]
    fn precedence_add_mul() {
        let (tokens, _) = scan(&"123+456*789");
        let expr = parse(tokens).unwrap();
        assert_eq!("(+ 123 (* 456 789))", &expr.pretty_print());
    }

    #[test]
    fn precedence_mul_add() {
        let (tokens, _) = scan(&"123*456+789");
        let expr = parse(tokens).unwrap();
        assert_eq!("(+ (* 123 456) 789)", &expr.pretty_print());
    }

    #[test]
    fn precedence_mul_add_unary() {
        let (tokens, _) = scan(&"-123*456+789");
        let expr = parse(tokens).unwrap();
        assert_eq!("(+ (* (- 123) 456) 789)", &expr.pretty_print());
    }

    #[test]
    fn unclosed_group() {
        let (tokens, _) = scan(&"(2");
        assert!(parse(tokens).is_err());
    }

    #[test]
    fn unopened_group() {
        let (tokens, _) = scan(&"2)");
        assert!(parse(tokens).is_err());
    }
}
<commit_msg>[clippy] dereference on all paths<commit_after>use ast::*;
use scanner::{Lexeme, Position, Token, TokenWithContext};
use std::iter::Peekable;

/// This behave exactly as try! but wraps the returned result in a Some.
/// It's useful to remove some boilerplate in the code introduced by
/// the use of Option<Result<T, E>>
macro_rules! try_wrap_err {
    ($e:expr) => (match $e {Ok(e) => e, Err(e) => return Some(Err(e))})
}

#[derive(Debug)]
pub enum ParseError {
    UnconsumedTokens,
    UnexpectedEndOfFile,
    UnexpectedToken(Lexeme, Position),
    MissingSubexpression(Lexeme, Position),
    MissingClosingParen(Lexeme, Position),
}

pub fn parse(tokens: Vec<TokenWithContext>) -> Result<Expr, Vec<ParseError>> {
    let mut iter = tokens.iter().peekable();
    if let Some(result) = parse_expression(&mut iter) {
        match result {
            Ok(expr) => {
                if let None = iter.next() {
                    Ok(expr)
                } else {
                    Err(vec![ParseError::UnconsumedTokens])
                }
            }
            Err(error) => {
                {
                    synchronise(&mut iter);
                }
                Err(vec![error])
            }
        }

    } else {
        Err(vec![ParseError::UnexpectedEndOfFile])
    }
}

fn synchronise<'a, I>(tokens: &mut Peekable<I>)
    where I: Iterator<Item = &'a TokenWithContext>
{
    enum TokenKind {
        StartOfConstruct,
        BodyOfConstruct,
        EndOfConstruct,
    };
    fn classify(token: &Token) -> TokenKind {
        match token {
            &Token::Semicolon => TokenKind::EndOfConstruct,
            &Token::Class => TokenKind::StartOfConstruct,
            &Token::Fun => TokenKind::StartOfConstruct,
            &Token::Var => TokenKind::StartOfConstruct,
            &Token::For => TokenKind::StartOfConstruct,
            &Token::If => TokenKind::StartOfConstruct,
            &Token::While => TokenKind::StartOfConstruct,
            &Token::Print => TokenKind::StartOfConstruct,
            &Token::Return => TokenKind::StartOfConstruct,
            _ => TokenKind::BodyOfConstruct,
        }
    }
    while let Some(token_kind) = tokens.peek().map(|t| classify(&t.token)) {
        match token_kind {
            TokenKind::StartOfConstruct => {
                break;
            }
            TokenKind::BodyOfConstruct => {
                let _ = tokens.next();
            }
            TokenKind::EndOfConstruct => {
                let _ = tokens.next();
                break;
            }
        }
    }
}

fn parse_expression<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    parse_equality(tokens)
}

fn parse_binary<'a, I>(tokens: &mut Peekable<I>,
                       map_operator: &Fn(&Token) -> Option<BinaryOperator>,
                       parse_subexpression: &Fn(&mut Peekable<I>)
                                                -> Option<Result<Expr, ParseError>>)
                       -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    let mut expr;
    {
        let result = parse_subexpression(tokens);
        if let Some(Ok(subexpression)) = result {
            expr = subexpression;
        } else {
            return result;
        }
    };
    while let Some(Some(mapped_operator)) = tokens.peek().map(|pt| map_operator(&pt.token)) {
        let operator; // We know it's right, we read it just for error reporting
        {
            operator = tokens.next().unwrap();
        }
        let right;
        {
            if let Some(result) = parse_subexpression(tokens) {
                right = try_wrap_err!(result);
            } else {
                return Some(Err(ParseError::MissingSubexpression(operator.lexeme.clone(),
                                                                 operator.position)));
            }
        };
        let binary_expression = BinaryExpr {
            left: expr,
            operator: mapped_operator,
            right: right,
        };
        expr = Expr::Binary(Box::new(binary_expression));
    }
    Some(Ok(expr))
}

fn parse_equality<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<BinaryOperator> {
        match *token {
            Token::BangEqual => Some(BinaryOperator::NotEqual),
            Token::EqualEqual => Some(BinaryOperator::Equal),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_comparison)
}

fn parse_comparison<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<BinaryOperator> {
        match *token {
            Token::Greater => Some(BinaryOperator::Greater),
            Token::GreaterEqual => Some(BinaryOperator::GreaterEqual),
            Token::Less => Some(BinaryOperator::Less),
            Token::LessEqual => Some(BinaryOperator::LessEqual),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_term)
}

fn parse_term<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<BinaryOperator> {
        match *token {
            Token::Minus => Some(BinaryOperator::Minus),
            Token::Plus => Some(BinaryOperator::Plus),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_factor)
}

fn parse_factor<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<BinaryOperator> {
        match *token {
            Token::Slash => Some(BinaryOperator::Slash),
            Token::Star => Some(BinaryOperator::Star),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_unary)
}

fn parse_unary<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<UnaryOperator> {
        match *token {
            Token::Minus => Some(UnaryOperator::Minus),
            Token::Bang => Some(UnaryOperator::Bang),
            _ => None,
        }
    }
    if let Some(Some(mapped_operator)) = tokens.peek().map(|pt| map_operator(&pt.token)) {
        let operator; // For error reporting
        {
            operator = tokens.next().unwrap();
        }
        let right = if let Some(result) = parse_unary(tokens) {
            try_wrap_err!(result)
        } else {
            return Some(Err(ParseError::MissingSubexpression(operator.lexeme.clone(),
                                                             operator.position)));
        };
        let unary_expression = UnaryExpr {
            operator: mapped_operator,
            right: right,
        };
        return Some(Ok(Expr::Unary(Box::new(unary_expression))));
    } else {
        parse_primary(tokens)
    }
}

fn parse_primary<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    let primary_token;
    {
        primary_token = tokens.next();
    };
    if let Some(primary_token) = primary_token {
        let parsed_expression = match primary_token.token {
            Token::False => Expr::Literal(Literal::BoolLiteral(false)),
            Token::True => Expr::Literal(Literal::BoolLiteral(true)),
            Token::Nil => Expr::Literal(Literal::NilLiteral),
            Token::NumberLiteral(n) => Expr::Literal(Literal::NumberLiteral(n)),
            Token::StringLiteral(ref s) => Expr::Literal(Literal::StringLiteral(s.clone())),
            Token::LeftParen => {
                let expr = if let Some(result) = parse_expression(tokens) {
                    try_wrap_err!(result)
                } else {
                    return Some(Err(ParseError::UnexpectedEndOfFile));
                };
                {
                    if let Some(token) = tokens.next() {
                        if token.token == Token::RightParen {
                            let grouping_expression = Grouping { expr: expr };
                            return Some(Ok(Expr::Grouping(Box::new(grouping_expression))));
                        } else {
                            return Some(Err(ParseError::MissingClosingParen(token.lexeme.clone(),
                                                                            token.position)));
                        }

                    }
                    return Some(Err(ParseError::UnexpectedEndOfFile));
                }
            }
            _ => {
                return Some(Err(ParseError::UnexpectedToken(primary_token.lexeme.clone(),
                                                            primary_token.position)));
            }
        };
        Some(Ok(parsed_expression))
    } else {
        None
    }
}

#[cfg(test)]
mod tests {
    use scanner::*;
    use parser::*;
    use pretty_printer::PrettyPrint;

    #[test]
    fn literal() {
        let string = String::from("123");
        let (tokens, _) = scan(&string);
        let expr = parse(tokens).unwrap();
        assert_eq!(&string, &expr.pretty_print());
    }

    #[test]
    fn binary() {
        let (tokens, _) = scan(&"123+456");
        let expr = parse(tokens).unwrap();
        assert_eq!("(+ 123 456)", &expr.pretty_print());
    }

    #[test]
    fn precedence_add_mul() {
        let (tokens, _) = scan(&"123+456*789");
        let expr = parse(tokens).unwrap();
        assert_eq!("(+ 123 (* 456 789))", &expr.pretty_print());
    }

    #[test]
    fn precedence_mul_add() {
        let (tokens, _) = scan(&"123*456+789");
        let expr = parse(tokens).unwrap();
        assert_eq!("(+ (* 123 456) 789)", &expr.pretty_print());
    }

    #[test]
    fn precedence_mul_add_unary() {
        let (tokens, _) = scan(&"-123*456+789");
        let expr = parse(tokens).unwrap();
        assert_eq!("(+ (* (- 123) 456) 789)", &expr.pretty_print());
    }

    #[test]
    fn unclosed_group() {
        let (tokens, _) = scan(&"(2");
        assert!(parse(tokens).is_err());
    }

    #[test]
    fn unopened_group() {
        let (tokens, _) = scan(&"2)");
        assert!(parse(tokens).is_err());
    }
}
<|endoftext|>


<commit_before>use ast::*;
use scanner::{Token, TokenWithContext};
use std::iter::Peekable;

pub fn parse(tokens: Vec<TokenWithContext>) -> Expr {
    let mut iter = tokens.iter().peekable();
    parse_expression(&mut iter)
}

fn parse_expression<'a, I>(tokens: &mut Peekable<I>) -> Expr
    where I: Iterator<Item = &'a TokenWithContext>
{
    parse_equality(tokens)
}

fn parse_binary<'a, I>(tokens: &mut Peekable<I>,
                       map_operator: &Fn(&Token) -> Option<Operator>,
                       parse_subexpression: &Fn(&mut Peekable<I>) -> Expr)
                       -> Expr
    where I: Iterator<Item = &'a TokenWithContext>
{
    let mut expr;
    {
        expr = parse_subexpression(tokens);
    };
    let peeked_token;
    {
        peeked_token = tokens.peek().cloned(); // Can I avoid this?
    };
    while let Some(peeked_token) = peeked_token {
        if let Some(mapped_operator) = map_operator(&peeked_token.token) {
            {
                // Just advance, we know all we need from the peeked value
                let _ = tokens.next();
            }
            let right;
            {
                right = parse_subexpression(tokens);
            };
            let binary_expression = BinaryExpr {
                left: expr,
                operator: mapped_operator,
                right: right,
            };
            expr = Expr::Binary(Box::new(binary_expression));
        } else {
            break;
        }
    }
    expr
}

fn parse_equality<'a, I>(tokens: &mut Peekable<I>) -> Expr
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::BangEqual => Some(Operator::NotEqual),
            &Token::EqualEqual => Some(Operator::Equal),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_comparison)
}

fn parse_comparison<'a, I>(tokens: &mut Peekable<I>) -> Expr
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::Greater => Some(Operator::Greater),
            &Token::GreaterEqual => Some(Operator::GreaterEqual),
            &Token::Less => Some(Operator::Less),
            &Token::LessEqual => Some(Operator::LessEqual),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_term)
}

fn parse_term<'a, I>(tokens: &mut Peekable<I>) -> Expr
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::Minus => Some(Operator::Minus),
            &Token::Plus => Some(Operator::Plus),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_factor)
}

fn parse_factor<'a, I>(tokens: &mut Peekable<I>) -> Expr
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::Slash => Some(Operator::Slash),
            &Token::Star => Some(Operator::Star),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_unary)
}

fn parse_unary<'a, I>(tokens: &mut Peekable<I>) -> Expr
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::Minus => Some(Operator::Minus),
            &Token::Bang => Some(Operator::Bang),
            _ => None,
        }
    }
    let peeked_token;
    {
        peeked_token = tokens.peek().cloned(); // Can I avoid this?
    };
    if let Some(Some(mapped_operator)) =
        peeked_token.map(|pt| &pt.token)
            .map(map_operator) {
        {
            // Just advance, we know all we need from the peeked value
            let _ = tokens.next();
        }
        let right;
        {
            right = parse_unary(tokens);
        };
        let unary_expression = UnaryExpr {
            operator: mapped_operator,
            right: right,
        };
        return Expr::Unary(Box::new(unary_expression));
    } else {
        parse_primary(tokens)
    }
}

fn parse_primary<'a, I>(tokens: &mut Peekable<I>) -> Expr
    where I: Iterator<Item = &'a TokenWithContext>
{
    let primary_token;
    {
        primary_token = tokens.next();
    };
    if let Some(primary_token) = primary_token {
        match primary_token.token {
            Token::False => Expr::Literal(Literal::BoolLiteral(false)),
            Token::True => Expr::Literal(Literal::BoolLiteral(true)),
            Token::Nil => Expr::Literal(Literal::NilLiteral),
            Token::NumberLiteral(n) => Expr::Literal(Literal::NumberLiteral(n)),
            Token::StringLiteral(ref s) => Expr::Literal(Literal::StringLiteral(s.clone())),
            Token::LeftParen => {
                let expr;
                {
                    expr = parse_expression(tokens);
                };
                {
                    if let Some(token) = tokens.next() {
                        if token.token == Token::LeftParen {
                            let grouping_expression = Grouping { expr: expr };
                            return Expr::Grouping(Box::new(grouping_expression));
                        }
                    }
                    unimplemented!()
                }
            }
            _ => unimplemented!(),
        }
    } else {
        unimplemented!()
    }
}

#[cfg(test)]
mod tests {
    use scanner::*;
    use parser::*;
    use pretty_printer::PrettyPrint;

    #[test]
    fn literal() {
        let tokens = scan(&"123".into()).unwrap();
        let expr = parse(tokens);
        assert_eq!("123", &expr.pretty_print());
    }
}
<commit_msg>Failing test<commit_after>use ast::*;
use scanner::{Token, TokenWithContext};
use std::iter::Peekable;

pub fn parse(tokens: Vec<TokenWithContext>) -> Expr {
    let mut iter = tokens.iter().peekable();
    parse_expression(&mut iter)
}

fn parse_expression<'a, I>(tokens: &mut Peekable<I>) -> Expr
    where I: Iterator<Item = &'a TokenWithContext>
{
    parse_equality(tokens)
}

fn parse_binary<'a, I>(tokens: &mut Peekable<I>,
                       map_operator: &Fn(&Token) -> Option<Operator>,
                       parse_subexpression: &Fn(&mut Peekable<I>) -> Expr)
                       -> Expr
    where I: Iterator<Item = &'a TokenWithContext>
{
    let mut expr;
    {
        expr = parse_subexpression(tokens);
    };
    let peeked_token;
    {
        peeked_token = tokens.peek().cloned(); // Can I avoid this?
    };
    while let Some(peeked_token) = peeked_token {
        if let Some(mapped_operator) = map_operator(&peeked_token.token) {
            {
                // Just advance, we know all we need from the peeked value
                let _ = tokens.next();
            }
            let right;
            {
                right = parse_subexpression(tokens);
            };
            let binary_expression = BinaryExpr {
                left: expr,
                operator: mapped_operator,
                right: right,
            };
            expr = Expr::Binary(Box::new(binary_expression));
        } else {
            break;
        }
    }
    expr
}

fn parse_equality<'a, I>(tokens: &mut Peekable<I>) -> Expr
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::BangEqual => Some(Operator::NotEqual),
            &Token::EqualEqual => Some(Operator::Equal),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_comparison)
}

fn parse_comparison<'a, I>(tokens: &mut Peekable<I>) -> Expr
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::Greater => Some(Operator::Greater),
            &Token::GreaterEqual => Some(Operator::GreaterEqual),
            &Token::Less => Some(Operator::Less),
            &Token::LessEqual => Some(Operator::LessEqual),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_term)
}

fn parse_term<'a, I>(tokens: &mut Peekable<I>) -> Expr
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::Minus => Some(Operator::Minus),
            &Token::Plus => Some(Operator::Plus),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_factor)
}

fn parse_factor<'a, I>(tokens: &mut Peekable<I>) -> Expr
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::Slash => Some(Operator::Slash),
            &Token::Star => Some(Operator::Star),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_unary)
}

fn parse_unary<'a, I>(tokens: &mut Peekable<I>) -> Expr
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::Minus => Some(Operator::Minus),
            &Token::Bang => Some(Operator::Bang),
            _ => None,
        }
    }
    let peeked_token;
    {
        peeked_token = tokens.peek().cloned(); // Can I avoid this?
    };
    if let Some(Some(mapped_operator)) =
        peeked_token.map(|pt| &pt.token)
            .map(map_operator) {
        {
            // Just advance, we know all we need from the peeked value
            let _ = tokens.next();
        }
        let right;
        {
            right = parse_unary(tokens);
        };
        let unary_expression = UnaryExpr {
            operator: mapped_operator,
            right: right,
        };
        return Expr::Unary(Box::new(unary_expression));
    } else {
        parse_primary(tokens)
    }
}

fn parse_primary<'a, I>(tokens: &mut Peekable<I>) -> Expr
    where I: Iterator<Item = &'a TokenWithContext>
{
    let primary_token;
    {
        primary_token = tokens.next();
    };
    if let Some(primary_token) = primary_token {
        match primary_token.token {
            Token::False => Expr::Literal(Literal::BoolLiteral(false)),
            Token::True => Expr::Literal(Literal::BoolLiteral(true)),
            Token::Nil => Expr::Literal(Literal::NilLiteral),
            Token::NumberLiteral(n) => Expr::Literal(Literal::NumberLiteral(n)),
            Token::StringLiteral(ref s) => Expr::Literal(Literal::StringLiteral(s.clone())),
            Token::LeftParen => {
                let expr;
                {
                    expr = parse_expression(tokens);
                };
                {
                    if let Some(token) = tokens.next() {
                        if token.token == Token::LeftParen {
                            let grouping_expression = Grouping { expr: expr };
                            return Expr::Grouping(Box::new(grouping_expression));
                        }
                    }
                    unimplemented!()
                }
            }
            _ => unimplemented!(),
        }
    } else {
        unimplemented!()
    }
}

#[cfg(test)]
mod tests {
    use scanner::*;
    use parser::*;
    use pretty_printer::PrettyPrint;

    #[test]
    fn literal() {
        let tokens = scan(&"123".into()).unwrap();
        let expr = parse(tokens);
        assert_eq!("123", &expr.pretty_print());
    }

    #[test]
    fn binary() {
        let tokens = scan(&"123+456".into()).unwrap();
        let expr = parse(tokens);
        assert_eq!("123 + 456", &expr.pretty_print());
    }
}
<|endoftext|>