1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
use std::io::Write;

use lalrpop_util::lalrpop_mod;

lalrpop_mod!(pub parser);
#[cfg(test)]
mod parser_tests;

pub trait Pretty {
    /// Pretty-print `Self` to the supplied writer.
    ///
    /// This function must only ever write valid utf8 strings.
    fn pretty_to<Writer: Write>(&self, writer: &mut Writer) -> Result<(), std::io::Error>;

    /// Pretty-print `Self` into a new string.
    fn pretty(&self) -> String {
        let mut writer = Vec::new();
        self.pretty_to(&mut writer)
            .expect("writing to Vec<u8> should never fail");
        String::from_utf8(writer).expect("we only ever write valid utf8")
    }
}

#[derive(Debug)]
pub enum Bound<'a> {
    Lifetime(&'a str),
    Item(Item<'a>),
    Reference {
        lifetime: &'a str,
        mut_: bool,
        item: Item<'a>,
    },
    Tuple(Vec<Bound<'a>>),
}

impl<'a> Bound<'a> {
    fn pretty_internal<Writer: Write>(
        &self,
        indent_level: usize,
        writer: &mut Writer,
    ) -> Result<(), std::io::Error> {
        indent(indent_level, writer)?;
        match self {
            Self::Lifetime(lifetime) => writer.write_all(lifetime.as_bytes()),
            Self::Item(item) => item.pretty_internal(indent_level, writer),
            Self::Reference {
                lifetime,
                mut_,
                item,
            } => {
                writer.write_all(b"&")?;
                writer.write_all(lifetime.as_bytes())?;
                if *mut_ {
                    writer.write_all(b" mut")?;
                }
                writer.write_all(b" ")?;
                item.pretty_internal(indent_level, writer)
            }
            Self::Tuple(bounds) => {
                writer.write_all(b"(\n")?;
                for (idx, bound) in bounds.iter().enumerate() {
                    bound.pretty_internal(indent_level + 1, writer)?;
                    if idx != bounds.len() - 1 {
                        writer.write_all(b",")?;
                    }
                    writer.write_all(b"\n")?;
                }
                indent(indent_level, writer)?;
                writer.write_all(b")")
            }
        }
    }
}

/// A struct, trait, enum, typedef, or generic bound.
#[derive(Debug)]
pub struct Item<'a> {
    /// Note that the name vector is backwards: `item[0]` is the item name; `item[1]` is the parent module, etc.
    name: Vec<&'a str>,
    generic_bounds: Vec<Bound<'a>>,
}

impl<'a> Item<'a> {
    fn pretty_internal<Writer: Write>(
        &self,
        indent_level: usize,
        writer: &mut Writer,
    ) -> Result<(), std::io::Error> {
        for (idx, component) in self.name.iter().enumerate().rev() {
            writer.write_all(component.as_bytes())?;
            if idx != 0 {
                writer.write_all(b"::")?;
            }
        }
        if !self.generic_bounds.is_empty() {
            writer.write_all(b"<\n")?;
            for (idx, bound) in self.generic_bounds.iter().enumerate() {
                bound.pretty_internal(indent_level + 1, writer)?;
                if idx != self.generic_bounds.len() - 1 {
                    writer.write_all(b",")?;
                }
                writer.write_all(b"\n")?;
            }
            indent(indent_level, writer)?;
            writer.write_all(b">")?;
        }
        Ok(())
    }
}

impl<'a> Pretty for Item<'a> {
    fn pretty_to<Writer: Write>(&self, writer: &mut Writer) -> Result<(), std::io::Error> {
        self.pretty_internal(0, writer)
    }
}

const INDENT: &'static [u8] = b"  ";
fn indent<Writer: Write>(indent_level: usize, writer: &mut Writer) -> Result<(), std::io::Error> {
    for _ in 0..indent_level {
        writer.write_all(INDENT)?;
    }
    Ok(())
}

#[derive(Debug)]
pub struct E0277<'a> {
    item: Item<'a>,
    trait_bound: Item<'a>,
}

impl<'a> Pretty for E0277<'a> {
    /// Pretty-print this Item to the supplied writer.
    fn pretty_to<Writer: Write>(&self, writer: &mut Writer) -> Result<(), std::io::Error> {
        writer.write_all(b"error[E0277]: the item:\n")?;
        writer.write_all(INDENT)?;
        self.item.pretty_internal(1, writer)?;
        writer.write_all(b"\ndoes not satisfy the trait bound:\n")?;
        writer.write_all(INDENT)?;
        self.trait_bound.pretty_internal(1, writer)?;
        Ok(())
    }
}