diff options
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/diagnostic.rs | 87 | ||||
| -rw-r--r-- | src/libsyntax/diagnostics/macros.rs | 51 | ||||
| -rw-r--r-- | src/libsyntax/diagnostics/plugin.rs | 132 | ||||
| -rw-r--r-- | src/libsyntax/diagnostics/registry.rs | 25 | ||||
| -rw-r--r-- | src/libsyntax/ext/build.rs | 6 | ||||
| -rw-r--r-- | src/libsyntax/ext/expand.rs | 4 | ||||
| -rw-r--r-- | src/libsyntax/lib.rs | 61 | ||||
| -rw-r--r-- | src/libsyntax/parse/lexer/mod.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/parse/mod.rs | 2 |
9 files changed, 307 insertions, 63 deletions
diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index e469f327ae8..9bb5eae2ed2 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -12,6 +12,7 @@ extern crate libc; use codemap::{Pos, Span}; use codemap; +use diagnostics; use std::cell::{RefCell, Cell}; use std::fmt; @@ -59,7 +60,7 @@ pub enum ColorConfig { pub trait Emitter { fn emit(&mut self, cmsp: Option<(&codemap::CodeMap, Span)>, - msg: &str, lvl: Level); + msg: &str, code: Option<&str>, lvl: Level); fn custom_emit(&mut self, cm: &codemap::CodeMap, sp: RenderSpan, msg: &str, lvl: Level); } @@ -90,6 +91,10 @@ impl SpanHandler { self.handler.emit(Some((&self.cm, sp)), msg, Error); self.handler.bump_err_count(); } + pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) { + self.handler.emit_with_code(Some((&self.cm, sp)), msg, code, Error); + self.handler.bump_err_count(); + } pub fn span_warn(&self, sp: Span, msg: &str) { self.handler.emit(Some((&self.cm, sp)), msg, Warning); } @@ -124,11 +129,11 @@ pub struct Handler { impl Handler { pub fn fatal(&self, msg: &str) -> ! { - self.emit.borrow_mut().emit(None, msg, Fatal); + self.emit.borrow_mut().emit(None, msg, None, Fatal); fail!(FatalError); } pub fn err(&self, msg: &str) { - self.emit.borrow_mut().emit(None, msg, Error); + self.emit.borrow_mut().emit(None, msg, None, Error); self.bump_err_count(); } pub fn bump_err_count(&self) { @@ -153,13 +158,13 @@ impl Handler { self.fatal(s.as_slice()); } pub fn warn(&self, msg: &str) { - self.emit.borrow_mut().emit(None, msg, Warning); + self.emit.borrow_mut().emit(None, msg, None, Warning); } pub fn note(&self, msg: &str) { - self.emit.borrow_mut().emit(None, msg, Note); + self.emit.borrow_mut().emit(None, msg, None, Note); } pub fn bug(&self, msg: &str) -> ! { - self.emit.borrow_mut().emit(None, msg, Bug); + self.emit.borrow_mut().emit(None, msg, None, Bug); fail!(ExplicitBug); } pub fn unimpl(&self, msg: &str) -> ! { @@ -169,7 +174,14 @@ impl Handler { cmsp: Option<(&codemap::CodeMap, Span)>, msg: &str, lvl: Level) { - self.emit.borrow_mut().emit(cmsp, msg, lvl); + self.emit.borrow_mut().emit(cmsp, msg, None, lvl); + } + pub fn emit_with_code(&self, + cmsp: Option<(&codemap::CodeMap, Span)>, + msg: &str, + code: &str, + lvl: Level) { + self.emit.borrow_mut().emit(cmsp, msg, Some(code), lvl); } pub fn custom_emit(&self, cm: &codemap::CodeMap, sp: RenderSpan, msg: &str, lvl: Level) { @@ -184,8 +196,9 @@ pub fn mk_span_handler(handler: Handler, cm: codemap::CodeMap) -> SpanHandler { } } -pub fn default_handler(color_config: ColorConfig) -> Handler { - mk_handler(box EmitterWriter::stderr(color_config)) +pub fn default_handler(color_config: ColorConfig, + registry: Option<diagnostics::registry::Registry>) -> Handler { + mk_handler(box EmitterWriter::stderr(color_config, registry)) } pub fn mk_handler(e: Box<Emitter + Send>) -> Handler { @@ -262,8 +275,8 @@ fn print_maybe_styled(w: &mut EmitterWriter, } } -fn print_diagnostic(dst: &mut EmitterWriter, - topic: &str, lvl: Level, msg: &str) -> io::IoResult<()> { +fn print_diagnostic(dst: &mut EmitterWriter, topic: &str, lvl: Level, + msg: &str, code: Option<&str>) -> io::IoResult<()> { if !topic.is_empty() { try!(write!(&mut dst.dst, "{} ", topic)); } @@ -272,13 +285,32 @@ fn print_diagnostic(dst: &mut EmitterWriter, format!("{}: ", lvl.to_string()).as_slice(), term::attr::ForegroundColor(lvl.color()))); try!(print_maybe_styled(dst, - format!("{}\n", msg).as_slice(), + format!("{}", msg).as_slice(), term::attr::Bold)); + + match code { + Some(code) => { + let style = term::attr::ForegroundColor(term::color::BRIGHT_MAGENTA); + try!(print_maybe_styled(dst, format!(" [{}]", code.clone()).as_slice(), style)); + match dst.registry.as_ref().and_then(|registry| registry.find_description(code)) { + Some(_) => { + try!(write!(&mut dst.dst, + " (pass `--explain {}` to see a detailed explanation)", + code + )); + } + None => () + } + } + None => () + } + try!(dst.dst.write_char('\n')); Ok(()) } pub struct EmitterWriter { dst: Destination, + registry: Option<diagnostics::registry::Registry> } enum Destination { @@ -287,7 +319,8 @@ enum Destination { } impl EmitterWriter { - pub fn stderr(color_config: ColorConfig) -> EmitterWriter { + pub fn stderr(color_config: ColorConfig, + registry: Option<diagnostics::registry::Registry>) -> EmitterWriter { let stderr = io::stderr(); let use_color = match color_config { @@ -301,14 +334,15 @@ impl EmitterWriter { Some(t) => Terminal(t), None => Raw(box stderr), }; - EmitterWriter { dst: dst } + EmitterWriter { dst: dst, registry: registry } } else { - EmitterWriter { dst: Raw(box stderr) } + EmitterWriter { dst: Raw(box stderr), registry: registry } } } - pub fn new(dst: Box<Writer + Send>) -> EmitterWriter { - EmitterWriter { dst: Raw(dst) } + pub fn new(dst: Box<Writer + Send>, + registry: Option<diagnostics::registry::Registry>) -> EmitterWriter { + EmitterWriter { dst: Raw(dst), registry: registry } } } @@ -324,11 +358,10 @@ impl Writer for Destination { impl Emitter for EmitterWriter { fn emit(&mut self, cmsp: Option<(&codemap::CodeMap, Span)>, - msg: &str, - lvl: Level) { + msg: &str, code: Option<&str>, lvl: Level) { let error = match cmsp { - Some((cm, sp)) => emit(self, cm, FullSpan(sp), msg, lvl, false), - None => print_diagnostic(self, "", lvl, msg), + Some((cm, sp)) => emit(self, cm, FullSpan(sp), msg, code, lvl, false), + None => print_diagnostic(self, "", lvl, msg, code), }; match error { @@ -339,7 +372,7 @@ impl Emitter for EmitterWriter { fn custom_emit(&mut self, cm: &codemap::CodeMap, sp: RenderSpan, msg: &str, lvl: Level) { - match emit(self, cm, sp, msg, lvl, true) { + match emit(self, cm, sp, msg, None, lvl, true) { Ok(()) => {} Err(e) => fail!("failed to print diagnostics: {}", e), } @@ -347,7 +380,7 @@ impl Emitter for EmitterWriter { } fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, rsp: RenderSpan, - msg: &str, lvl: Level, custom: bool) -> io::IoResult<()> { + msg: &str, code: Option<&str>, lvl: Level, custom: bool) -> io::IoResult<()> { let sp = rsp.span(); let ss = cm.span_to_string(sp); let lines = cm.span_to_lines(sp); @@ -357,12 +390,12 @@ fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, rsp: RenderSpan, // the span) let span_end = Span { lo: sp.hi, hi: sp.hi, expn_info: sp.expn_info}; let ses = cm.span_to_string(span_end); - try!(print_diagnostic(dst, ses.as_slice(), lvl, msg)); + try!(print_diagnostic(dst, ses.as_slice(), lvl, msg, code)); if rsp.is_full_span() { try!(custom_highlight_lines(dst, cm, sp, lvl, lines)); } } else { - try!(print_diagnostic(dst, ss.as_slice(), lvl, msg)); + try!(print_diagnostic(dst, ss.as_slice(), lvl, msg, code)); if rsp.is_full_span() { try!(highlight_lines(dst, cm, sp, lvl, lines)); } @@ -501,9 +534,9 @@ fn print_macro_backtrace(w: &mut EmitterWriter, try!(print_diagnostic(w, ss.as_slice(), Note, format!("in expansion of {}{}{}", pre, ei.callee.name, - post).as_slice())); + post).as_slice(), None)); let ss = cm.span_to_string(ei.call_site); - try!(print_diagnostic(w, ss.as_slice(), Note, "expansion site")); + try!(print_diagnostic(w, ss.as_slice(), Note, "expansion site", None)); try!(print_macro_backtrace(w, cm, ei.call_site)); } Ok(()) diff --git a/src/libsyntax/diagnostics/macros.rs b/src/libsyntax/diagnostics/macros.rs new file mode 100644 index 00000000000..b0260e1180f --- /dev/null +++ b/src/libsyntax/diagnostics/macros.rs @@ -0,0 +1,51 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![macro_escape] + +// NOTE: remove after next snapshot +#[cfg(stage0)] +#[macro_export] +macro_rules! __register_diagnostic( + ($code:tt, $description:tt) => (); + ($code:tt) => () +) + +#[macro_export] +macro_rules! register_diagnostic( + ($code:tt, $description:tt) => (__register_diagnostic!($code, $description)); + ($code:tt) => (__register_diagnostic!($code)) +) + +// NOTE: remove after next snapshot +#[cfg(stage0)] +#[macro_export] +macro_rules! __build_diagnostic_array( + ($name:ident) => { + pub static $name: [(&'static str, &'static str), ..0] = []; + } +) + +// NOTE: remove after next snapshot +#[cfg(stage0)] +#[macro_export] +macro_rules! __diagnostic_used( + ($code:ident) => { + () + } +) + +#[macro_export] +macro_rules! span_err( + ($session:expr, $span:expr, $code:ident, $($arg:expr),*) => ({ + __diagnostic_used!($code); + ($session).span_err_with_code($span, format!($($arg),*).as_slice(), stringify!($code)) + }) +) diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs new file mode 100644 index 00000000000..6582d2e44c8 --- /dev/null +++ b/src/libsyntax/diagnostics/plugin.rs @@ -0,0 +1,132 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::cell::RefCell; +use std::collections::HashMap; +use std::gc::Gc; +use ast; +use ast::{Ident, Name, TokenTree}; +use codemap::Span; +use ext::base::{ExtCtxt, MacExpr, MacItem, MacResult}; +use ext::build::AstBuilder; +use parse::token; + +local_data_key!(registered_diagnostics: RefCell<HashMap<Name, Option<Name>>>) +local_data_key!(used_diagnostics: RefCell<HashMap<Name, Span>>) + +fn with_registered_diagnostics<T>(f: |&mut HashMap<Name, Option<Name>>| -> T) -> T { + match registered_diagnostics.get() { + Some(cell) => f(cell.borrow_mut().deref_mut()), + None => { + let mut map = HashMap::new(); + let value = f(&mut map); + registered_diagnostics.replace(Some(RefCell::new(map))); + value + } + } +} + +fn with_used_diagnostics<T>(f: |&mut HashMap<Name, Span>| -> T) -> T { + match used_diagnostics.get() { + Some(cell) => f(cell.borrow_mut().deref_mut()), + None => { + let mut map = HashMap::new(); + let value = f(&mut map); + used_diagnostics.replace(Some(RefCell::new(map))); + value + } + } +} + +pub fn expand_diagnostic_used(ecx: &mut ExtCtxt, span: Span, + token_tree: &[TokenTree]) -> Box<MacResult> { + let code = match token_tree { + [ast::TTTok(_, token::IDENT(code, _))] => code, + _ => unreachable!() + }; + with_registered_diagnostics(|diagnostics| { + if !diagnostics.contains_key(&code.name) { + ecx.span_err(span, format!( + "unknown diagnostic code {}", token::get_ident(code).get() + ).as_slice()); + } + () + }); + with_used_diagnostics(|diagnostics| { + match diagnostics.swap(code.name, span) { + Some(previous_span) => { + ecx.span_warn(span, format!( + "diagnostic code {} already used", token::get_ident(code).get() + ).as_slice()); + ecx.span_note(previous_span, "previous invocation"); + }, + None => () + } + () + }); + MacExpr::new(quote_expr!(ecx, ())) +} + +pub fn expand_register_diagnostic(ecx: &mut ExtCtxt, span: Span, + token_tree: &[TokenTree]) -> Box<MacResult> { + let (code, description) = match token_tree { + [ast::TTTok(_, token::IDENT(ref code, _))] => { + (code, None) + }, + [ast::TTTok(_, token::IDENT(ref code, _)), + ast::TTTok(_, token::COMMA), + ast::TTTok(_, token::LIT_STR_RAW(description, _))] => { + (code, Some(description)) + } + _ => unreachable!() + }; + with_registered_diagnostics(|diagnostics| { + if !diagnostics.insert(code.name, description) { + ecx.span_err(span, format!( + "diagnostic code {} already registered", token::get_ident(*code).get() + ).as_slice()); + } + }); + let sym = Ident::new(token::gensym(( + "__register_diagnostic_".to_string() + token::get_ident(*code).get() + ).as_slice())); + MacItem::new(quote_item!(ecx, mod $sym {}).unwrap()) +} + +pub fn expand_build_diagnostic_array(ecx: &mut ExtCtxt, span: Span, + token_tree: &[TokenTree]) -> Box<MacResult> { + let name = match token_tree { + [ast::TTTok(_, token::IDENT(ref name, _))] => name, + _ => unreachable!() + }; + + let (count, expr) = with_used_diagnostics(|diagnostics_in_use| { + with_registered_diagnostics(|diagnostics| { + let descriptions: Vec<Gc<ast::Expr>> = diagnostics + .iter().filter_map(|(code, description)| { + if !diagnostics_in_use.contains_key(code) { + ecx.span_warn(span, format!( + "diagnostic code {} never used", token::get_name(*code).get() + ).as_slice()); + } + description.map(|description| { + ecx.expr_tuple(span, vec![ + ecx.expr_str(span, token::get_name(*code)), + ecx.expr_str(span, token::get_name(description)) + ]) + }) + }).collect(); + (descriptions.len(), ecx.expr_vec(span, descriptions)) + }) + }); + MacItem::new(quote_item!(ecx, + pub static $name: [(&'static str, &'static str), ..$count] = $expr; + ).unwrap()) +} diff --git a/src/libsyntax/diagnostics/registry.rs b/src/libsyntax/diagnostics/registry.rs new file mode 100644 index 00000000000..7bc191df55a --- /dev/null +++ b/src/libsyntax/diagnostics/registry.rs @@ -0,0 +1,25 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::collections::HashMap; + +pub struct Registry { + descriptions: HashMap<&'static str, &'static str> +} + +impl Registry { + pub fn new(descriptions: &[(&'static str, &'static str)]) -> Registry { + Registry { descriptions: descriptions.iter().map(|&tuple| tuple).collect() } + } + + pub fn find_description(&self, code: &str) -> Option<&'static str> { + self.descriptions.find_equiv(&code).map(|desc| *desc) + } +} diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 4d79ff3257a..4d3913da365 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -148,6 +148,8 @@ pub trait AstBuilder { fn expr_some(&self, sp: Span, expr: Gc<ast::Expr>) -> Gc<ast::Expr>; fn expr_none(&self, sp: Span) -> Gc<ast::Expr>; + fn expr_tuple(&self, sp: Span, exprs: Vec<Gc<ast::Expr>>) -> Gc<ast::Expr>; + fn expr_fail(&self, span: Span, msg: InternedString) -> Gc<ast::Expr>; fn expr_unreachable(&self, span: Span) -> Gc<ast::Expr>; @@ -674,6 +676,10 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.expr_path(none) } + fn expr_tuple(&self, sp: Span, exprs: Vec<Gc<ast::Expr>>) -> Gc<ast::Expr> { + self.expr(sp, ast::ExprTup(exprs)) + } + fn expr_fail(&self, span: Span, msg: InternedString) -> Gc<ast::Expr> { let loc = self.codemap().lookup_char_pos(span.lo); self.expr_call_global( diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index b7d72ae4deb..b5f7005c2a3 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -58,7 +58,7 @@ pub fn expand_expr(e: Gc<ast::Expr>, fld: &mut MacroExpander) -> Gc<ast::Expr> { None => { fld.cx.span_err( pth.span, - format!("macro undefined: '{}'", + format!("macro undefined: '{}!'", extnamestr.get()).as_slice()); // let compilation continue @@ -567,7 +567,7 @@ fn expand_stmt(s: &Stmt, fld: &mut MacroExpander) -> SmallVector<Gc<Stmt>> { let marked_after = match fld.extsbox.find(&extname.name) { None => { fld.cx.span_err(pth.span, - format!("macro undefined: '{}'", + format!("macro undefined: '{}!'", extnamestr).as_slice()); return SmallVector::zero(); } diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 1ef376c6615..184ce39aaf2 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -27,12 +27,11 @@ #![feature(quote, unsafe_destructor)] #![allow(deprecated)] -extern crate serialize; -extern crate term; -#[phase(plugin, link)] extern crate log; - extern crate fmt_macros; extern crate debug; +#[phase(plugin, link)] extern crate log; +extern crate serialize; +extern crate term; pub mod util { pub mod interner; @@ -41,26 +40,30 @@ pub mod util { pub mod small_vector; } +pub mod diagnostics { + pub mod macros; + pub mod plugin; + pub mod registry; +} + pub mod syntax { pub use ext; pub use parse; pub use ast; } -pub mod owned_slice; -pub mod attr; -pub mod diagnostic; -pub mod codemap; pub mod abi; pub mod ast; -pub mod ast_util; pub mod ast_map; -pub mod visit; +pub mod ast_util; +pub mod attr; +pub mod codemap; +pub mod crateid; +pub mod diagnostic; pub mod fold; - - +pub mod owned_slice; pub mod parse; -pub mod crateid; +pub mod visit; pub mod print { pub mod pp; @@ -70,31 +73,25 @@ pub mod print { pub mod ext { pub mod asm; pub mod base; + pub mod build; + pub mod bytes; + pub mod cfg; + pub mod concat; + pub mod concat_idents; + pub mod deriving; + pub mod env; pub mod expand; - + pub mod fmt; + pub mod format; + pub mod log_syntax; + pub mod mtwt; pub mod quote; - - pub mod deriving; - - pub mod build; + pub mod source_util; + pub mod trace_macros; pub mod tt { pub mod transcribe; pub mod macro_parser; pub mod macro_rules; } - - pub mod mtwt; - - pub mod cfg; - pub mod fmt; - pub mod format; - pub mod env; - pub mod bytes; - pub mod concat; - pub mod concat_idents; - pub mod log_syntax; - pub mod source_util; - - pub mod trace_macros; } diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 0aaddacfab6..5c5943f0cd4 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1308,7 +1308,7 @@ mod test { use std::io::util; fn mk_sh() -> diagnostic::SpanHandler { - let emitter = diagnostic::EmitterWriter::new(box util::NullWriter); + let emitter = diagnostic::EmitterWriter::new(box util::NullWriter, None); let handler = diagnostic::mk_handler(box emitter); diagnostic::mk_span_handler(handler, CodeMap::new()) } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 37c84c95af6..a3e169cd511 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -40,7 +40,7 @@ pub struct ParseSess { pub fn new_parse_sess() -> ParseSess { ParseSess { - span_diagnostic: mk_span_handler(default_handler(Auto), CodeMap::new()), + span_diagnostic: mk_span_handler(default_handler(Auto, None), CodeMap::new()), included_mod_stack: RefCell::new(Vec::new()), } } |
