1 #![feature(rustc_private)]
4 extern crate env_logger;
5 extern crate rustc_ast;
6 extern crate rustc_span;
8 use std::cell::RefCell;
9 use std::collections::BTreeMap;
11 use std::error::Error;
15 use std::path::PathBuf;
17 use rustc_span::edition::DEFAULT_EDITION;
19 use rustdoc::html::markdown::{ErrorCodes, IdMap, Markdown, Playground};
21 pub struct ErrorMetadata {
22 pub description: Option<String>,
25 /// Mapping from error codes to metadata that can be (de)serialized.
26 pub type ErrorMetadataMap = BTreeMap<String, ErrorMetadata>;
30 Markdown(MarkdownFormatter),
35 fn from(format: &str, resource_suffix: &str) -> OutputFormat {
36 match &*format.to_lowercase() {
37 "html" => OutputFormat::HTML(HTMLFormatter(
38 RefCell::new(IdMap::new()),
39 resource_suffix.to_owned(),
41 "markdown" => OutputFormat::Markdown(MarkdownFormatter),
42 s => OutputFormat::Unknown(s.to_owned()),
48 fn header(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>>;
49 fn title(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>>;
52 output: &mut dyn Write,
55 ) -> Result<(), Box<dyn Error>>;
56 fn footer(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>>;
59 struct HTMLFormatter(RefCell<IdMap>, String);
60 struct MarkdownFormatter;
62 impl Formatter for HTMLFormatter {
63 fn header(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
69 <title>Rust Compiler Error Index</title>
70 <meta charset="utf-8">
71 <!-- Include rust.css after light.css so its rules take priority. -->
72 <link rel="stylesheet" type="text/css" href="light{suffix}.css"/>
73 <link rel="stylesheet" type="text/css" href="rust.css"/>
87 fn title(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
88 write!(output, "<h1>Rust Compiler Error Index</h1>\n")?;
94 output: &mut dyn Write,
97 ) -> Result<(), Box<dyn Error>> {
98 // Enclose each error in a div so they can be shown/hidden en masse.
99 let desc_desc = match info.description {
100 Some(_) => "error-described",
101 None => "error-undescribed",
103 write!(output, "<div class=\"{}\">", desc_desc)?;
105 // Error title (with self-link).
108 "<h2 id=\"{0}\" class=\"section-header\"><a href=\"#{0}\">{0}</a></h2>\n",
112 // Description rendered as markdown.
113 match info.description {
115 let mut id_map = self.0.borrow_mut();
116 let playground = Playground {
118 url: String::from("https://play.rust-lang.org/"),
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 for (var i = 0; i < arr.length; i++) {{
153 function hasClass(elem, className) {{
154 if (elem && className && elem.className) {{
155 var elemClass = elem.className;
156 var start = elemClass.indexOf(className);
159 }} else if (elemClass.length === className.length) {{
162 if (start > 0 && elemClass[start - 1] !== ' ') {{
165 var end = start + className.length;
166 if (end < elemClass.length && elemClass[end] !== ' ') {{
171 if (start > 0 && elemClass[start - 1] !== ' ') {{
174 var end = start + className.length;
175 if (end < elemClass.length && elemClass[end] !== ' ') {{
183 onEach(document.getElementsByClassName('rust-example-rendered'), function(e) {{
184 if (hasClass(e, 'compile_fail')) {{
185 e.addEventListener("mouseover", function(event) {{
186 e.previousElementSibling.childNodes[0].style.color = '#f00';
188 e.addEventListener("mouseout", function(event) {{
189 e.previousElementSibling.childNodes[0].style.color = '';
191 }} else if (hasClass(e, 'ignore')) {{
192 e.addEventListener("mouseover", function(event) {{
193 e.previousElementSibling.childNodes[0].style.color = '#ff9200';
195 e.addEventListener("mouseout", function(event) {{
196 e.previousElementSibling.childNodes[0].style.color = '';
208 impl Formatter for MarkdownFormatter {
209 #[allow(unused_variables)]
210 fn header(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
214 fn title(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
215 write!(output, "# Rust Compiler Error Index\n")?;
221 output: &mut dyn Write,
222 info: &ErrorMetadata,
224 ) -> Result<(), Box<dyn Error>> {
225 Ok(match info.description {
226 Some(ref desc) => write!(output, "## {}\n{}\n", err_code, desc)?,
231 #[allow(unused_variables)]
232 fn footer(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
237 /// Output an HTML page for the errors in `err_map` to `output_path`.
238 fn render_error_page<T: Formatter>(
239 err_map: &ErrorMetadataMap,
242 ) -> Result<(), Box<dyn Error>> {
243 let mut output_file = File::create(output_path)?;
245 formatter.header(&mut output_file)?;
246 formatter.title(&mut output_file)?;
248 for (err_code, info) in err_map {
249 formatter.error_code_block(&mut output_file, info, err_code)?;
252 formatter.footer(&mut output_file)
255 fn main_with_result(format: OutputFormat, dst: &Path) -> Result<(), Box<dyn Error>> {
256 let long_codes = register_all();
257 let mut err_map = BTreeMap::new();
258 for (code, desc) in long_codes {
259 err_map.insert(code.to_string(), ErrorMetadata { description: desc.map(String::from) });
262 OutputFormat::Unknown(s) => panic!("Unknown output format: {}", s),
263 OutputFormat::HTML(h) => render_error_page(&err_map, dst, h)?,
264 OutputFormat::Markdown(m) => render_error_page(&err_map, dst, m)?,
269 fn parse_args() -> (OutputFormat, PathBuf) {
270 let mut args = env::args().skip(1);
271 let format = args.next();
272 let dst = args.next();
273 let resource_suffix = args.next().unwrap_or_else(String::new);
275 .map(|a| OutputFormat::from(&a, &resource_suffix))
276 .unwrap_or(OutputFormat::from("html", &resource_suffix));
277 let dst = dst.map(PathBuf::from).unwrap_or_else(|| match format {
278 OutputFormat::HTML(..) => PathBuf::from("doc/error-index.html"),
279 OutputFormat::Markdown(..) => PathBuf::from("doc/error-index.md"),
280 OutputFormat::Unknown(..) => PathBuf::from("<nul>"),
287 let (format, dst) = parse_args();
288 let result = rustc_ast::with_default_globals(move || main_with_result(format, &dst));
289 if let Err(e) = result {
290 panic!("{}", e.to_string());
294 include!(concat!(env!("OUT_DIR"), "/error_codes.rs"));