1 #![feature(rustc_private)]
3 extern crate rustc_driver;
4 extern crate rustc_span;
6 use std::cell::RefCell;
7 use std::collections::BTreeMap;
13 use std::path::PathBuf;
15 use rustc_span::edition::DEFAULT_EDITION;
17 use rustdoc::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, Playground};
19 pub struct ErrorMetadata {
20 pub description: Option<String>,
23 /// Mapping from error codes to metadata that can be (de)serialized.
24 pub type ErrorMetadataMap = BTreeMap<String, ErrorMetadata>;
28 Markdown(MarkdownFormatter),
33 fn from(format: &str, resource_suffix: &str) -> OutputFormat {
34 match &*format.to_lowercase() {
35 "html" => OutputFormat::HTML(HTMLFormatter(
36 RefCell::new(IdMap::new()),
37 resource_suffix.to_owned(),
39 "markdown" => OutputFormat::Markdown(MarkdownFormatter),
40 s => OutputFormat::Unknown(s.to_owned()),
46 fn header(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>>;
47 fn title(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>>;
50 output: &mut dyn Write,
53 ) -> Result<(), Box<dyn Error>>;
54 fn footer(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>>;
57 struct HTMLFormatter(RefCell<IdMap>, String);
58 struct MarkdownFormatter;
60 impl Formatter for HTMLFormatter {
61 fn header(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
67 <title>Rust Compiler Error Index</title>
68 <meta charset="utf-8">
69 <!-- Include rust.css after light.css so its rules take priority. -->
70 <link rel="stylesheet" type="text/css" href="rustdoc{suffix}.css"/>
71 <link rel="stylesheet" type="text/css" href="light{suffix}.css"/>
72 <link rel="stylesheet" type="text/css" href="rust.css"/>
86 fn title(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
87 write!(output, "<h1>Rust Compiler Error Index</h1>\n")?;
93 output: &mut dyn Write,
96 ) -> Result<(), Box<dyn Error>> {
97 // Enclose each error in a div so they can be shown/hidden en masse.
98 let desc_desc = match info.description {
99 Some(_) => "error-described",
100 None => "error-undescribed",
102 write!(output, "<div class=\"{}\">", desc_desc)?;
104 // Error title (with self-link).
107 "<h2 id=\"{0}\" class=\"section-header\"><a href=\"#{0}\">{0}</a></h2>\n",
111 // Description rendered as markdown.
112 match info.description {
114 let mut id_map = self.0.borrow_mut();
115 let playground = Playground {
117 url: String::from("https://play.rust-lang.org/"),
126 error_codes: ErrorCodes::Yes,
127 edition: DEFAULT_EDITION,
128 playground: &Some(playground),
129 heading_offset: HeadingOffset::H1,
134 None => write!(output, "<p>No description.</p>\n")?,
137 write!(output, "</div>\n")?;
141 fn footer(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
145 function onEach(arr, func) {{
146 if (arr && arr.length > 0 && func) {{
147 var length = arr.length;
149 for (i = 0; i < length; ++i) {{
158 function onEachLazy(lazyArray, func) {{
160 Array.prototype.slice.call(lazyArray),
164 function hasClass(elem, className) {{
165 return elem && elem.classList && elem.classList.contains(className);
168 onEachLazy(document.getElementsByClassName('rust-example-rendered'), function(e) {{
169 if (hasClass(e, 'compile_fail')) {{
170 e.addEventListener("mouseover", function(event) {{
171 e.parentElement.previousElementSibling.childNodes[0].style.color = '#f00';
173 e.addEventListener("mouseout", function(event) {{
174 e.parentElement.previousElementSibling.childNodes[0].style.color = '';
176 }} else if (hasClass(e, 'ignore')) {{
177 e.addEventListener("mouseover", function(event) {{
178 e.parentElement.previousElementSibling.childNodes[0].style.color = '#ff9200';
180 e.addEventListener("mouseout", function(event) {{
181 e.parentElement.previousElementSibling.childNodes[0].style.color = '';
193 impl Formatter for MarkdownFormatter {
194 #[allow(unused_variables)]
195 fn header(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
199 fn title(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
200 write!(output, "# Rust Compiler Error Index\n")?;
206 output: &mut dyn Write,
207 info: &ErrorMetadata,
209 ) -> Result<(), Box<dyn Error>> {
210 Ok(match info.description {
211 Some(ref desc) => write!(output, "## {}\n{}\n", err_code, desc)?,
216 #[allow(unused_variables)]
217 fn footer(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
222 /// Output an HTML page for the errors in `err_map` to `output_path`.
223 fn render_error_page<T: Formatter>(
224 err_map: &ErrorMetadataMap,
227 ) -> Result<(), Box<dyn Error>> {
228 let mut output_file = File::create(output_path)?;
230 formatter.header(&mut output_file)?;
231 formatter.title(&mut output_file)?;
233 for (err_code, info) in err_map {
234 formatter.error_code_block(&mut output_file, info, err_code)?;
237 formatter.footer(&mut output_file)
240 fn main_with_result(format: OutputFormat, dst: &Path) -> Result<(), Box<dyn Error>> {
241 let long_codes = register_all();
242 let mut err_map = BTreeMap::new();
243 for (code, desc) in long_codes {
244 err_map.insert(code.to_string(), ErrorMetadata { description: desc.map(String::from) });
247 OutputFormat::Unknown(s) => panic!("Unknown output format: {}", s),
248 OutputFormat::HTML(h) => render_error_page(&err_map, dst, h)?,
249 OutputFormat::Markdown(m) => render_error_page(&err_map, dst, m)?,
254 fn parse_args() -> (OutputFormat, PathBuf) {
255 let mut args = env::args().skip(1);
256 let format = args.next();
257 let dst = args.next();
258 let resource_suffix = args.next().unwrap_or_else(String::new);
260 .map(|a| OutputFormat::from(&a, &resource_suffix))
261 .unwrap_or(OutputFormat::from("html", &resource_suffix));
262 let dst = dst.map(PathBuf::from).unwrap_or_else(|| match format {
263 OutputFormat::HTML(..) => PathBuf::from("doc/error-index.html"),
264 OutputFormat::Markdown(..) => PathBuf::from("doc/error-index.md"),
265 OutputFormat::Unknown(..) => PathBuf::from("<nul>"),
271 rustc_driver::init_env_logger("RUST_LOG");
272 let (format, dst) = parse_args();
274 rustc_span::create_default_session_globals_then(move || main_with_result(format, &dst));
275 if let Err(e) = result {
276 panic!("{}", e.to_string());
280 fn register_all() -> Vec<(&'static str, Option<&'static str>)> {
281 let mut long_codes: Vec<(&'static str, Option<&'static str>)> = Vec::new();
282 macro_rules! register_diagnostics {
283 ($($ecode:ident: $message:expr,)*) => (
284 register_diagnostics!{$($ecode:$message,)* ;}
287 ($($ecode:ident: $message:expr,)* ; $($code:ident,)*) => (
290 (stringify!($ecode), Some($message)),
296 ].iter().cloned().map(|s| (s, None)).collect::<Vec<_>>());}
300 include!(concat!(env!("OUT_DIR"), "/all_error_codes.rs"));